Rails 3 Complex Associations Using nested_has_many_through

I am trying to develop a movie-based application that supports several regions (Hollywood, Bollywood, etc.). I name several areas as languages โ€‹โ€‹in the application.

Each language has its own data set, i.e. in English there are all films related to Hollywood and Hindi in the language, all films 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 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 thatโ€™s 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, language.article, should return all the articles related to celebrities and films.

The reason I am not using SQL is that find_by_sql does not support ActiveRelation, and I cannot use the has_scope functions.

I use nested_has_many_through, has_scope and inherited_resources gems

Any help on this would be greatly appreciated.

+7
source share
3 answers

ok Here is what I did to fix it.

The following class is added to the 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 an instance of ActiveRecord :: Relation, which I expect, which retrieves all the entries for a movie, celebrity, or event.

Thanks to everyone who helped me.

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

0
source

There are a few tricks that should allow what you need, leaving the Article , you can request all Movies for a given id language

 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 the language, define a method that will use the earlier area 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 uncertain part here is how :article_movies will be presented in sql ...

+1
source

Rails 3.1 now supports nesting relationships. Of course, the built-in one should be better than the plugin :)

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

+1
source

All Articles