0

I have the following in my controller that will assign a different collection of results depending on what params are received with an Ajax call. It is messy and i would like to just call a function with all the logic in rather than all this in my index controller

class PublicController < ApplicationController
  def index
    if params[:literacy_param].present?
      @skills = Skill.search(params)
    elsif params[:numeracy_param].present?
      @skills = Skill.numeracy_default_params
    elsif params[:numeracy_number_skills].present?
      @skills = Skill.numeracy_number_skills
    elsif params[:numeracy_measuring_skills].present?
      @skills = Skill.numeracy_measuring_skills
    elsif params[:numeracy_data_skills].present?
      @skills = Skill.numeracy_data_skills
    else
      @skills = Skill.default_params
    end
  end
end

Im just a bit unsure on how to set out my function so that it can read the params that are being sent,

I have come up with this so far

private
 def skills(params)
   if params[:literacy_param].present?
     @skills = Skill.search(params)
   elsif params[:numeracy_param].present?
     @skills = Skill.numeracy_default_params
   elsif params[:numeracy_number_skills].present?
    @skills = Skill.numeracy_number_skills
   elsif params[:numeracy_measuring_skills].present?
    @skills = Skill.numeracy_measuring_skills
   elsif params[:numeracy_data_skills].present?
    @skills = Skill.numeracy_data_skills
   else
    @skills = Skill.default_params
   end    
 end

Then in my index action i would do

@skills = skills(params)

would this be an efficient way?

Thanks

2
  • just info. you can also do @skills = if condition ... end instead of repeating @skills all over. being DRY ;) Commented Jan 5, 2015 at 9:14
  • @Nithin Hehehe. Good DRY. :-) Commented Jan 5, 2015 at 9:27

3 Answers 3

3

You can do this

class PublicController < ApplicationController
  def index
    skills = ['literacy_param', 'numeracy_param', 'numeracy_number_skills', 'numeracy_measuring_skills', 'numeracy_data_skills']
    common_in_params = (skills & params).first
    @skills = common_in_params.present? ? (common_in_params.eql?('literacy_param') ? Skill.search(params) : Skill.send(common_in_params)) : Skill.default_params                
  end
end

You can define skills array in an initializer for resusability

Sign up to request clarification or add additional context in comments.

1 Comment

There is a small difference to the original implementation - if literacy_params is an empty string it will use the default. I would go with common_in_params = skills.find {|skill| params[skill].present?} to fix it.
1

One way of doing it would be this:

def skills(params)
  set_of_skills = params.slice(
    :numeracy_param,
    :numeracy_number_skills,
    :numeracy_measuring_skills,
    :numeracy_data_skills,
  ).first

  @skills = if params[:literacy_param]
    Skill.search(params)
  elsif set_of_skills
    Skill.public_send(set_of_skills)
  else
    Skill.default_params
  end
end

I would also advise to have this extracted into a lib/ folder, and unit-tested. So that in your controller you could perform the following:

def index
  @skills = SkillSearch.new(params).search
end

Comments

1

Two ways I can think of doing this right now:

  1. Wrap the params in a unique key. As in params = { :keyword => :literacy_param }, and then use this unique key to identify the right operation.

In you skill.rb:

def self.filter(params)
  if params[:keyword] == :literacy_param
    search(params)
  elsif available_filters.include?(params[:keyword])
    public_send(params[:keyword])
  else
    default_params
  end
end

private

  def self.available_filters
    %i{numeracy_default_params numeracy_number_skills numeracy_measuring_skills numeracy_data_skills}
  end

considering that instead of :numeracy_param, you send :numeracy_default_params in :keyword key. Otherwise you'll have to make another elsif inside filter method.

then in your index method:

def index
  @skilles = Skill.filter(params)
end
  1. You create a separate filter class, which is an expandable solution, just in case when you need to go for complex search queries and filtering.

Let's call it SkillSeacrher, inside you app/models/skill_searcher.rb:

class SkillSearcher
  attr_reader :keyword

  def initialize(keyword)
    @keyword = keyword
  end

  def filter
    if keyword == :literacy_param
      Skill.search(params)
    elsif available_filters.include?(keyword)
      Skill.public_send(keyword)
    else
      Skill.default_params
    end
  end

  private

    def self.available_filters
      %i{numeracy_default_params numeracy_number_skills numeracy_measuring_skills numeracy_data_skills}
    end
end

then in index method:

def index
  @skills = SkillSearcher.new(params[:keyword]).filter
end

However, you can do one more change to filter method(depends on your taste):

def filter
  if keyword == :literacy_param
    Skill.search(params)
  else
    Skill.public_send(available_filters.include?(keyword) ? keyword : :default_params)
  end
end

And, if you have all these methods accepting params as arguments then it'd be much more sleek:

def filter
  Skill.public_send(available_filters.include?(keyword) ? keyword : :default_params, params)
end

Comments

Your Answer

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.