retailevolved
retailevolved

Reputation: 485

Rails DRY up similar controller actions

I have two separate controllers that inherit from Admin::UserBaseController, display a searchable, sortable table of users, and use the same partial views.

Here is the index method of Admin::UsersController:

  def index
    q = "%#{params[:search]}%"
    @users = User.where("first_name like ? or last_name like ? or username like ?", q, q, q).order(sort_column + ' ' + sort_direction).paginate(:page => params[:page])

    respond_to do |format|
      format.html # index.html.erb
      format.json { render :json => @users }
    end
  end

Here is the edit method of Admin::OrganizationsController:

def edit
    @organization = Organization.find(params[:id])
    q = "%#{params[:search]}%"
    @users = @organization.users.where("first_name like ? or last_name like ? or username like ?", q, q, q).order(sort_column + ' ' + sort_direction).paginate(:page => params[:page])
end

There is a lot of similarity between the two methods in the way that the @users variable is assigned. It's a difference of User and @organization.users and that's it. How do I DRY this up?

Upvotes: 1

Views: 653

Answers (2)

Ben Miller
Ben Miller

Reputation: 1484

Move

where("first_name like ? or last_name like ? or username like ?", q, q, q).order(sort_column + ' ' + sort_direction).paginate(:page => params[:page])

to a method in User

such as:

def self.method_name(q,params)
  where("first_name like ? or last_name like ? or username like ?", q, q, q).order(sort_column + ' ' + sort_direction).paginate(:page => params[:page])
end

then just use that method in place of the where

Upvotes: 0

mguymon
mguymon

Reputation: 9015

So what this screams is scopes. This removes the duplicate queries into a single place in the model and enables you to chain scopes onto the class and associations.

class User < ActiveRecord::Base
  scope :search_identity, lambda { |identity| where("first_name like ? or last_name like ? or username like ?", identity, identity, identity) }
  scope :user_order, lambda { |column,direction| order("#{column} #{direction}") }
end

Then in Admin::UsersController

q = "%#{params[:search]}%"
@users = User.search_identity( q ).user_order( sort_column, sort_direction).paginate(:page => params[:page])

In Admin::OrganizationsController:

q = "%#{params[:search]}%"
@users = @organization.users.search_identity( q ).user_order( sort_column, sort_direction).paginate(:page => params[:page])

Making everything nice and succinct.

Upvotes: 2

Related Questions