Arel, Joins и Rails Queries - PullRequest
       18

Arel, Joins и Rails Queries

15 голосов
/ 22 февраля 2011

Я недавно застрял на проблеме и нашел свой путь к Арелу, который, похоже, должен позволять мне делать ИЛИ в моих запросах.

В качестве отправной точки мне нужно было преобразовать существующий запрос Rails 3 в Arel, и здесь я столкнулся с проблемами.

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

#in the Request class
scope :responder, lambda { |user| joins(:ad).where(:ads => { :user_id => user }) }

Request.responder(303).to_sql

=> "SELECT \"requests\".* FROM \"requests\" INNER JOIN \"ads\" ON \"ads\".\"id\" = \"requests\".\"ad_id\" WHERE (\"ads\".\"user_id\" = 303)"

В соответствии с doco на странице Arel github и Railscast 215 я мог бы сделать что-то вроде следующего, чтобы повторить запрос с Arel

  requests = Request.arel_table
  ads = Ad.arel_table
  where(requests.join(ads).on(ads[:id].eq(requests[:ad_id])))

Это приводит к ошибке

TypeError: Cannot visit Arel::SelectManager

Я могу сделать следующее в консоли, хотя

r = Request.arel_table
a = Ad.arel_table

r.join(a).to_sql
 => "SELECT  FROM \"requests\" INNER JOIN \"ads\" "

Похоже, он формирует запрос SQL, однако, когда вы помещаете его в где

Request.where(r.join(a)).to_sql

Я получаю следующее

TypeError: Cannot visit Arel::SelectManager....

Я пытался делать другие действия с Arel в пределах где и это работает (например,)

Request.where(r[:status].eq(nil)).to_sql
 => "SELECT \"requests\".* FROM \"requests\" WHERE (\"requests\".\"status\" IS NULL)"

Это немного за пределами моих знаний о рельсах и рубинах. Есть идеи?

Заранее спасибо.

Ответы [ 5 ]

9 голосов
/ 01 июня 2012

Вы можете использовать join_sources.first на Arel::SelectManager и передать это для объединения

requests = Request.arel_table
ads = Ad.arel_table
Request.joins(requests.join(ads).on(ads[:id].eq(requests[:ad_id])).join_sources.first)
8 голосов
/ 18 марта 2011

Более широкий ответ здесь заключается в том, что, несмотря на причудливый, вдохновляющий пример здесь: http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/

... Active Record на самом деле не поддерживает полную функциональность Arel.По крайней мере, не через отношения или границы.Вы можете создавать любые (большинство) запросов в Arel, но в итоге вы будете использовать:

sql = User.arel_table.(something awesome in Arel).to_sql
users = User.find_by_sql(sql)

Технически, все еще есть метод ".to_a", но он не возвращает ActiveRecordэкземпляры модели, и устарели.

{ОБНОВЛЕНИЕ}

http://erniemiller.org/projects/squeel/ - это лучшее, что может случиться с ActiveRecord, когда-либо.Все эти арельские вещи, поняли.

3 голосов
/ 22 февраля 2011

Я не эксперт по арелам, но я думаю, что вы хотите объединить объединение и области видимости вместо того, чтобы включать одно в другое.Поэтому вместо

where(requests.join(ads).on(ads[:id].eq(requests[:ad_id])))

попробуйте (например):

requests.join(ads).on(ads[:id].eq(requests[:ad_id])).where(requests[:status].eq(nil))
1 голос
/ 22 февраля 2011

Чтобы сделать ИЛИ в рельсах 3, проверьте MetaWhere. На ней есть хороший Railscast: http://railscasts.com/episodes/251-metawhere-metasearch

0 голосов
/ 18 июля 2011

Самое гибкое решение, которое я нашел до сих пор, это что-то вроде следующего:

class Request
  class << self
    def your_join_scope
      joins('INNER JOIN "ads" ON "ads"."id" = "requests"."ad_id"')
    end
  end
end

Сила этого в том, что вы можете смешивать и сопоставлять его с другими областями

...