1
\$\begingroup\$

How I can rewrite or refactor my controller code? I have the same SQL query (@plan_gp_users) in all defs.

 class PlanGpsController < ApplicationController
 def index
 @search = PlanGp.joins(:user).search(params[:q])
 @plan_gps = @search.result.order("created_at DESC").page(params[:page]).per(15)
 @plan_gp_users = User.where("users.ab_id = :abs_id AND users.id != :user_id AND is_admin IS NULL AND role != 'head'", {:abs_id => current_user.ab_id,:user_id =>current_user.id})
 respond_to do |format|
 format.js
 format.html # index.html.erb
 format.json { render json: @plan_gps }
 end
 end
 def show
 @plan_gp = PlanGp.find(params[:id])
 @plan_gp_users = User.where("users.ab_id = :abs_id AND users.id != :user_id AND is_admin IS NULL AND role != 'head'", {:abs_id => current_user.ab_id,:user_id =>current_user.id})
 respond_to do |format|
 format.js
 format.html # show.html.erb
 format.json { render json: @plan_gp }
 end
 end
 # GET /plan_gps/new
 # GET /plan_gps/new.json
 def new
 @plan_gp = PlanGp.new
 # 3.times { render @plan_gp.user_id }
 # .joins("LEFT JOIN plan_gps ON plan_gps.user_id = users.id and strftime('%Y-%m','now') = strftime('%Y-%m',plan_gps.month)") AND plan_gps.user_id is null 
 @plan_gp_users = User.where("users.ab_id = :abs_id AND users.id != :user_id AND is_admin IS NULL AND role != 'head'", {:abs_id => current_user.ab_id,:user_id =>current_user.id})
 # raise @plan_gp_users.to_sql
 respond_to do |format|
 format.js
 format.html # new.html.erb
 format.json { render json: @plan_gp }
 end
 end
 # GET /plan_gps/1/edit
 def edit
 @plan_gp = PlanGp.find(params[:id])
 @plan_gp_users = User.where("users.ab_id = :abs_id AND users.id != :user_id AND is_admin IS NULL AND role != 'head'", {:abs_id => current_user.ab_id,:user_id =>current_user.id})
 end
 # POST /plan_gps
 # POST /plan_gps.json
 def create
 @plan_gp = PlanGp.new(params[:plan_gp])
 @plan_gp_users = User.where("users.ab_id = :abs_id AND users.id != :user_id AND is_admin IS NULL AND role != 'head'", {:abs_id => current_user.ab_id,:user_id =>current_user.id})
 User.where("id IN (:user_ids) AND role != :role", {:user_ids => params[:plan_gp]["user_id"],:role =>'head'}).select("id").map do|m| 
 @plan_gp = PlanGp.new(params[:plan_gp])
 @plan_gp.user_id = m.id
 @plan_gp.abs_id = current_user.ab_id
 if @plan_gp.save 
 @plan_gp_save = true
 else 
 @plan_gp_save = false
 end
 end
 @plan_gp.abs_id = current_user.ab_id
 respond_to do |format|
 if @plan_gp_save
 format.js
 format.html { redirect_to plan_gps_url }
 format.json { render json: @plan_gp, status: :created, location: @plan_gp } 
 else
 format.js
 format.html { redirect_to plan_gps_url }
 format.json { render json: @plan_gp.errors, status: :unprocessable_entity } 
 end
 end
 end
 # PUT /plan_gps/1
 # PUT /plan_gps/1.json
 def update
 @plan_gp = PlanGp.find(params[:id])
 @plan_gp_users = User.where("users.ab_id = :abs_id AND users.id != :user_id AND is_admin IS NULL AND role != 'head'", {:abs_id => current_user.ab_id,:user_id =>current_user.id})
 respond_to do |format|
 if @plan_gp.update_attributes(params[:plan_gp])
 format.js
 format.html { redirect_to @plan_gp, notice: 'Plan gp was successfully updated.' }
 format.json { head :no_content }
 else
 format.js
 format.html { render action: "edit" }
 format.json { render json: @plan_gp.errors, status: :unprocessable_entity }
 end
 end
 end
 # DELETE /plan_gps/1
 # DELETE /plan_gps/1.json
 def destroy
 @plan_gp = PlanGp.find(params[:id])
 @plan_gp.destroy
 respond_to do |format|
 format.js
 format.html { redirect_to plan_gps_url }
 format.json { head :no_content }
 end
 end
end
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Dec 6, 2012 at 7:11
\$\endgroup\$
1
  • \$\begingroup\$ It looks like much of the code is double-spaced (has extra blank lines). Is that an accident of cut-and-paste? \$\endgroup\$ Commented Jan 8, 2014 at 23:53

1 Answer 1

2
\$\begingroup\$

You should use a named Scope in your model

class User < ...
 scope :by_ab_without_user, lambda do |ab_id, id| 
 where(:ab_id => ab_id, :is_admin => null).
 where("id != :user_id AND role != 'head'", { :user_id => id })
 end
 ...
end

You can then use it from your controller with

User.by_ab_without_user(current_user.ab_id, current_user.id)

I'm not a big fan of writing another scope for each query which occurs in a controller though (which might end up only used once). That just increases the noise in the model. So you should strive for orthogonal scopes which can be combined easily. So for the above example you might do:

class User < ...
 scope :not_admin, where(:is_admin => null)
 scope :not_head, where("role != 'head'")
 scope :not_user, lambda { |id| where("id != ?", id) }
 scope :by_ab, lambda { |ab_id| where(:ab_id => ab_id) }
 ...
end

Then you could use them like this

User.not_admin.not_head.not_user(current_user).by_ab(current_user.ab_id)

Or if you need this particular combination often you can define a specialized scope with them (yes you can use other scopes in scope definitions).

But of course it depends on the problem domain wether or not you need that flexibility. So it's probably best to start with specialized scopes and orthogonalize later when you see fit.

Another thing you should do is to put common action initialization code in a before filter

class PlanGpsController < ApplicationController
 before_filter :init_plan_gp_users, :except => :destroy
 ...
private
 def init_plan_gp_users
 @plan_gp_users = ...
 end
end

But you still should use named scopes, because they improve code reusability across controllers.

answered Nov 9, 2013 at 0:59
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.