7

我一直在试图开发一个基于电影的轨道应用程序,它支持多个区域(好莱坞,宝莱坞等)。我在应用程序中将多个区域称为语言。Rails 3复杂的协会使用nested_has_many_through

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

语言模型

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宝石

任何帮助,在此将不胜感激。

+0

作为一个侧面说明,代表地区语言是一个有点令人费解。如果一部印度电影是英文的呢?拆分概念。 – 2011-05-14 03:42:36

+0

如果我理解墙,你的麻烦不是来自嵌套的has_many:through(你有它的宝石),而是来自你想要来自2个来源(电影和名人)的文章? 你试过扭转问题吗?没有在Language中定义has_many关系,而是在Article中定义lambda范围?尽管它可能涉及一些SQL。 – MrRuru 2011-05-15 12:58:17

+0

@MrRuru你是对的。我没有nested_has_many_through gem问题。它做到了它的承诺。你也是对的,我有多个文章的来源,即电影和名人。我试图避免基于SQL的范围,因为基于SQL的范围不会返回给我一个活动关系实例,并且我将无法链接我使用的其他插件(即inherited_resources)所需的范围。 – 2011-05-15 19:10:24

回答

0

好的这就是我所做的解决这个问题。

加在我的文章类中的下列范围

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 ::关系实例。

感谢所有帮助过我的人。

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

1

很少有技巧,应该让你需要什么,走出去的Article可以查询所有Movies对于给定的语言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 

然后在语言定义将使用的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

为了研究这个。我尝试了你的建议,但当我尝试“ActiveRecord :: ConfigurationError:找不到名为'article_movies'的关联时,出现以下错误;也许你拼错了它? ”。我想它的发生是因为我没有在article_association类 – 2011-05-17 03:27:09

+0

中的article_movies,您应该在ArticleAssociation中尝试'belongs_to:article_movie,:class =>'Movie'',但这需要迁移(将键从'movie_id'更改为'article_movie_id' - 我猜 – mpapis 2011-05-17 08:59:22

1

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

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

+0

你说得对,我知道Rails 3.1已经嵌套关联了,我知道我不会长时间使用这个插件。 – 2011-05-21 23:12:35