开发者

Rails where with join, but return object of parent?

Suppose I have a class that represents a list of movies, belonging to a user:

class User < ActiveRecord::Base
    has_one :movie_list
end

class MovieList < ActiveRecord::Base
    belongs_to :user

    has_many :movie_list_movie_relationships
    has_many :movies, :through => :movie_list_movie_relationships
end

class Movie < ActiveRecord::Base
    has_many :movie_list_movie_relationships
    has_many :movie_lists, :through => :movie_list_movie_relationships
end

class MovieListMovieRelationship < ActiveRecord::Base
   开发者_高级运维 belongs_to :movie
    belongs_to :movie_list
end

Is there any way to have a method on MovieList that returns a MovieList containing only movies with, for example, a specific release year. I want something like:

class MovieList < ActiveRecord::Base
    ....
    def for_year year
        movies.where(:year => year)
    end
end

EXCEPT that I want the result to be a MovieList itself, whereas this returns an array of Movies. So I could do, for example:

list = User.first.movie_list.for_year(1999)
list.id # would give the id of the MovieList = User.first.movie_list.id
list.movies.first.id # would give the id of the first movie in list

I have a feeling that I'm either a) faced with this problem because my design is bad, and it would be great if someone could explain how I should design this, or b) asking for something relatively mundane but I just don't know the right terminology.

Thanks!

Edit

I have specific reasons for wanting a MovieList and not an array of Movies. For one, I've written the question with User has_one :movie_list but in reality a User has_many :movie_lists (e.g., "Movies I have on DVD", "Movies I want to see", etc). That's why I don't just use a simple join between User and Movie. I want a MovieList because I want the id of the list to get passed around to make it easy to add a movie to a specific list; I have a MovieListMovieRelationshipController. I think what I'm going to end up having to do is fetch the movies as an array and just pass around the list id manually.

Edit 2

Here's what I ended up doing, as per @normalocity and the ensuing comments. Any further comments/suggestions are appreciated :)

class MovieList
    ...
    def limit_to_year year
        new_list = MovieList.new(self.attributes)
        new_list.id = self.id
        new_list.movies = []

        limited_movies = movies.where(:year => year)
        new_list.movies = limited_movies
        return new_list
    end
end


You can't do what you're hoping for directly, no, but it's simple enough to create an empty MovieList, and then add the array of movies from your for_year method to the new MovieList. You can even make the query for the array of associated Movie objects faster/simpler via a named_scope.

  • Create a named scope to get all Movies from a specific year:

In Movie class:

named_scope :for_year, lambda { |year| {:conditions => ["year = ?", year]} }

Now, every time you call Movie.for_year("1945") you get back an array of Movie objects from that year.

Then...

  • Create a new MovieList (that belongs to NO user), and add the results from #1 to the list

This might work: movies1945 = MovieList.create(:movies => Movie.for_year("1945")

If it doesn't work, you might have to split up the creation of the new MovieList object, and the assignment of values to the Movie collection.

If you need to distinguish between a simple list of Movies (what's the difference between that and an Array, I don't know, but if that distinction is necessary), and the Movies that a particular user has in their collection, then you could separate your classes into MovieList (just a list of movies) and a Collection (the movies that a given user has).

If you don't need that, then the 1945 movie list could either have a nil user, or (say your web site is called imdb.com) you could create a dummy user account called "imdb", and have the list belong to that user.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜