Reputation: 688
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
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