Объединение пользовательских соединений с обычными соединениями рельсов

У меня есть модели foo, bar и baz вот так

# has a field join_condition_string
class Foo < AR::Base
    :has_many :bar
end

# Has a field exclusion_critera
class Bar < AR::Base
    :belongs_to foo
end

# has a fields condition_string, exclusion_criteria
class Baz < AR::Base
end

Я хочу иметь возможность извлекать Foo на основе критериев как из Bar, так и из Baz. Таким образом, мне нужно присоединиться к обеим моделям. Я хочу присоединиться к Бару, используя магию рельсов,

Foo.find(:all, :joins => :bar)

И я хочу присоединиться к Baz, используя пользовательское соединение.

Foo.find(:all, :joins=>"left join baz on baz.condition_string = foo.join_condition_string")

Независимо друг от друга они отлично работают, но я не могу найти способ элегантно их объединить.

Я пытался сделать наивную вещь и объединить два условия в массив, но безрезультатно.

Foo.find(:all, :joins=>["left join baz ...", :bar])

документы утверждают, что я могу сделать Foo.find(:all, :joins => :bar, :joins => "left join baz ..."), но это не похоже как будто это должно работать (и не работает в rails 2.3.8), потому что аргументы, которые нужно найти, завернуты в хеш, а первый :joins потерян.

Конечно, я всегда мог объединить их в одну строку :joins. Однако как эти два вызова можно совместить с минимальным количеством необработанного sql? Любые идеи?

РЕДАКТИРОВАТЬ: Принятый ответ действительно отвечает на мой вопрос, но я все еще думаю, что может быть лучший способ.

РЕДАКТИРОВАТЬ 2: Как уже упоминалось, rubyprince, это было решено в rails >= 3.0.0


person diedthreetimes    schedule 07.04.2011    source источник
comment
Вы пробовали это Foo.find(:all, :joins=>[:bar, "left join baz ..."])? Я имею в виду массив в обратном порядке...   -  person rubyprince    schedule 07.04.2011


Ответы (1)


Вероятно, это решение вашей проблемы. Вы можете хранить эти объединения отдельно как две именованные области в модели и называть их так.

class Foo < AR::Base
  has_many :bars
  named_scope :joined_bars, :joins => :bars
  named_scope :joined_baz, :joins => "LEFT JOIN baz on ..."
end

Затем вы можете вызвать его в контроллере следующим образом

Foo.joined_bars.joined_baz

Вы можете добавить любые условия или другие параметры к выбранному, как это

Foo.joined_bars.joined_baz.all(:conditions => ..,
                               :limit => ..)

Это создаст один SQL-запрос со всеми соединениями, где, лимитом и т. д.

person rubyprince    schedule 07.04.2011
comment
Это определенно сработает, но было бы круто, если бы существовало лучшее решение. На самом деле join_bars представляет собой довольно сложный хэш соединений {:model=›{:nother_model=›:etc}, и добавление области действия внесет ненужный беспорядок в и без того большую модель. - person diedthreetimes; 07.04.2011
comment
то, как вы написали, должно было сработать, но я думаю, что это ошибка в Rails. - person rubyprince; 08.04.2011
comment
@Карлитос Моралес. Если ваш Rails ›=3, вам не нужно делать все это. Он имеет Foo.joins(:bar).joins("LEFT JOIN baz on ...") - person rubyprince; 12.02.2014
comment
Неважно, я нашел синтаксис, который хотел =) - person Carlos Morales; 12.02.2014