В моем приложении Rails 4 у ​​меня есть следующие модели:

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

Я использую функцию :includes, чтобы вернуть результат запроса в одну переменную:

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

Он работает должным образом, за исключением того, что я не хочу, чтобы запрос возвращал каждый столбец.

Вот что я пробовал:

  • используйте select и явно укажите имя таблицы и имена столбцов, например "city.name", но Rails генерирует большой запрос с внешними соединениями, что может быть очень дорогостоящим, особенно при большом количестве параллельных запросов, поэтому предпочтите лучшее решение.
  • не хотят жестко кодировать полные и необработанные операторы SQL из-за проблем с обслуживанием позже
  • создать новую "фиктивную" связь belongs_to, как в Address: belongs_to :city_select_columns, -> { select('name') }, :class => 'City', но это не работает (на самом деле я не уверен, поддерживается ли это select, только наткнулся на документацию о where пока).
  • может быть, определить scope в Городе и Человеке? но я не уверен, как это должно быть определено, и есть ли смысл сделать это таким образом

Предложения? благодаря

1
jiax 30 Апр 2014 в 10:55

3 ответа

Лучший ответ

Вы пробовали это?

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

Затем:

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

Похоже, это генерирует INNER JOIN, но с индексами это не должно быть слишком дорого?

3
msanteler 30 Апр 2014 в 15:10

Вы пробовали select?

Address.select(<output_columns>).includes(:person, :city).where("person_id = 1")
1
Lenin Raj Rajasekaran 30 Апр 2014 в 06:59

Не удалось найти хороший метод запроса с использованием Rails API, я закончил тем, что написал необработанный SQL-запрос внутреннего соединения, а затем вызвал ActiveRecord::Base.connection.execute для его запуска.

0
jiax 1 Май 2014 в 06:02