将对象数组转换为ActiveRecord :: Relation

Nat*_*han 93 ruby activerecord ruby-on-rails

我有一个对象数组,我们称之为Indicator.我想def self.subjects在这个数组上运行Indicator类方法(变种类,范围等).我知道在一组对象上运行类方法的唯一方法是让它们成为ActiveRecord :: Relation.所以我最终要求添加一个to_indicators方法Array.

def to_indicators
  # TODO: Make this less terrible.
  Indicator.where id: self.pluck(:id)
end
Run Code Online (Sandbox Code Playgroud)

有时我会链接相当多的这些范围来过滤类方法中的结果.所以,即使我在ActiveRecord :: Relation上调用一个方法,我也不知道如何访问该对象.我只能通过它来获取它的内容all.但是all是一个数组.那么我必须将该数组转换为ActiveRecord :: Relation.例如,这是其中一种方法的一部分:

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
Run Code Online (Sandbox Code Playgroud)

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

  1. 如何将对象数组转换为ActiveRecord :: Relation?最好不要where每次都做.
  2. def self.subjectsActiveRecord :: Relation上运行类型方法时,如何访问ActiveRecord :: Relation对象本身?

谢谢.如果我需要澄清任何事情,请告诉我.

Mar*_*ins 152

你可以arr像这样将一个对象数组转换为一个ActiveRecord :: Relation(假设你知道对象是哪个类,你可能会这样做)

MyModel.where(id: arr.map(&:id))
Run Code Online (Sandbox Code Playgroud)

你必须使用where它,它是一个你不应该不愿意使用的有用工具.现在你有一个单行程序将数组转换为关系.

map(&:id)将您的对象数组转换为仅包含其ID的数组.将数组传递给where子句将生成一个SQL语句,IN其外观如下所示:

SELECT .... WHERE `my_models`.id IN (2, 3, 4, 6, ....
Run Code Online (Sandbox Code Playgroud)

请记住,数组的顺序将丢失 - 但由于您的目标只是在这些对象的集合上运行类方法,我认为它不会是一个问题.

  • 非常低效!您已将内存中已有的对象集合转换为要进行数据库查询的对象.我会考虑重构那些你想要迭代数组的类方法. (8认同)
  • 为什么在你可以做`where(id:arr.map(&:id))`时自己构建文字SQL?严格地说,这不会将数组转换为关系,而是使用那些可能具有与数组中已经存储器内实例不同的属性值的对象(一旦实现关系)获取对象的新实例. (7认同)
  • 但是,这会失去排序. (7认同)
  • 干得好,正是我需要的.您可以将此用于模型上的任何属性.适合我. (3认同)
  • 没有男人@james2m男人,这是高效的男人. (3认同)
  • @VelizarHristov那是因为它现在是一个关系,只能按列排序,而不是您想要的任何方式。关系处理大型数据集的速度更快,并且会存在一些权衡。 (2认同)
  • @james2m 你能想到一种更有效的方法来将任何对象数组转换为活动记录关系吗?据我所知,在 Rails 中没有内置的方法或方法可以做到这一点。这是 Rails 中最实用的方法。 (2认同)

And*_*all 44

如何将对象数组转换为ActiveRecord :: Relation?最好不要每次都做一次.

您无法将Array转换为ActiveRecord :: Relation,因为Relation只是SQL查询的构建器,并且其方法不能对实际数据进行操作.

但是,如果你想要的是一个关系,那么:

  • 对于ActiveRecord 3.x,不要调用all而是调用scoped,这将返回一个Relation,它表示all将在Array中提供的相同记录.

  • 对于ActiveRecord 4.x,只需调用all,返回一个Relation.

def self.subjectsActiveRecord :: Relation上运行类型方法时,如何访问ActiveRecord :: Relation对象本身?

在Relation对象上调用方法时,self是关系(与其定义的模型类相对).


Xin*_*Xia 5

好吧,以我为例,我需要将对象数组转换为ActiveRecord :: Relation并使用特定的列(例如,id)它们进行排序。由于我使用的是MySQL,因此field函数可能会有所帮助。

MyModel.where('id in (?)',ids).order("field(id,#{ids.join(",")})") 
Run Code Online (Sandbox Code Playgroud)

SQL看起来像:

SELECT ... FROM ... WHERE (id in (11,5,6,7,8,9,10))  
ORDER BY field(id,11,5,6,7,8,9,10)
Run Code Online (Sandbox Code Playgroud)

MySQL字段功能