Mathieu
Mathieu

Reputation: 4797

DRY Rails controller to avoid repeating multiple times same method

I would like to DRY my controller as I use some snippets/blocks of code many times inside the same controller (I have removed some as it was too long but this already gives an idea of the repetition). Here are the blocks I keep repeating :

I'm quite rookie and don't know how to do this but I feel this code should be factorized.

class DealsController < ApplicationController

  before_filter :find_deal,
    :only => [  :showcase ]
  before_filter :ensure_canonical_deal_path!,
    :only => [  :showcase ]   

  def showcase    
    # find appropriate deal
    @deal = search_deal 

    respond_to do |format|
      format.html # showcase.html.erb
      format.json { render json: @deal }
    end      

  end  

  def buy_stuff
    @deal = search_deal 
    # bring 'next deal' url to the view
    @next_deal                   = find_next_deal

    # USER IS SIGNED-IN
    if user_signed_in?

      @userdeal                     = find_or_create_userdeal_participation
      @user_credits = calculate_user_credits_in_deal

      # if: user still has credits available
      if @user_credits >= 1 
        #do this
        respond_to do |format|
          format.js 
        end

      else
        respond_to do |format|
          # do that
        end
      end  

    # USER IS NOT SIGNED-IN 

    else  
      respond_to do |format|
        format.js { render :template => "deals/call_to_sign_in.js.erb" }
      end
    end
  end


  def show_discounts
    @deal = search_deal 
    respond_to do |format|
      #do that
    end
  end

  def pending_deals
    @deal = search_deal 
    # bring 'next deal' url to the view
    @next_deal                   = find_next_deal
    if user_signed_in?

      @userdeal                     = find_or_create_userdeal_participation
      @user_credits = calculate_user_credits_in_deal
    end

    respond_to do |format|
      #do this
    end
  end

  def ask_question
    @deal = search_deal 
    respond_to do |format|
      #do that
    end
  end


  protected  


    def ensure_canonical_deal_path!
      if request.path != actual_deal_page_path(@deal)
        redirect_to actual_deal_page_path(@deal, :format => params[:format]), :status => :moved_permanently
        return false
      end
    end



  private
    # DRY file as this is used multiple times 
    # trick source - http://blog.rstankov.com/rails-anti-pattern-setting-view-variables-in-before-actions/
    def search_deal
      Deal.friendly.find(params[:id])
    end

    def find_or_create_userdeal_participation
      UserDeal.where('user_id = ? AND deal_id = ?', current_user.id, @deal.id).take ||
      UserDeal.create(user_id: current_user.id, deal_id: @deal.id)
    end

    def calculate_user_credits_in_deal
      current_user.credit_nb + @userdeal.history
    end

    def find_next_deal
      Deal.order_next_deal_at(@deal).next
    end

end

Upvotes: 0

Views: 825

Answers (2)

sawa
sawa

Reputation: 168269

class DealsController < ApplicationController
  before_filter :find_deal, only: [:showcase]
  before_filter :ensure_canonical_deal_path!, only: [:showcase]

  def showcase
    search_deal
    respond_to do |format|
      format.html
      format.json{render json: @deal}
    end      
  end  
  def buy_stuff
    search_deal 
    find_next_deal
    if user_signed_in?
      find_or_create_userdeal_participation
      calculate_user_credits_in_deal
      if @user_credits >= 1
        respond_to(&:js)
      else
        respond_to{|format| }
      end  
    else  
      respond_to{|format| format.js{render template: "deals/call_to_sign_in.js.erb"}}
    end
  end
  def show_discounts
    search_deal 
    respond_to{|format|}
  end
  def pending_deals
    search_deal 
    find_next_deal
    if user_signed_in?
      find_or_create_userdeal_participation
      calculate_user_credits_in_deal
    end
    respond_to{|format| }
  end
  def ask_question
    search_deal 
    respond_to{|format| }
  end
  protected def ensure_canonical_deal_path!
    if request.path != actual_deal_page_path(@deal)
      redirect_to actual_deal_page_path(@deal, format: params[:format]), status: :moved_permanently
      return false
    end
  end
  private def search_deal
    @deal = Deal.friendly.find(params[:id])
  end
  private def find_or_create_userdeal_participation
    @user_deal =
    UserDeal.where('user_id = ? AND deal_id = ?', current_user.id, @deal.id).take ||
    UserDeal.create(user_id: current_user.id, deal_id: @deal.id)
  end
  private def calculate_user_credits_in_deal
    @user_credits = current_user.credit_nb + @userdeal.history
  end
  private def find_next_deal
    @next_deal = Deal.order_next_deal_at(@deal).next
  end
end

Upvotes: 0

Thorin
Thorin

Reputation: 2034

I think the best way to just add before_filters for those methods where you are calling repeat code like:

before_filter :search_deal, :only => [:showcase, :buy_stuff, ...]

Upvotes: 1

Related Questions