frostbite
frostbite

Reputation: 688

Rails model query with many optional params

A user wants to search by an attribute and/or order the results. Here are some example requests

/posts?order=DESC&title=cooking
/posts?order=ASC
/posts?title=cooking

How can I conditionally chain such options to form a query?

So far I have a very ugly method that will quickly become difficult to maintain.

  def index
    common = Hash.new
    common["user_id"] = current_user.id

    if params[:order] && params[:title]

      @vacancies = Post.where(common)
                          .where("LOWER(title) LIKE ?", params[:title])
                          .order("title #{params[:order]}")

    elsif params[:order] && !params[:title]

      @vacancies = Post.where(common)
                          .order("title #{params[:order]}")

    elsif params[:title] && !params[:order]

      @vacancies = Post.where(common)
                          .where("LOWER(title) LIKE ?", params[:title])
    end
  end

Upvotes: 0

Views: 31

Answers (1)

Jordan Running
Jordan Running

Reputation: 106027

Remember that query methods like where and order are meant to be chained. What you want to do is start with a base query (like Post.where(common), which you use in all cases) and then conditionally chain other methods:

def index
  common = Hash.new
  common["user_id"] = current_user.id

  @vacancies = Post.where(common)

  if params[:order]
    @vacancies = @vacancies.order(title: params[:order].to_sym)
  end

  if params[:title]
    @vacancies = @vacancies.where("LOWER(title) LIKE ?", params[:title])
  end
end

P.S. Your original code had .order("title #{params[:order]}"). This is very dangerous, since it opens you up to SQL injection attacks. As a rule of thumb never use string concatenation (#{...}) with a value you get from the end user when you're going to pass the result to the database. Accordingly, I've changed it to .order(title: params[:order]). Rails will use this hash to construct a secure query so you don't have to worry about injection attacks.

You can read more about SQL injection attacks in Rails in the official Ruby on Rails Security Guide.

Upvotes: 1

Related Questions