I have an array of objects, let's call it an Indicator
. I want to run Indicator class methods (those of the def self.subjects
variety, scopes, etc) on this array. The only way I know to run class methods on a group of objects is to have them be an ActiveRecord::Relation. So I end up resorting to adding a to_indicators
method to Array
.
def to_indicators # TODO: Make this less terrible. Indicator.where id: self.pluck(:id) end
At times I chain quite a few of these scopes to filter down the results, within the class methods. So, even though I call a method on an ActiveRecord::Relation, I don't know how to access that object. I can only get to the contents of it through all
. But all
is an Array. So then I have to convert that array to a ActiveRecord::Relation. For example, this is part of one of the methods:
all.to_indicators.applicable_for_bank(id).each do |indicator| total += indicator.residual_risk_for(id) indicator_count += 1 if indicator.completed_by?(id) end
I guess this condenses down to two questions.
where
each time.def self.subjects
type method on an ActiveRecord::Relation, how do I access that ActiveRecord::Relation object itself?Thanks. If I need to clarify anything, let me know.
The Relation Class. Having queries return an ActiveRecord::Relation object allows us to chain queries together and this Relation class is at the heart of the new query syntax. Let's take a look at this class by searching through the ActiveRecord source code for a file called relation.
ActiveRecord::Base indicates that the ActiveRecord class or module has a static inner class called Base that you're extending.
What is ActiveRecord? ActiveRecord is an ORM. It's a layer of Ruby code that runs between your database and your logic code. When you need to make changes to the database, you'll write Ruby code, and then run "migrations" which makes the actual changes to the database.
You can convert an array of objects arr
to an ActiveRecord::Relation like this (assuming you know which class the objects are, which you probably do)
MyModel.where(id: arr.map(&:id))
You have to use where
though, it's a useful tool which you shouldn't be reluctant to use. And now you have a one-liner converting an array to a relation.
map(&:id)
will turn your array of objects to an array containing only their id's. And passing an array to a where clause will generate a SQL statement with IN
that looks something like:
SELECT .... WHERE `my_models`.id IN (2, 3, 4, 6, ....
Keep in mind that the ordering of the array will be lost - But since your objective is only to run a class method on the collection of these objects, I assume it won't be a problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With