ActiveRecord:过滤子项而不访问数据库

时间:2009-12-14 21:02:20

标签: ruby activerecord

我正在寻找一种干净的方法来过滤has_many关系中父级的子级而不会访问数据库,从而将db的对象视图重新加载回应用程序。

例如:

class Parent < ActiveRecord::Base
  has_many :children, ...
  ...
end

我的理解(如果我错了,请纠正我)

parent.children.find_all_by_attr('foo')

返回db中具有attr值'foo'的所有父级子级,但由于它再次命中数据库,所有在保存之前将其attr值设置为foo的子级将恢复其db值从而覆盖任何改变。

我用

攻击了这个
parent.children.reject { |child| child.attr != 'foo' }

但这看起来很草率,更难阅读。有没有人对如何做到这一点提出更清晰的建议?

2 个答案:

答案 0 :(得分:3)

做了一些戳之后,看起来它比这复杂一点。 我的戳子是这样的:

  • 我创建了一对模型,Parent 和has_many的孩子 在一次性铁轨中的关系 应用程序。
  • 我打开了script/console和 戳了戳。

我创建了一个带有孩子的新父母并保存了他们

>> p = Parent.new;p.children << Child.new(:foo=>'bar');p.save
=> true

看到孩子在db中并且可以找到by_foo

>> p.children.find_by_foo('bar')
=> #<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05">

我在集合中添加了另一个子节点,它显示在p.children中,但不会显示在命中数据集的集合方法中。

>> p.children << Child.new(:foo=>'bar')
=> [#<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05">, #<Child id: 2, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:25", updated_at: "2009-12-14 22:08:25">]
>> p.children.find_by_foo('bar')
=> #<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05">

我改变了数据库中的孩子。

>> p.children[0].foo = 'baz'
=> "baz"

当我搜索它时,它会给我db版本。

>> p.children.find_by_foo('bar')
=> #<Child id: 1, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05">

但是,本地收藏没有变化。

>> p.children
=> [#<Child id: 1, foo: "baz", parent_id: 1, created_at: "2009-12-14 22:08:05", updated_at: "2009-12-14 22:08:05">, #<Child id: 2, foo: "bar", parent_id: 1, created_at: "2009-12-14 22:08:25", updated_at: "2009-12-14 22:08:25">]

因此,如果再次保存p,它将传递更改。

如果要获取所有本地关联对象,包括已更改的对象,则不能使用ActiveRecord查找器,因为它们命中了db,而是使用上面的数组方法。但是,使用find_allselect会更容易理解

parent.children.select{|c| c.attr == 'foo'}

答案 1 :(得分:0)

您可以执行reject的相反操作,即find_all

parent.children.find_all {|child| child.attr == 'foo' }