vshl
vshl

Reputation: 145

Array.select with optional conditionals

I have an Array of Hashes

[
{ :user_id => 123,
  :start_date => Date,
  :end_date => Date
},
{ :user_id => 345,
  :start_date => Date,
  :end_date => Date
},
...
]

I want to select some of the objects based on optional parameters, say if params[:user_id], params[:start_date], params[:end_date] is optionally passed from the controller. How do I include multiple conditionals within a single .select statement.

Array.select do |arr|
   arr[:user_id] == params[:user_id] if params[:user_id] &&
       arr[:start_date] >= params[:start_date] if params[:start_date] &&
       arr[:end_date] <= params[:end_date] if params[:end_date]
end

wasn't working as intended. The 2nd and 3rd conditional is ignored.

Upvotes: 0

Views: 1317

Answers (1)

max pleaner
max pleaner

Reputation: 26758

A pattern I like to use is next. This is basically a way to 'return early' from the block, and split up your conditions into multiple statements. Just make sure you add a true at the end so that if the item passes all the validations, it will be included in the result.

result = array.select do |item|
  if params[:user_id]
    next if item[:user_id] != params[:user_id]
  end
  if params[:start_date]
    next if item[:start_date] <= params[:start_date]
  end
  if params[:end_date]
    next if item[:end_date] >= params[:end_date]
  end
  true
end

you could of course change all these if .. else blocks to one liners if you prefer:

result = array.select do |item|
  next if params[:user_id] && item[:user_id] != params[:user_id]
  next if params[:start_date] && item[:start_date] <= params[:start_date]
  next if params[:end_date] && item[:end_date] >= params[:end_date]
  true
end

Upvotes: 1

Related Questions