views:

20

answers:

2

I have some geography related classed defined as follows:

class Location < ActiveRecord::Base
end

class State < Location
  has_many :geographies
  has_many :cities
  has_many :counties
end

class County < Location
  belongs_to :state
  has_many :geographies
  has_many :cities, :through => :geographies, :uniq => true
end    

class City < Location
  belongs_to :state
  has_many :geographies
  has_many :counties, :through => :geographies, :uniq => true
end

class Geography < ActiveRecord::Base
  belongs_to :state
  belongs_to :city
  belongs_to :county
end

The following console output demonstrates the problem that I'm having.

>> County.first.cities.loaded?
=> false
>> County.first.state.loaded?
=> true

Looking in the logs I see that when I call state.loaded? it runs a SQL statement to load the state, i.e., the state was not loaded until I "touched" it. However, when I call cities.loaded? no SQL is executed and false is returned. This behavior seems inconsistent to me. I searched around a bit on the interwebs and couldn't find anything regarding this so I'm guessing it's my mistake, though, I don't see how.

Any help is much appreciated.

Thanks in advance.

+1  A: 

I think it comes down to the type of relationship being used and the interaction with lazy loading.

When you call County.first.state, Rails will load the state object that belongs to the County - there is only one, and therefore a call to .state is actually a call to a 'concrete' object in the database that can be loaded.

However, when you call County.first.cities, you are actually calling the relationship collection that belongs to the county object. As you don't actually call on a specific object or set of conditions, Rails is smart enough not to load the collection.

If you said something like:

County.first.cities.all
County.first.cities.each
County.first.cities.first

Rails would then kick-off the SQL statement and load the data.

Toby Hede
Right, is there a way to know if a belongs_to association has been loaded into memory or not seeing that the loaded? method will always return true? It seems that the method loaded? is useless for belongs_to associations.
Jason
A: 

I found that you can use the Object method instance_variable_get to check to see if a belongs_to association is loaded without triggering the association to be loaded during your check. So...

>> c = County.first
=> #<County id: 1, ...>
>> c.instance_variable_get("@state")
=> nil
>> c.state
=> #<State id: 1, ...>
>> c.instance_variable_get("@state")
=> #<State id: 1, ...>
>> c = County.first(:include => :state)
=> #<County id: 1, ...>
>> c.instance_variable_get("@state")
=> #<State id: 1, ...>
Jason