Rails 3 сложные ассоциации с использованием nested_has_many_through - PullRequest
7 голосов
/ 04 мая 2011

Я пытался разработать приложение, основанное на фильмах, которое поддерживает несколько регионов (Голливуд, Болливуд и т. Д.).Я называю несколько регионов в качестве языков в приложении.

Каждый язык имеет свой собственный набор данных, т. Е. Английский имеет все фильмы, связанные с Голливудом, а язык хинди имеет все фильмы, связанные с Болливудом.

Модель языка

class Language < ActiveRecord::Base
  has_many :movies
  has_many :cast_and_crews, :through => :movies, :uniq => true
  has_many :celebrities, :through => :cast_and_crews, :uniq => true

  # FIXME: Articles for celebrities and movies 
  has_many :article_associations, :through => :celebrities
  has_many :articles, :through => :article_associations, :uniq => true
end

Здесь и у фильмов, и у знаменитостей есть статьи, использующие класс article_association.

Модель фильма

class Movie < ActiveRecord::Base
  belongs_to :language
  has_many :cast_and_crews
  has_many :celebrities, :through => :cast_and_crews
  has_many :article_associations
  has_many :articles, :through => :article_associations, :uniq => true
end

модель знаменитости

class Celebrity < ActiveRecord::Base
  has_many :cast_and_crews
  has_many :movies, :through => :cast_and_crews, :uniq => true
  has_many :article_associations
  has_many :articles, :through => :article_associations, :uniq => true
end

class ArticleAssociation < ActiveRecord::Base
  belongs_to :article
  belongs_to :celebrity
  belongs_to :movie
end

и вот как определяется моя модель изделия

class Article < ActiveRecord::Base
  has_many :article_associations
  has_many :celebrities, :through => :article_associations
  has_many :movies, :through => :article_associations
end

ЧтоЯ пытаюсь добиться того, чтобы language.article должен возвращать все статьи, связанные со знаменитостями и фильмами.

Причина, по которой я не использую SQL, заключается в том, что find_by_sql не поддерживает ActiveRelation, и я не смогу использовать функциональность has_scope.

Я использую драгоценные камни nested_has_many_through, has_scope и inherited_resources

Любая помощь в этом будет принята с благодарностью.

Ответы [ 3 ]

2 голосов
/ 21 мая 2011

Rails 3.1 теперь поддерживает вложенные отношения.Конечно, встроенный должен быть лучше, чем плагин:)

http://railscasts.com/episodes/265-rails-3-1-overview

1 голос
/ 17 мая 2011

Есть несколько трюков, которые должны позволить вам то, что вам нужно. Из Article вы можете запросить все Movies для данного идентификатора языка

class Article < ActiveRecord::Base
  has_many :article_associations
  has_many :celebrities, :through => :article_associations
  has_many :article_movies, :through => :article_associations, :class => 'Movie'
  scope :for_language, lambda {|lang_id| 
    joins(
      :article_associations=>[ 
        :article_movies, 
        {:celebrities => { :cast_and_crews => :movies } } 
      ]
    ).where(
      'movies.language_id = ? OR article_movies.language_id = ?', 
      lang_id, lang_id
    ) 
  } 
end

Затем в языке определите метод, который будет использовать более раннюю область действия Article

.
class Language < ActiveRecord::Base
  has_many :movies
  has_many :cast_and_crews, :through => :movies, :uniq => true
  has_many :celebrities, :through => :cast_and_crews, :uniq => true

  def articles
    Article.for_language id
  end
end

Единственная неуверенная часть в том, как :article_movies будет представлен в sql ...

0 голосов
/ 20 мая 2011

хорошо Это то, что я сделал, чтобы это исправить.

Добавлена ​​следующая область видимости в мой класс Article

def self.region(region_id)
  joins(<<-eos
    INNER JOIN
    (
      SELECT DISTINCT aa.article_id
      FROM regions r
           LEFT JOIN movies m on m.region_id = r.id
           LEFT JOIN cast_and_crews cc on cc.movie_id = m.id
           LEFT JOIN celebrities c on c.id = cc.celebrity_id
           LEFT JOIN events e on e.region_id = r.id
           LEFT JOIN article_associations aa on (aa.event_id = e.id or aa.movie_id = m.id or aa.celebrity_id = c.id)
      WHERE r.id = #{region_id}
    ) aa
  eos
  ).where("aa.article_id = articles.id")
end

Это дает мне ожидаемый экземпляр ActiveRecord :: Relation, который извлекает все записи для фильма, знаменитости или события.

Спасибо всем, кто мне помог.

Если у вас есть какие-либо комментарии, чтобы улучшить его, пожалуйста, прокомментируйте его. Очень ценится.

...