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 self的那些方法)。在该数组上的主题种类、范围等)。我知道在一组对象上运行类方法的唯一方法是让它们成为ActiveRecord::Relation。因此,我最终求助于向数组添加to_indicators方法。
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:
有时,我在类方法中链接了许多这样的作用域来过滤结果。因此,即使我调用ActiveRecord::Relation上的一个方法,我也不知道如何访问该对象。我只能通过所有的内容来了解它的内容。但所有的都是数组。因此,我必须将这个数组转换为ActiveRecord::关系。例如,这是其中一个方法的一部分:
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.
我想这可以归结为两个问题。
- How can I convert an Array of objects to an ActiveRecord::Relation? Preferably without doing a
where
each time. - 如何将对象数组转换为ActiveRecord::关系?最好不要每次都做。
- When running a
def self.subjects
type method on an ActiveRecord::Relation, how do I access that ActiveRecord::Relation object itself? - 当运行def self时。在ActiveRecord:::关系上的subject类型方法,我如何访问那个ActiveRecord:::关系对象本身?
Thanks. If I need to clarify anything, let me know.
谢谢。如果我需要澄清什么,请告诉我。
3 个解决方案
#1
39
How can I convert an Array of objects to an ActiveRecord::Relation? Preferably without doing a where each time.
如何将对象数组转换为ActiveRecord::关系?最好不要每次都做。
You cannot convert an Array to an ActiveRecord::Relation since a Relation is just a builder for a SQL query and its methods do not operate on actual data.
不能将数组转换为ActiveRecord::关系,因为关系只是SQL查询的构建器,它的方法不对实际数据进行操作。
However, if what you want is a relation then:
然而,如果你想要的是一种关系,那么:
-
for ActiveRecord 3.x, don’t call
all
and instead callscoped
, which will give back a Relation which represents the same records thatall
would give you in an Array.ActiveRecord 3。x,不要调用all,而是调用作用域,它将返回一个关系,该关系表示一个数组中所有的记录。
-
for ActiveRecord 4.x, simply call
all
, which returns a Relation.ActiveRecord 4。x,简单地调用all,它返回一个关系。
When running a
def self.subjects
type method on an ActiveRecord::Relation, how do I access that ActiveRecord::Relation object itself?当运行def self时。在ActiveRecord:::关系上的subject类型方法,我如何访问那个ActiveRecord:::关系对象本身?
When the method is called on a Relation object, self
is the relation (as opposed to the model class it’s defined in).
当在关系对象上调用方法时,self就是关系(与在其中定义的模型类相反)。
#2
124
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)
您可以将一个对象数组arr转换为这样的ActiveRecord::关系(假设您知道对象是哪个类,您可能会这么做)
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.
但是你必须使用where,它是一个有用的工具,你不应该不愿意使用它。现在你有了一个一行程序将数组转换成一个关系。
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:
map(&:id)将把对象数组转换为仅包含其id的数组。将数组传递到where子句将生成一个SQL语句,其中包含如下内容:
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.
请记住数组的顺序将会丢失——但是由于您的目标只是在这些对象的集合上运行一个类方法,所以我认为这不会是个问题。
#3
3
Well, in my case, I need to converting an array of objects to ActiveRecord::Relation as well as sorting them with a specific column(id for instance). Since I'm using MySQL, the field function could be helpful.
在我的示例中,我需要将对象数组转换为ActiveRecord::Relation,并使用特定的列(例如id)对它们进行排序。因为我使用的是MySQL,所以字段函数会很有用。
MyModel.where('id in (?)',ids).order("field(id,#{ids.join(",")})")
The SQL looks like:
SQL的样子:
SELECT ... FROM ... WHERE (id in (11,5,6,7,8,9,10))
ORDER BY field(id,11,5,6,7,8,9,10)
MySQL域函数
#1
39
How can I convert an Array of objects to an ActiveRecord::Relation? Preferably without doing a where each time.
如何将对象数组转换为ActiveRecord::关系?最好不要每次都做。
You cannot convert an Array to an ActiveRecord::Relation since a Relation is just a builder for a SQL query and its methods do not operate on actual data.
不能将数组转换为ActiveRecord::关系,因为关系只是SQL查询的构建器,它的方法不对实际数据进行操作。
However, if what you want is a relation then:
然而,如果你想要的是一种关系,那么:
-
for ActiveRecord 3.x, don’t call
all
and instead callscoped
, which will give back a Relation which represents the same records thatall
would give you in an Array.ActiveRecord 3。x,不要调用all,而是调用作用域,它将返回一个关系,该关系表示一个数组中所有的记录。
-
for ActiveRecord 4.x, simply call
all
, which returns a Relation.ActiveRecord 4。x,简单地调用all,它返回一个关系。
When running a
def self.subjects
type method on an ActiveRecord::Relation, how do I access that ActiveRecord::Relation object itself?当运行def self时。在ActiveRecord:::关系上的subject类型方法,我如何访问那个ActiveRecord:::关系对象本身?
When the method is called on a Relation object, self
is the relation (as opposed to the model class it’s defined in).
当在关系对象上调用方法时,self就是关系(与在其中定义的模型类相反)。
#2
124
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)
您可以将一个对象数组arr转换为这样的ActiveRecord::关系(假设您知道对象是哪个类,您可能会这么做)
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.
但是你必须使用where,它是一个有用的工具,你不应该不愿意使用它。现在你有了一个一行程序将数组转换成一个关系。
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:
map(&:id)将把对象数组转换为仅包含其id的数组。将数组传递到where子句将生成一个SQL语句,其中包含如下内容:
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.
请记住数组的顺序将会丢失——但是由于您的目标只是在这些对象的集合上运行一个类方法,所以我认为这不会是个问题。
#3
3
Well, in my case, I need to converting an array of objects to ActiveRecord::Relation as well as sorting them with a specific column(id for instance). Since I'm using MySQL, the field function could be helpful.
在我的示例中,我需要将对象数组转换为ActiveRecord::Relation,并使用特定的列(例如id)对它们进行排序。因为我使用的是MySQL,所以字段函数会很有用。
MyModel.where('id in (?)',ids).order("field(id,#{ids.join(",")})")
The SQL looks like:
SQL的样子:
SELECT ... FROM ... WHERE (id in (11,5,6,7,8,9,10))
ORDER BY field(id,11,5,6,7,8,9,10)
MySQL域函数