4

I’m using Rails 4.2.3 I have a model with two relations to the same type of object,

class MyObject < ActiveRecord::Base
  belongs_to :user
  has_many :my_object_times
…
  has_one :my_object_time, foreign_key: :linked_my_object_time_id

The column name in my database for the "has_one" is "linked_my_object_time_id." What I can’t figure out is how to write the model for the linked object. I know I need to put two “belongs_to” clauses, but I can’t figure out how to write the second one. So far I have

class MyObjectTime < ActiveRecord::Base
  belongs_to :my_object

When I go to save my object …

    my_object.linked_my_object_time = my_object_time
    my_object.save

I get the error “NoMethodError (undefined method `linked_my_object_time=' for #”

Dave
  • 15,639
  • 133
  • 442
  • 830

2 Answers2

3

Rails magically infers the foreign key of an association and its model name based on the association name. If the foreign key or model name differs from the association name, you must explicitly tell rails which class name and foreign key to use. Doing this will allow you to write your model with two relations.

It should look something like this:

class MyObject < ActiveRecord::Base
  belongs_to :user
  has_many :my_object_times
  has_one :linked_my_object_time, class_name: 'MyObjectTime'

What happened here? I changed the name of the has_one association because it needs to be differentiated in name from the has_many relationship that rails will infer. There is no name clash in this file, but if you used has_many :my_object_times and has_one :my_object_time, you wouldn't be able to differentiate between the associations (ie. belongs_to :my_object) in the MyObjectTime model. Because I changed the association name, rails cannot infer the model name anymore so I specify it. But because rails generally adds _id to the association name, it should be able to infer the foreign key column of linked_my_object_time_id from the association name.

What about the MyObjectTime model?

class MyObjectTime < ActiveRecord::Base
  belongs_to :my_object
  belongs_to :whatever_you_want_to_call_it, class_name: 'MyObject', foreign_key: 'linked_my_object_time_id'

The first belongs_to is the reverse association for has_many: my_object_times and rails will look for the my_object_id column in the MyObjectTime table as expected. The second belongs_to has to have a different association name to be able to differentiate between the associations, and since the association name changed, I have to include the class name and the foreign_key since it cannot be inferred from the association name.

I got all of my information from here.

(EDIT: Fixed syntax in association)

hypern
  • 887
  • 4
  • 16
  • The "linked_my_object_time" is a foreign key from "MyObject" to "MyObjectTime". In as far as that's true, shouldn't the "has_one :linked_my_object_Time" be a belongs_to? – Dave Jun 23 '16 at 16:21
  • The belongs_to association is always for the model of the table that holds the foreign key. If in your specification you want MyObject to **have** MyObjectTime then the foreign key would be in MyObjectTime table and the belongs_to association would be in MyObjectTime model. If you want MyObjectTime to **have** a MyObject then you would use has_one association in MyObjectTime and a belongs_to in MyObject. The foreign key would be in MyObject table. – hypern Jun 23 '16 at 16:30
  • 2
    give this guy his bounty :) – jaydel Jun 23 '16 at 20:54
0

When creating associations you can also create it like this

rails generate model MyObject => parent

rails g model MyObjectTime my_object:references => child

and in my_object.rb

class MyObject < ActiveRecord::Base
  has_one :my_object_time
end

then you can reference my_object from my_object_times like this

my_object_time.my_object

Saad
  • 1,856
  • 1
  • 22
  • 28
  • Right but what about when MyObject has two relations, "has_one" and "has_many", what does the model look like for "MyObjectTime"? If you could include taht code in your question, taht woudl solve my problem. – Dave Jun 18 '16 at 17:16