Reputation: 12003
My models:
metro_station.rb
class MetroStation < ActiveRecord::Base
belongs_to :metro_line
has_one :city, through: :metro_line, autosave: false
end
metro_line.rb`
class MetroLine < ActiveRecord::Base
belongs_to :city
has_many :metro_stations
end
city.rb
class City < ActiveRecord::Base
has_many :metro_lines
end
When I run:
MetroStation.where(city: City.first)
I get
PG::UndefinedColumn: ERROR: column metro_stations.city_id does not exist
: SELECT "metro_stations".* FROM "metro_stations" WHERE "metro_stations"."city_id" = 1
(pry) output error: #<ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column metro_stations.city_id does not exist
LINE 1: ...CT "metro_stations".* FROM "metro_stations" WHERE "metro_sta...
While this query works:
MetroStation.joins(:metro_line).where(metro_lines: {city_id: 1})
Upvotes: 1
Views: 3166
Reputation: 1665
To find out why your first approach doesn't work type in
MetroStation.where(city: City.first).to_sql
You should see something like
... WHERE metro_stations.city_id = 1
forming part of the query. The MetroStation model simply doesn't have the city_id attribute, as a result your first approach forms an invalid SQL statement.
The join works since it is filtering on the MetroLine table which has the relationship to the City model in form of the city_id field.
Nothing wrong with your models it is just the way Rails generates the SQL statements which in the world of SQL makes sense.
A has_many relationship on City to MetroStation through MetroLine delivers the desired results for your question (which metro stations are in a city).
class City < ActiveRecord::Base
has_many :metro_lines
has_many :metro_stations, through: :metro_lines
end
class MetroLine < ActiveRecord::Base
belongs_to :city
has_many :metro_stations
end
class MetroStation < ActiveRecord::Base
belongs_to :metro_line
has_one :city, through: :metro_line
end
# Return all metro stations for a city
# * assuming City has name 'name' field
london_stations = City.find_by_name('London').metro_stations
Hope this helps!
Upvotes: 2
Reputation: 52356
City should also:
has_many :metro_stations, :through => :metro_lines
And then you write:
City.first.metro_stations
Upvotes: 1