Ruby on Rails .create Rollback Mystery
Published: 2020-04-10 18:41:35

I interrupt your regularly scheduled Binary Tree blogs to bring you a frustration I ran into, and then the fix. 

In my pet project, [The World Builder's Tome](https://wbtome.herokuapp.com/), which started as my final project at Flatiron, I have quite a few interconnected models in my Ruby backend. There are worlds and stories and characters and notes and more, and each of these models "has many" images. The way I have handled this is to have only one Images model, with foreign keys for all these different categories. 

Initially, the image.rb file in models looked like this:

```
class Image < ApplicationRecord
    belongs_to :world_note
    belongs_to :story_note
    belongs_to :world
    belongs_to :story
    belongs_to :character
    belongs_to :location 
end
```

In the midst of solving some minor bug (I honestly can't remember what it was now), I added a reference to the foreign keys, which is more syntactically correct. This looked like this: 

```
class Image < ApplicationRecord
    belongs_to :world_note, :foreign_key => "world_note_id"
    belongs_to :story_note, :foreign_key => "story_note_id"
    belongs_to :world, :foreign_key => "world_id"
    belongs_to :story, :foreign_key => "story_id"
    belongs_to :character, :foreign_key => "character_id"
    belongs_to :location, :foreign_key => "location_id"

end
```

Little did I know, however, that this would cause me another issue somewhere else. 

When I next came back to the program, I discovered that I could no longer successfully create images. Narrowing things down, I confirmed it wasn't an issue with Heroku, my hosting site, since it also wasn't working on my localhost. I even tried directly running Image.create() in the Rails Console, which confirmed that it wasn't an issue with a fetch somewhere that was creating the problem.

Looking at the output in Rails, I saw that the .create would begin, and then immediately rollback with no explanation. Here's that code, for those curious:

```
2.6.1 :003 > Image.create(url: "thisisaurl")
   (0.4ms)  BEGIN
   (0.4ms)  ROLLBACK
 => #<Image id: nil, url: "thisisaurl", world_id: nil, story_id: nil, 
character_id: nil, location_id: nil, story_note_id: nil, created_at: nil, 
updated_at: nil, world_note_id: nil>
```

Frustratingly, this proved to be a difficult problem to google. I couldn't quite get the wording right to get at the issue I was having. Eventually, however, I managed to find [this question](https://teamtreehouse.com/community/database-gives-rollback-transaction-on-rails-console-create-method-on-rails-5) another programmer had. 

They seemed to be having just the issue I was! Huzzah! Here's a key line from the winning response: "Rails, in 5.0, requires validation on belongs_to. There are two ways to fix it, adding optional: true or required: false."

There's a spot for each of these different connections on each image instance, but any given image will only have the one connection. Given that, the foreign-key for all other connections on that instance would be nil. Turns out, you need to specify whether or not those foreign-keys are required, or Rails (5.0) will default them to required and reject any new object instance that doesn't have them!

I gave that a try, altering my code to look like so: 

```
class Image < ApplicationRecord
    belongs_to :world_note, :foreign_key => "world_note_id", optional: true
    belongs_to :story_note, :foreign_key => "story_note_id", optional: true 
    belongs_to :world, :foreign_key => "world_id", optional: true 
    belongs_to :story, :foreign_key => "story_id", optional: true 
    belongs_to :character, :foreign_key => "character_id", optional: true 
    belongs_to :location, :foreign_key => "location_id", optional: true 

end
```

Lo and behold, that solved it!! Who knew this was a thing? I sure didn't. Do now, though! Learn a little something new every day. (The commenter also recommended reading [this blog post](https://blog.bigbinary.com/2016/02/15/rails-5-makes-belong-to-association-required-by-default.html) describing the change.

Hopefully this will help someone with my same issue discover the problem a little faster!