2
\$\begingroup\$

This isn't the actual use-case I have but for simplicity, let's say I have an ActiveRecord Animal model in a Rails app. The Animals have a name (string) and rating (int). There could be animals with the same name but different ratings. In my Animal model I have a hardcoded constant like this:

SPECIAL_ANIMAL_TYPES = [
  { name: 'Cat', rating: 3 },
  { name: 'Dog', rating: 5 },
  { name: 'Fish', rating: 1 }
]

I want to grab a single ActiveRecord:Relation with all Animals that match these attributes exactly. I can't pass an array to the where clause like where(name: ['Cat', 'Dog', etc], rating: [3, 5, 1]) because I only want cats that are rating 3, and dogs that are rating 5 and so on. Like I said, there could be multiple records with the same name but different ratings.

In the Animal model I have a class method (basically a scope) to grab the records that match the types specified in SPECIAL_ANIMAL_TYPES. The following code does what I want, but clearly is pretty ugly and if I added more types to SPECIAL_ANIMAL_TYPES I'd have to modify this method:

def self.special_animals_only
 where(SPECIAL_ANIMAL_TYPES[0]).or(where(SPECIAL_ANIMAL_TYPES[1])).or(where(SPECIAL_ANIMAL_TYPES[2]))
end

I also tried something like:

def self.special_animals_only
  SPECIAL_ANIMAL_TYPES.collect { |types| where(types) }.sum
end

But that returns an array and I want an ActiveRecord Relation. So is there a more elegant way to write this class method so I can continue modifying/adding types to the constant and have this method work dynamically?

\$\endgroup\$
  • \$\begingroup\$ The code snippets I posted do work absolutely correctly (see code snippet #2), but it could be improved, it's not the most elegant solution, which is what I thought this Stack Exchange was for. Would appreciate some actual feedback on how to improve this question! \$\endgroup\$ – kaydanzie Sep 10 at 15:38
3
\$\begingroup\$

Turns out the last code snippet in my question was close to what I ended up needing:

def self.special_animals_only
  SPECIAL_ANIMAL_TYPES.collect { |types| where(types) }.reduce(:or)
end
\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.