0

My idea for an #index method of a controller is to set things = Thing.all and then if there are filter params, check for them one by one and chain them on so that at the end, you're left with a single query to execute. But the following queries get executed as they are called:

def things_controller
  def index
    things = Thing.all #<-- db call #1

    if params[:color]
      things = things.where(color: params[:color]) #<-- db call #2
    end

    render json: things  #<-- I would like to make a single db call here instead
  end
end

How can I prevent multiple unnecessary db calls? Is there some convention for filter params that I should be using?

2 Answers 2

1

You just need to reorganise the code like this:

  def index
    things = if params[:color]
               Thing.where(color: params[:color])
             # ...else if 
             else
               Thing.all
             end
    render json: things
  end

Updated

If you want to chain where clauses, do this:

def index
  valid_params_keys = %w(color size)

  filtered_keys = valid_params_keys.select { |key| params.keys.include?(key) }

  # Don't need conditional check anymore :).
  @products = filtered_keys.inject(Product.all) do |scope, key|
    scope.where(key => params[key])
  end 
end
Sign up to request clarification or add additional context in comments.

4 Comments

But imagine if there were two params: color and size. You couldn’t just add an elsif for the size param. It would stop after the if part. That’s why I want to construct the query first, and then tell it to execute. I might just have to do it with strings and then use ‘connection.execute’, but was hoping to be able to do it by chaining ‘where’s
Yea, If you know what params keys are in advance, you can chain where clause using inject. That wouldn’t be too hard
You're not talking about Enumerable#inject are you? Can you give me an example? I'd be very interested if this will do the trick. Tho I'm still thinking maybe theres just some completely other standard way to write a controller that I just don't know about.
hiya, updated my answer. Check rails log to see in action :).
0

Since things is an array, you can do this, which is only an array operation.

def index
  things = Thing.all

  if params[:color]
    things = things.select!{ |thing| thing.color == params[:color]}
  end

  render json: things 
end

1 Comment

doing this is less optimal if table is large though

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.