Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails ActiveRecord builds wrong foreign key if there are two belongs_to relationships to same model

Using Rails 3.2.3, I have User and Message models. Each message is owned by a user, and each message has an optional from_user field that also takes a user.id.

app/models/user.rb

class User < ActiveRecord::Base
  has_many :messages, :foreign_key => "owner_id",     :inverse_of => :owner
  has_many :messages, :foreign_key => "from_user_id", :inverse_of => :from_user
end

app/models/message.rb

class Message < ActiveRecord::Base
  belongs_to :owner, :class_name => "User", :inverse_of => :messages
  validates  :owner, :presence => true   # Every message must have an owner_id

  belongs_to :from_user, :class_name => "User", :inverse_of => :messages
end

The problem I'm seeing is with the .build method. The main reason to use .build is to instantiate a (possibly protected) foreign key, right? (See the Rails Guide on Active Record associations: "the link through their foreign key will be created.") However when I run

@message = @user.messages.build(<accessible attributes>)

I find that it is filling in the optional from_user and not the mandatory owner.

Is there some way to control which foreign key .build fills in? Or do I need to just use .new and assign all foreign keys manually?

@message = Message.new(<accessible attributes>)
@message.owner = @user
@message.from_user = @another_user
like image 433
Mark Berry Avatar asked May 29 '12 19:05

Mark Berry


Video Answer


1 Answers

ActiveRecord doesnt like that you have 2 associations with the same name. You're going to have to change the association names. This means that you will also have to supply the class_name attibute. Maybe something like:

has_many :owner_messages, :class_name => 'Message', :foreign_key => "owner_id",     :inverse_of => :owner
has_many :user_messages, :class_name => 'Message', :foreign_key => "from_user_id", :inverse_of => :from_user
like image 149
Cody Caughlan Avatar answered Sep 28 '22 08:09

Cody Caughlan