Question

In my Rails 4 app, I have the following models:

class Person < ActiveRecord::Base
    has_many :addresses
  end

class Address < ActiveRecord::Base
  belongs_to :person
  belongs_to :city
end

class City < ActiveRecord::Base
  has_many :addresses
end

I'm using the :includes function to return query result into one variable:

Address.includes(:person, :city).where("person_id = 1")

It works as expected, except that I do not want the query to return every single column.

Here's what I've tried:

  • use select and specify table name and column names explicitly, e.g. "city.name", but Rails generates a big query with outer joins, that can be very costly, especially when there are lots of concurrent requests, so prefer a better solution.
  • don't want to hard code complete and raw SQL statements, because of maintenance issue later on
  • create a new "dummy" belongs_to relationship like in Address: belongs_to :city_select_columns, -> { select('name') }, :class => 'City', but that doesn't work (actually I'm not sure if that select is even supported, only came across documentation about where so far).
  • maybe define scope in City and Person? but I'm not sure how it should be defined or if it'd make sense to do it this way

Suggestions? Thanks

Était-ce utile?

La solution

Have you tried this?

class Person < ActiveRecord::Base
    has_many :addresses
    has_many :cities, :through => :addresses
end

class Address < ActiveRecord::Base
  belongs_to :person
  belongs_to :city
end

class City < ActiveRecord::Base
  has_many :addresses
end

Then:

Person.find(1).cities.pluck(:name)

Looks like this generates an INNER JOIN but with indexes it shouldn't be too costly?

Autres conseils

Did you try select?

Address.select(<output_columns>).includes(:person, :city).where("person_id = 1")

Could not find a good query method using Rails' API, I ended up writing a raw inner join SQL, then call ActiveRecord::Base.connection.execute to run it.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top