Rails 3 使用nested_has_many_through 进行复杂关联

发布于 2024-11-04 22:38:08 字数 1840 浏览 0 评论 0原文

我一直在尝试开发一个基于电影的 Rails 应用程序,它支持多个地区(好莱坞、宝莱坞等)。我将多个区域称为应用程序中的语言。

每种语言都有自己的一组数据,即英语有与好莱坞相关的所有电影,印地语有与宝莱坞相关的所有电影。

语言模型

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 gems

对此的任何帮助将不胜感激。

I have been trying to develop a movie based rails application which has support for multiple regions (Hollywood, Bollywood etc). I call the multiple regions as languages in the application.

Each language has its own set of data i.e., english has all the movies related to hollywood and language hindi has all the movies related to bollywood.

Language Model

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

Here movies and celebrities both have articles using the article_association class.

Movie Model

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

Celebrity Model

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

and this is how my Article model is defined

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

What I am trying to achieve is language.article should return all the articles related to celebrities and movies.

The reason why I am not using SQL is find_by_sql does not support ActiveRelation and I will not be able use has_scope functionality.

I am using nested_has_many_through, has_scope and inherited_resources gems

Any help in this will be greatly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一紙繁鸢 2024-11-11 22:38:08

Rails 3.1 现在支持嵌套关系。当然,内置的应该比插件更好:)

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

Rails 3.1 now has support for nesting relations. Of course the built in one should be better then a plugin :)

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

拥醉 2024-11-11 22:38:08

有一些技巧可以满足您的需求,在 Article 之外,您可以查询给定语言 id 的所有 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 中表示...

There are few tricks that should allow what you need, going out of Article you can query all the Moviesfor given language id

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

Then in language define a method that will use earlier scope of 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

The only unsure part here is how :article_movies will be represented in sql ...

无妨# 2024-11-11 22:38:08

好的,这就是我解决这个问题的方法。

在我的 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 实例,我期望它检索电影、名人或事件的所有记录。

感谢所有帮助过我的人。

如果您有任何改进意见,请评论。非常感谢。

ok This is what I did to fix this.

Added the following scope in my Article class

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

This gives me a ActiveRecord::Relation instance that I am expected which retrieves all the records for a movie, celebrity or event.

Thanks for all who helped me.

If you have any comments to improve it please comment it. Very much appreciated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文