简体   繁体   中英

ActiveRecord not setting foreign key on has_many association using .build

I have a Rails app with the following (simplified) models:

# member.rb
class Member < ActiveRecord::Base
  has_many :member_roles, :dependent => :destroy, 
           :autosave => true, :inverse_of => :member
end

...

# member_role.rb
class MemberRole < ActiveRecord::Base
  belongs_to :member, :inverse_of => :member_roles
  validates_presence_of :member_id
end

If I try to use the .build method on the association, the created object doesn't have the foreign key set. This causes it to fail validation, or without the validation become not be associated with the Member .

# Rails console
> m = Member.find(280)
> mr = m.member_roles.build(:role_id => Role.find_by_name("Crew Chief").id)
=> #<MemberRole id: nil, member_id: nil, role_id: 6697350, start_date: nil, \
   end_date: nil, memo: nil, created_at: nil, updated_at: nil>
> mr.save!
ActiveRecord::RecordInvalid: Validation failed: Member can't be blank
> mr.save(:validate => false)
> mr
=> #<MemberRole id: 1834, member_id: nil, role_id: 6697350, start_date: nil, \
   end_date: nil, memo: nil, created_at: "2012-04-11 06:37:00", \
   updated_at: "2012-04-11 06:37:00">

Which conflicts with the Rails Guide :

The collection.build method returns one or more new objects of the associated type. These objects will be instantiated from the passed attributes, and the link through their foreign key will be created, but the associated objects will not yet be saved.

Obviously, manually setting the member_id is a easy work around. But I'd like to avoid that. I believe this code worked correctly in previous versions of rails;the above is the behavior of Rails 3.2.3.

I had as an initializer the code in grosser's answer at: Can nested attributes be used in combination with inheritance?

Changing that to:

class ActiveRecord::Reflection::AssociationReflection
  def build_association(*options, &block)
    if options.first.is_a?(Hash) and options.first[:type].presence
      options.first[:type].to_s.constantize.new(*options, &block)
    else
      klass.new(*options, &block)
    end
  end
end

solved the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM