Reputation: 7066
I'm having a very irritating issue with a self-referential belongs_to
association in Rails 3:
class Locale < ActiveRecord::Base
belongs_to :parent_locale, :class_name => 'Locale', :foreign_key => 'parent_locale_id'
end
In console:
locale = Locale.find(2)
locale.parent_locale = Locale.find(3)
locale.save
#----> Association is saved correctly!
locale.parent_locale_id
=> 3
locale.parent_locale
#----> Association is returned correctly!
# Now let's retrieve the record again, and see if it still works...
locale = Locale.find(2)
locale.parent_locale_id
=> 3
locale.parent_locale
=> nil
What on earth could be the issue here? Any suggestions?
Edit: This does not work either:
belongs_to :parent_locale, :class_name => 'Locale', :foreign_key => 'parent_locale_id', :inverse_of => :child_locales
has_many :child_locales, :class_name => 'Locale', :foreign_key => 'parent_locale_id', :inverse_of => :parent_locale
Edit: I enabled SQL query logging in the console and noticed what happens when I try to retrieve the parent_locale
:
locale.parent_locale
Phrase Load (0.4ms) SELECT `phrases`.* FROM `phrases` WHERE `phrases`.`key` = 'parent_locale_id' LIMIT 1
=> nil
Whoa, what is this? It turns out that Locale
has the following method:
def [](key)
if phrase = Phrase.find_by_key(key)
t = self.translations.find_by_phrase_id(phrase.id)
t.text if t
end
end
Still, how do I make sure this method is not triggered, but the association instead? Frankly, I don't even know why this method is called, as I'm not treating the locale as an array anywhere. Also, there are other associations on this class that do work.
Upvotes: 1
Views: 742
Reputation: 7066
I solved the problem. The culprit was that the []
method was overwritten in the model, and Rails seems to use it to access the model's foreign key column.
I had to change this..
def [](key)
if phrase = Phrase.find_by_key(key)
t = self.translations.find_by_phrase_id(phrase.id)
t.text if t
end
end
to this:
def [](key)
if phrase = Phrase.find_by_key(key)
t = self.translations.find_by_phrase_id(phrase.id)
t.text if t
else
super(key)
end
end
Sorry, you guys could not have guessed this of course.
Upvotes: 1
Reputation: 11921
The problem is that the second find may be hitting ActiveRecord's cache, which is retrieving the "unedited", cached record, instead of retrieving the updated one from the database.
Also, your association is missing the other end, whether it be has_many
or has_one
, which is probably preventing the record from being retrieved when referencing parent_locale
Edit The two ends of the relation should not use the same foreign key, belongs_to
should not use foreign_key
Upvotes: 0
Reputation: 8954
belongs_to :parent_locale, :class_name => 'Locale', :foreign_key => 'parent_locale_id'
has_many :child_locales, :class_name => 'Locale', :foreign_key => 'parent_locale_id'
Upvotes: 1