ActiveRecord назвал область действия на двух отношениях к одной модели
Я использую полиморфную ассоциацию двух разных моделей с моделью тегирования. Отлично, легко. Но одна из этих двух моделей также принадлежит другой модели.
class Facility < ActiveRecord::Base
has_many :units
has_many :taggings, :as => :taggable
has_many :tags, :through => :taggings
end
class Unit < ActiveRecord::Base
belongs_to :facility
has_many :taggings, :as => :taggable
has_many :tags, :through => :taggings
end
class Tagging < ActiveRecord::Base
belongs_to :taggable, :polymorphic => true
belongs_to :tag
end
class Tag < ActiveRecord::Base
has_many :taggings
end
Я пытаюсь написать область действия для извлечения всех единиц для определенного тега, включая те единицы, которые принадлежат объекту с этим тегом. Это не работает:
named_scope :by_tag_id, lambda {|tag_id|
{
:select => "DISTINCT units.*",
:joins => [:taggings, {:facility => :taggings}],
:conditions => ["taggings.tag_id = ? OR taggings_facilities.tag_id = ?",
tag_id.to_i, tag_id.to_i]
}}
Для этого named_scope я получаю только те единицы, которые имеют тег.
Какие-нибудь мысли? Я что-то упускаю здесь очевидное?
Обновить
Я, к сожалению, на Rails 2.3.x, Ruby 1.8.7.
Я пытаюсь прямо сейчас некоторые методы с более явно написанными объединениями.
Обновление 2
Я не смог ответить на свой вопрос, потому что у меня нет репутации. К сожалению. Я должен действительно внести больше...
Ну, я думаю, мне просто нужно было еще немного подтолкнуть. Вот что у меня работает:
named_scope :by_tag_id, lambda {|tag_id|
{
:select => "DISTINCT units.*",
:joins => [
"INNER JOIN facilities as bti_facilities ON units.facility_id = bti_facilities.id",
"LEFT JOIN taggings AS bti_facilities_taggings
ON bti_facilities_taggings.taggable_id = bti_facilities.id AND bti_facilities_taggings.taggable_type = 'Facility'",
"LEFT JOIN taggings AS bti_units_taggings ON bti_units_taggings.taggable_id = units.id AND bti_units_taggings.taggable_type = 'Unit'",
],
:conditions => ["bti_units_taggings.tag_id = ? OR bti_facilities_taggings.tag_id = ?", tag_id.to_i, tag_id.to_i]
}
}
Я использую некоторые намеренно скрытые псевдонимы таблиц, чтобы попытаться избежать столкновения с другими именованными областями. (У меня не было псевдонимов для запуска средств, и я столкнулся с ошибкой SQL в запросе, пытаясь соединиться с другой областью действия, ссылающейся на таблицу возможностей.)
Если у кого-то есть лучший ответ или какой-либо отзыв о моем методе, я бы хотел услышать его.
2 ответа
Я вижу, что вы уже ответили на ваш вопрос, но если бы вы использовали :include =>
вместо :join =>
в исходном запросе это сгенерирует LEFT OUTER JOIN
, Тем не менее, вам может не потребоваться загружать ассоциацию, а только запрашивать ее, поэтому ваш пробег может отличаться.
Интересно, вы могли бы написать что-то вроде этого?
named_scope :by_tag_id, lambda {|tag_id|
{
:select => "DISTINCT units.*",
:include => [:tags, {:facility => :taggings}],
:conditions => { :tags => { :tag_id => tag_id } }
}
}