Ruby on rails 将对象数组转换为ActiveRecord::Relation
我有一个对象数组,让我们称之为Ruby on rails 将对象数组转换为ActiveRecord::Relation,ruby-on-rails,ruby,activerecord,Ruby On Rails,Ruby,Activerecord,我有一个对象数组,让我们称之为指示器。我想在这个数组上运行指示符类方法(定义self.subjects的那些方法)。我知道在一组对象上运行类方法的唯一方法是让它们成为ActiveRecord::Relation。因此,我最终求助于将添加到数组的\u indicators方法 def to_indicators # TODO: Make this less terrible. Indicator.where id: self.pluck(:id) end 有时,我会在类方法中链接相当多的
指示器。我想在这个数组上运行指示符类方法(定义self.subjects的那些方法)。我知道在一组对象上运行类方法的唯一方法是让它们成为ActiveRecord::Relation。因此,我最终求助于将添加到数组的\u indicators
方法
def to_indicators
# TODO: Make this less terrible.
Indicator.where id: self.pluck(:id)
end
有时,我会在类方法中链接相当多的这些作用域以过滤结果。因此,即使我调用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
我想这可以归结为两个问题
如何将对象数组转换为ActiveRecord::Relation?最好不要每次都执行,其中
在ActiveRecord::Relation上运行def self.subjects
type方法时,如何访问ActiveRecord::Relation对象本身
谢谢。如果我需要澄清什么,请告诉我
如何将对象数组转换为ActiveRecord::Relation?最好不要每次都去哪里
您无法将数组转换为ActiveRecord::关系,因为关系只是SQL查询的生成器,其方法不会对实际数据进行操作
但是,如果您想要的是关系,那么:
- 对于ActiveRecord 3.x,不要调用
all
,而是调用,这将返回一个关系,该关系表示all
将在数组中提供给您的相同记录
- 对于ActiveRecord4.x,只需调用,它将返回一个关系
在ActiveRecord::Relation上运行def self.subjects
type方法时,如何访问ActiveRecord::Relation对象本身
当在关系对象上调用该方法时,self
是关系(与它在中定义的模型类相反)。您可以将对象数组arr
转换为如下ActiveRecord::关系(假设您知道对象是哪个类,您可能会这样做)
您必须使用where
,但这是一个非常有用的工具,您不应该不情愿地使用它。现在我们有了一个将数组转换为关系的单行程序
map(&:id)
将对象数组转换为仅包含其id的数组。将数组传递给where子句将生成一个SQL语句,该语句在
中包含,如下所示:
SELECT .... WHERE `my_models`.id IN (2, 3, 4, 6, ....
请记住,数组的顺序将丢失-但由于您的目标只是在这些对象的集合上运行一个类方法,因此我认为这不会是一个问题。在我的例子中,我需要将对象数组转换为ActiveRecord::Relation以及使用特定列(例如id)对它们进行排序。由于我使用的是MySQL,字段函数可能会有所帮助
MyModel.where('id in (?)',ids).order("field(id,#{ids.join(",")})")
SQL看起来像:
SELECT ... FROM ... WHERE (id in (11,5,6,7,8,9,10))
ORDER BY field(id,11,5,6,7,8,9,10)
ActiveRecord::Relation
绑定从数据库检索数据的数据库查询
假设有意义,我们有一个数组,其中包含相同类的对象,那么我们应该用哪个查询来绑定它们呢
当我跑步时
users = User.where(id: [1,3,4,5])
User Load (0.6ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 3, 4, 5) ORDER BY created_at desc
在上面的这里,用户
返回关系
对象,但将数据库查询绑定在其后面,您可以查看它
users.to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 3, 4, 5) ORDER BY created_at desc"
因此,不可能从独立于sql查询的对象数组中返回ActiveRecord::Relation
。首先,这不是一个灵丹妙药。根据我的经验,我发现转变为关系有时比选择更容易。我试图非常谨慎地使用这种方法,并且只在替代方案更复杂的情况下使用
这就是我的解决方案,我扩展了Array
类
\lib/core\u ext/array.rb
类数组
def到_activerecord_的关系
如果self.empty,是否返回ApplicationRecord.none?
clazzes=self.collect(&:class).uniq
如果clazzes.size>1,则raise“数组不能转换为ActiveRecord::Relation,因为它没有相同的元素”
clazz=clazzes.first
raise“元素类不是ApplicationRecord,因此无法转换”,除非clazz.祖先.include?应用记录
分类位置(id:self.collect(&:id))
结束
结束
一个使用示例是array.to\u activerecord\u relation.update\u all(状态:“finished”)
。现在我在哪里使用它
有时您需要过滤掉ActiveRecord::Relation
,例如,去掉未完成的元素。在这种情况下,最好使用scope元素。未完成
,您仍将保持ActiveRecord::Relation
但有时这种情况更为复杂。取出所有未完成的元件,以及在过去4周内生产并经过检查的元件。为了避免创建新的作用域,可以过滤到数组,然后再转换回数组。请记住,您仍然可以快速查询DB,因为它通过id
进行搜索,但仍然是一个查询。如果您尝试将该数组转换回关系的唯一原因是因为您通过获得它。所有,只需使用。如Andrew Marshall的回答所示,使用(虽然在rails 4中,它可以与.all
)一起使用。如果您发现自己需要将数组转换为关系,那么您在某个地方出了问题……做得好,这正是我所需要的。您可以将其用于模型上的任何属性。对我来说非常适合。既然您可以在where(id:arr.map(&:id))中执行操作,为什么还要自己构建文字SQL
?严格地说,这不会将数组转换为关系,而是会获得对象的新实例(一旦关系被转换)
users.to_sql
=> "SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 3, 4, 5) ORDER BY created_at desc"