Entries Tagged 'rails' ↓

Building Named Scopes Conditionally

I recently ran across an article at Caboose.se about building named scopes conditionally to make a slick filter. Unfortunately comments on it are closed now. The code he shared looked like this:

def index
  scopes = []
  scopes << [ :by_user, params[:user_id] ] if params[:user_id]
  scopes << [ :tag_name, params[:tag_name] ] if params[:tag_name]
  scopes << [ :rating, params[:rating] ] if params[:rating]

  order = { 'name' => 'videos.name ASC' }[params[:order]] || 'videos.id DESC'

  @videos = scopes.inject(Video) {|m,v| m.scopes[v[0]].call(m, v[1]) }.paginate(:all, :order => order, :page => params[:page])
end

I found this code soon after writing something similar for myself, and modifying his code to look like mine would give:

def index
  scope = Video
  scope = scope.by_user params[:user_id] if params[:user_id]
  scope = scope.tag_name params[:tag_name] if params[:tag_name]
  scope = scope.rating params[:rating] if params[:rating]

  order = { 'name' => 'videos.name ASC' }[params[:order]] || 'videos.id DESC'

  @videos = scope.paginate(:all, :order => order, :page => params[:page])
end

With this there’s no need for the inject/call, you just call the methods yourself, and skip building an array of symbols/strings. I’m sure this is more efficient, but does this make it more or less readable to you?

I saw Ryan Bates post a response to his article suggesting one could use his scope builder plugin which would turn the code into this:

def index
  scope = Video.scope_builder
  scope.by_user params[:user_id] if params[:user_id]
  scope.tag_name params[:tag_name] if params[:tag_name]
  scope.rating params[:rating] if params[:rating]

  order = { 'name' => 'videos.name ASC' }[params[:order]] || 'videos.id DESC'

  @videos = scope.paginate(:all, :order => order, :page => params[:page])
end

Seems like a very small gain for the introduction of a plugin. Am I missing something? Are there other examples where my solution would not be as attractive? Or is this a case where the original Rails code suits the purpose just fine?