首页 > 解决方案 > 防止 ActiveRecord 关系转换为数组

问题描述

更新:

如何将虚拟属性添加到模型并保留活动记录关系。

我尝试了以下方法,但是 .each 返回一个数组,而不是活动记录。我还可以使用什么其他方法?


我的set_listable_for方法是将 activerecord 关系转换为数组。我想保留 ActiveRecord 关系。

在运行时,我向活动记录模型添加了 attr_access。

def add_listable_attribute_to(*relation)
  relation.each do |rel|
    rel[1].first.class.class_eval do
      attr_accessor :listable
    end
  end
end

然后我使用这种方法将所有记录的属性值设置为相同的值....

   def set_listable_for(relation, object)
      relation.each do |record|
        record.listable = object
      end
    end

但是,我的 ActiveRecord 关系被转换为 Array afterwords。

如何保留 Active Record 关系,因为我不想要数组。由于我在这里继续使用它并继续对其进行范围和查询......

def union_scope(*relation)
  add_listable_attribute_to(*relation)

  listable = relation.first[0]
  combined = set_listable_for(relation.first[1], listable)
  relation.drop(1).each do |relation_set|
    listable = relation[0]
    set_listable_for(relation_set[1], listable)
    combined = combined.or(relation_set[1])
  end
  combined
end

谢谢

标签: ruby-on-railsrubyactiverecordruby-on-rails-5.2

解决方案


.each调用执行查询并迭代结果。如果在作用域和分页之后在控制器中发生这种情况不会有问题,但是如果在作用域和分页之前调用它,则将加载整个模型数据集,这是不好的。

为避免这种情况,您需要在listable从数据库检索数据后尽可能晚地设置。我可以看到三种方法来处理这个问题:

  1. 在将关系加载到控制器或视图中后,使用装饰器包装关系的实例。这更容易理解,但会将功能从模型层中提取出来。

  2. listableafter_initialize回调中设置。这保留了模型层中的功能,但增加了很多复杂性。

  3. 确保您仅set_listable_for在确定范围后调用控制器。#1 的变体。


推荐阅读