将对象数组转换为ActiveRecord::关系

时间:2022-02-01 13:19:21

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.

我想这可以归结为两个问题。

  1. How can I convert an Array of objects to an ActiveRecord::Relation? Preferably without doing a where each time.
  2. 如何将对象数组转换为ActiveRecord::关系?最好不要每次都做。
  3. When running a def self.subjects type method on an ActiveRecord::Relation, how do I access that ActiveRecord::Relation object itself?
  4. 当运行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 call scoped, which will give back a Relation which represents the same records that all 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 field function

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 call scoped, which will give back a Relation which represents the same records that all 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 field function

MySQL域函数