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\$

closed as off-topic by πάντα ῥεῖ, 200_success, Dannnno, Grajdeanu Alex., pacmaninbw Sep 10 at 13:08

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Code not implemented or not working as intended: Code Review is a community where programmers peer-review your working code to address issues such as security, maintainability, performance, and scalability. We require that the code be working correctly, to the best of the author's knowledge, before proceeding with a review." – πάντα ῥεῖ, Dannnno, Grajdeanu Alex., pacmaninbw
If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\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.