ActiveRecord where语句从嵌套对象中选择字段

xxj*_*jnn 1 ruby activerecord ruby-on-rails

特定

class Foo
  has_many :bar
end

class Bar
  belongs_to :foo
end
Run Code Online (Sandbox Code Playgroud)

我想要:

=> #<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' >]>
Run Code Online (Sandbox Code Playgroud)

我可以做这个:

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

但它不会加载子记录.似乎只是在需要的时候坚持下去.

必须有比这更优雅的东西吗?

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

Moh*_*mad 5

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

Foo.where(qux: 'hi').each do |foo|
  puts foo.bar.inspect
end
Run Code Online (Sandbox Code Playgroud)

如果你想得到他们所有的foos地方bar.qux = hi,那么去其他地方:

Bar.joins(:foo).where(foo: { qux: 'hi' })
Run Code Online (Sandbox Code Playgroud)