活动记录其中语句从嵌套对象中选择字段



给定

class Foo
  has_many :bar
end
class Bar
  belongs_to :foo
end

我想要:

=> #<ActiveRecord::Relation [#<Foo id: 11, qux: 'hi', bar_id: 1, bar_name: 'blah', bar_something: 'blahblah' >, #<Foo id: 23, qux: 'hi', bar_id: 2, bar_name: 'lorem', bar_something: 'ipsum' >]>

我可以这样做:

> Foo.where(qux: 'hi').includes(:bar)
=> #<ActiveRecord::Relation [#<Foo id: 11, qux: 'hi', bar_id: 1 >, #<Foo id: 23, qux: 'hi', bar_id: 2 >]>

但它不会加载子记录。它似乎只是为了在需要时坚持它。

一定有比这更优雅的东西吧?

Foo.where(qux: 'hi').includes(:bar).to_a.map do | f |
  f.keys.each { |k| f[ k.to_s ] = f.delete(k) if k.class == :symbol }
  Bar.column_names.except('id','foo_id').each do | ba |
    ba_name = 'bar_' + ba
    f.merge({ba_name => f.bar.send(ba.to_sym)})
  end
  f
end

includes(:bar)延迟加载子记录,在本例中为 bar .这是避免 n+1 个查询的一种方法(这样您就不会为每个 foo 实例运行一个查询)。而且您确实可以访问它。

Foo.where(qux: 'hi').each do |foo|
  puts foo.bar.inspect
end

如果你想得到所有foos他们的bar.qux = hi,那就走另一条路:

Bar.joins(:foo).where(foo: { qux: 'hi' })
Foo.select("foos.id,foos.qux,bar_id,bars.bar_name,bars.something").joins(:bar).where(qux: 'hi')

includes延迟加载关联,因此它基本上不会合并两个表。您正在寻找的内容可以通过joins来完成,它允许您查询两个表并选择所需的所有必需列。您可以在此处找到更多帮助 http://tomdallimore.com/blog/includes-vs-joins-in-rails-when-and-where/

你真的需要AR关系来预先加载所有这些值吗? 延迟加载是故意防止您不必要地殴打数据库......

您仍然可以直接引用柱线的任何属性:

Foo.where(qux: 'hi').includes(:bar).each do |foo|
  puts foo.bar.name   # This will actually load bar from the DB
end

通常没有很好的理由来覆盖这一点,特别是如果数据集可能很大。

最新更新