Faisal
Faisal

Reputation: 18978

has_many association .build is not saving object in DB for Rails 6.1

I'm upgrading to Rails 6.1, and have the following associations in my model

class Product < ApplicationRecord
  has_many :classifications, dependent: :destroy
  has_many :order_lines, dependent: :destroy
end

For this following snippet:

p = Product.new
p.classifications.build name: 'my name'
p.order_lines.build line_number: '123'
p.save

If I run it in my existing code env (Rails 6.0, Ruby 2.7.7), it works as expected. However, if I run it against Rails 6.1, the classifications object is stored in the DB, whereas the order_line is dropped. There is no SQL statement that attempts to write it to the DB, and checking p.order_lines.inspect after the save, returns an empty CollectionProxy. Changing the order of how we build the objects had no impact. Changing the order of how the association is defined in the model DID change the behaviour (order_line was persisted and classifications wasn't)

Interestingly enough, if I switch to

p = Product.create # instead of .new
# rest of snippet

It works as expected against Rails 6.1, and both order_line and classification were stored. This is very confusing behaviour, and I have no idea what is introducing it. Any thoughts?

EDIT: the behaviour is consistent with any two has_many associations I define on any model. The association defined first in the model gets saved, while the other one gets dropped. I tried swapping them around and reloading my console, and the one that gets saved vs dropped was swapped.

Upvotes: 4

Views: 197

Answers (1)

Bryan Giovanny
Bryan Giovanny

Reputation: 424

I am the author former co-worker that inherited this issue to solve and I am giving an update to this problem.

So what I found out after more investigation is that, the problem comes from the fact that one of the has many relationship doesn't have an inverse relationship to the parent.

From the sample above, classifications has an inverse relationship to Product

belongs_to :product, inverse_of: :classifications

while OrderLine doesn't define this inverse relationship.

What breaks it is that rails 6.1 introduces below config as default.

config.active_record.has_many_inversing = true

Due to this being a legacy application with a lot of moving parts, the solution for us is to set this config back to false.

Upvotes: 0

Related Questions