Question

Here is what I have

currently, I'm doing this:

current_account.send(object).search(params[:search]).user_id_equals_any(users).visibility_is_any(visibilities)

but thats not very flexible? What if I want to conditionally not have one of those scopes?

I figure an array of scopes with conditionally added elements would be a good solution

An array of parameters that I would invoke using .send()

scopes = []    
scopes = << [:user_id_equals_any, users] if filter_users
    scopes = << [:visibility_is_any, visibilities] if filter_visibility

So, I could have some unknown number scopes.

To execute the scopes, I need to invoke .send(:scope_name, scope_param)

But How do I do that for any number of scopes in my scopes array?

As a loop, I think It would be something like

result = current_account.send(object).search(params[:search])
scopes.each do |scope|
    result.send(scope[0], scope[1])
end
return result

the loop can be simplified to

scopes.each {|s| result.send(s[0], s[1]) }

but is there a way to append the different send calls in one line?

Was it helpful?

Solution

You can use inject:

scopes = []
# Note that in your example, the assignment is invalid syntax
scopes << [:user_id_equals_any, users] if filter_users
scopes << [:visibility_is_any, visibilities] if filter_visibility

# initial result
result = current_account.send(object).search(params[:search])

# applying the scopes
result = scopes.inject(result) do |result, (method, param)|
  result.send(method, param)
end
return result

In each loop, the last return value of the previous block execution gets passed the first parameter of the block, in this case result. The first loop gets the initial result (i.e. the parameter in square brackets to the inject call. The return value of the last loop gets returned.

For more details, have a look at the documentation.

OTHER TIPS

Feel free to build your own abstractions so your code reflects how you think about a problem:

class Object
  def send_if(condition, *args, &block)
    condition ? send(*args, &block) : self
  end
end

current_account.send(object).search(params[:search]).
  send_if(filter_user, :user_id_equals_any, users).
  send_if(filter_visibility, :visibility_is_any, visibilities)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top