how to implement ActiveRecord's "scoped" for MongoMapper models in Rails 3?
Note that I'm new to Ruby, so many obvious things are not so obvious for me ;)
I have got many parameters sent to my controller (res, page, since). Using those parameters I'm trying to compose a query for my MongoMapper-based models.
The problem is that I have to specify request for each combination of params I want to provide.
For example
if (params[:res] && para开发者_StackOverflow社区ms[:page] && params[:since])
@movies = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).sort(:DateModified.desc).paginate(:per_page => params[:res], :page => params[:page])
@total_results = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).count
elsif (params[:res] && params[:page])
@movies = Movie.sort(:DateModified.desc).paginate(:per_page => params[:res], :page => params[:page])
@total_results = Movie.count
elsif (params[:since]) # Too slow request
@movies = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).sort(:DateModified.desc)
@total_results = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).count
else # default request
@year_now = Time.new.year
@movies = Movie.limit(30).offset(0).where(:FirstReleasedYear.gt => @year_now-1).sort(:DateModified.desc).order.all
@total_results = Movie.where(:FirstReleasedYear.gt => @year_now).count
end
This is total disaster - if I wanna add some new parameter I will have to add more ifs.
I would love to use this as follows
@movies = Movie.scoped # I've found this in example for ActiveRecord model
if (params[:since])
@movies.where(:FirstReleasedYear.gt => params[:since].to_i-1)
end
# Some other params like sort and so on
if (params[:res] && params[:page])
@movies.paginate(:per_page => params[:res], :page => params[:page])
end
Please give me your advice on how to handle such situation
I'll focus in on this code you have:
@movies = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).sort(:DateModified.desc)
@total_results = Movie.where(:FirstReleasedYear.gt => params[:since].to_i-1).count
Goals:
- Use named scopes to help increase readability
- Do not execute the query twice to get a count
In your model:
class Movie
include MongoMapper::Document
scope :released_in, :lambda{|year| where(:FirstReleasedYear.gt=>(year.to_i -1)}
end
Your controller section will now look:
@movies = Movie.released_in(params[:year]).sort(:DateModified.desc)
@total_results = @movies.count
Other recommendations:
- Don't bother with params[:res], just set it as the defaults
- Don't check if params[:page] exists -- will_paginate will set to 1 if you don't set it
- If you are using will_paginate, you can get the total number of results from it, don't do an extra query to get the count
精彩评论