简体   繁体   中英

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

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

PS 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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM