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 } }
  }
}
Другие вопросы по тегам