【问题标题】:Rails Active Record specify where on relational modelRails Active Record 指定关系模型的位置
【发布时间】:2014-12-20 03:05:48
【问题描述】:

如果我有这种关系:

Foo has_many :bars

Bar belongs_to :foo

我想在 Foo 模型中指定一个范围,因为我想在其中过滤一些字段(即 where("code='AV1' OR code='AH5'"

bars 中有 Foo 的外键。如何指定适合上述过滤器的bars?像Bar.foo.customScope 这样的东西,假设我也想过滤Bar 中的东西?

Bar.where(".....").foo.customScope?

编辑

是的,code 是 foo 表中的一个字段

bars 表中有几百个条目。它们每个都有一个指向foos 表(模型Foo)的外键。我想从foos 表中获取具有特定code 的所有bars 的列表。例如

foos:
id, code
1,okay
2,not okay
3,somewhat okay

bars:
id,foo_id,otherstuff
1,1,blah
2,1,blob
3,2,hello
4,3,hurray

如果我的 Foo 模型如下所示:

class Foo < ActiveRecord::Base
   has_many :bars

   def self.goodCodes
     where("code='okay' or code='somewhat okay')
   end

end

我的 Bar 模型如下所示:

class Bar < ActiveRcord::Base
  belongs_to :foo
end

我想调用一些东西来获取所有符合条件的 Bar 项目以及满足 goodCodes 条件的 foos 项目。我认为它会是这样的:Bar.where(....).foo.goodCodes 或者,

Bar.where(...).each do |row|
  if row.foo.goodCodes
    ##do something
  end
end

【问题讨论】:

  • 那么,您是否尝试过简单地在 Foo 类中创建范围?那没用?

标签: ruby-on-rails activerecord


【解决方案1】:

一定有一些混乱。由于 Bar 属于 1 且仅属于 1 个 foo,因此运行 @bar.foo 只会返回 1 个结果:您分配给 @barfoo。范围用于返回多条记录。

如果您有Foo 模型中提到的范围:

class Foo < ActiveRecord::Base
  scope :customScope, -> { where("code='AV1' OR code='AH5'") }
end

那么customScope作用域就是Foo类上的一个类方法:

Foo.customScope # e.g. => [#<Foo code='AV1'], ...]

但如果作用域在Bar 类上:

class Bar < ActiveRecord::Base
  scope :customScope, -> { where("code='AV1' OR code='AH5'") }
end

然后调用Bar.customScope 并返回所有符合该条件的bars。你也可以调用它来获取Foobars的子集:

foo = Foo.new
foo.bars << Bar.new(code: 'AV1')
foo.bars << Bar.new(code: 'XXX')

foo.bars # => [#<Bar code: 'AV1'>, #<Bar code: 'XXX'>]
foo.bars.customScope # => [#<Bar code: 'AV1'>]

为了消除你所说的任何困惑:

我想在 Foo 模型中指定一个范围,因为有几个 我要过滤的字段(即 where("code='AV1' OR 代码='AH5'")

我认为codeFoo 中的一个字段。但后来你说:

如何指定符合上述过滤器的条形?

嗯,你不能。如果code 字段在Foo 表中,则该过滤器只能用于Foo 模型。您不能按不同数据库表中的字段过滤Bars。但是,您可以获取与过滤器或范围匹配的所有 Foos,Foo.customScope,然后获取所有这些 foos bars:

Foo.customScope.flat_map &:bars

此外,没有这样的方法Bar.fooBar 是一个类,只有Bar 的实例才会响应foo

Bar.foo # NoMethodError
bar = Bar.new
bar.foo = Foo.new
bar.foo # the new foo

更新:

这行不通:

row.foo.goodCodes

因为goodCodes 是Foo 上的类方法,而不是row.foo 等实例上的方法。就像我上面说的,你需要这样做:

Foo.customScope.flat_map &:bars

获取所有foos 符合条件的bars。

原因是当你得到Bar的实例比如在:

Bar.where(...).each do |row|
  if row.foo.goodCodes
    ##do something
  end
end

row 现在是 Bar 的一个实例row.foo 将返回fooinstance您不能在实例上调用范围或类方法。这不起作用:row.foo.goodCodes,因为您将goodCodes 定义为 Foo 的类方法。如前所述,您可以调用:

foos_with_good_codes = Foo.goodCodes
bars_with_foos_that_have_good_codes = foos_with_good_codes.flat_map &:bars

希望能稍微澄清一下。

【讨论】:

  • 我编辑了我的问题,这应该使我的要求更加明显。
  • 感谢您澄清这一点。我是 AR 新手,但这很有意义
  • 其实你可以通过'merge'方法实现OP想要的。看看我的回复,迭戈。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多