开发者

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:

  1. Use named scopes to help increase readability
  2. 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
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜