mr_muscle
mr_muscle

Reputation: 2910

Ruby .where query with optional params

I want to display all user Notes but if in params I will have params[:activity_id].present? I want to display all Notes for given activity. The whole code, which works, looks like:

get do
  ::Notes::DetailedSerializer.new(
    params[:activity_id].present? ? activity_notes : all_notes,
  )
end

def all_notes
  Note.where(user_id: current_user.id)
end

def activity_notes
  Note.where(user_id: current_user.id, activity_id: params[:activity_id])
end

So is there a way to use this .where query in one line instead of using two methods? I cannot leave only Note.where(user_id: current_user.id, activity_id: params[:activity_id]) when activity_id is nil because it will not return all Notes but Notes with actvitity_id: nil

Upvotes: 1

Views: 193

Answers (2)

Deepak
Deepak

Reputation: 148

I suggest to use the hash for query and update hash with activity id if passed in params. Then use the query hash query from database by passing it to where method. This will reduce the number of queries to database as well.

Sample:

get do
  query = {user_id: current_user.id}
  query = query.merge({activity_id: params[:activity]}) if params[:activity_id]
  ::Notes::DetailedSerializer.new(Note.where(query))
end

The above query can be further improved by using allowed params check on before filters to make it dynamic. Assuming that params related to query is always passed under key 'query' and checking if the keys in query is mapped with table fields. Need to handle the exceptions as well.

Sample:

get do
  query = {user_id: current_user.id}
  params[:query].keys.each do |key| 
     query = query.merge({key => params[key]})
  end
  ::Notes::DetailedSerializer.new(Note.where(query))
end

Better to go with first option if this is only for one key.

Upvotes: 1

Roc Khalil
Roc Khalil

Reputation: 1385

I would suggest that you add the conditions and then return 1 value at the end.

Example:

get do
  notes = Note.where(user_id: current_user.id)

  if params[:activity_id].present?
    notes = notes.where(activity_id: params[:activity_id])
  end

  ::Notes::DetailedSerializer.new(notes)
end

That way, you can add as many parameters as you want. You can also change the params[:activity_id] into a loop of params:

get do
  notes = Note.where(user_id: current_user.id)

  %i(activity_id).each do |param|
    if params[param].present?
      notes = notes.where(param => params[param])
    end
  end

  ::Notes::DetailedSerializer.new(notes)
end

so you can loop through whatever params you want

Upvotes: 1

Related Questions