【问题标题】:Filtering a relation in Rails在 Rails 中过滤关系
【发布时间】:2013-01-20 23:11:55
【问题描述】:

我的Product 模型中有这种关系:

has_many :features, :class_name => 'ProductFeature', :source => :product_feature, :include => :feature

所以我可以Product.features

效果很好。但我希望能够在必要时按feature 表中的字段过滤它。以伪代码为例:

find all product features where feature is comparable

comparefeature 上的布尔字段。

我已经尝试了 2 个小时,但无法弄清楚(没有完全编写新查询)。我不知道如何从Product.features 关系中访问feature 表的字段,因为它似乎只能过滤product_features 字段。

这是我目前想出的:

def features_compare
  features.feature.where(:compare => true)
end

但它只是说feature 不是一个有效的方法,我理解。

编辑

我更新了我的模型,使关系更加清晰:

product.rb:

class Product < ActiveRecord::Base
  belongs_to :company
  belongs_to :insurance_type

  has_many :product_features
  has_many :reviews

  attr_accessible :description, :name, :company
end

product_feature.rb:

class ProductFeature < ActiveRecord::Base
  belongs_to :product
  belongs_to :feature

  delegate :name, :to => :feature

  attr_accessible :value
end

feature.rb

class Feature < ActiveRecord::Base
  attr_accessible :name, :compare
end

我希望能够查询属于productfeatureproduct_features,其中Feature.comparetrue。像这样的:

产品.rb

def features_compare
  product_features.where(:compare => true)
end

这会引发错误,因为 compareFeature 模型中,而不是 ProductFeature。我在 product_feature.rb 中尝试了以下内容:

delegate :compare, :to => :feature

但我没有帮助。

我将在几个小时内为此添加赏金,所以请帮助我!

【问题讨论】:

  • 我对应用程序的组织感到困惑。所以你有一个 features 表和一个 product_features 表,一个 Feature 模型和一个 ProductFeature 模型?
  • 另外,你不需要 :source 属性,因为 has_many :features 不是 has_many :through 关联。
  • 我开始怀疑你是否也需要 :include =&gt; :feature 部分,除非 ProductFeature 有一个功能。
  • 我知道你会怎么样!我有一个特征模型,其中包含一组特征,例如“颜色”、“尺寸”、“形状”等。然后是一个 ProductFeature 模型,其中包含指向产品和特征的链接,并包含一个“值”,例如“ black', 'medium', 'round' 等。我在 Product 模型上将关系重命名为 'features' 而不是 'product_features' 以提高可读性(或者我希望如此大声笑)
  • 我需要包含,所以我可以通过关系访问功能名称

标签: ruby-on-rails ruby ruby-on-rails-3 arel


【解决方案1】:

find all product features where feature is comparable 只是

ProductFeature.joins(:feature).where(:feature => {:compare => true})

你可以通过引入一个作用域使其更易于重用:

#in product_feature.rb
scope :with_feature_like, lambda do |filter|
   joins(:feature).where(:feature => filter)
end

#elsewhere
ProductFeature.with_feature_like(:compare => true)

#all the product features of a certain product with at comparable features
some_product.product_features.with_feature_like(:compare => true)

最后,如果您希望所有产品的产品功能具有类似功能,您需要类似:

Product.joins(:product_features => :feature).where(:feature => {:compare => true})

当然你也可以在Product上变成一个范围。

【讨论】:

  • 那有没有办法直接对Product的product_features关系做过滤呢? IE product_features.where(:features => {:compare => true}) ?
  • 当然可以,但您需要先加入。所以some_product.product_features.joins(:features).where(:features =&gt; {:compare =&gt; true})。这就是我在答案中的some_product 示例所做的一切,除了它隐藏了范围内的详细信息。
  • 好的,如果我将 ProductFeature 设置为包括 :feature ,我还需要加入吗?
  • (顺便说一句,我刚刚编辑了我的答案以使用:feature 而不是:features。我忘记了每个产品功能只有一个功能。)当你说“包含”时,你的意思是与代表?是的,所有代表所做的就是将对product_feature.compare 的调用转换为product_feature.feature.compare。完全不影响查询。
  • 考虑所有这些的一种方法是注意如果delegate 确实 影响查询,它必须通过偷偷写一个连接来做到这一点,因为相关数据位于不同的表中。它可以做但不能做的另一件事是将字段复制/更新到product_features 表中的额外列。实际上,您可以通过一些工作(或宝石)自己实现这种非规范化,并且有些情况需要这样做。但除非你有一个紧迫的理由这样做,否则我会坚持做你自己的加入。这当然是最简单的解决方案。
【解决方案2】:

这似乎是一个 has_many :through 关系。尝试改变这个:

has_many :features, :class_name => 'ProductFeature', :source => :product_feature, :include => :feature

到这里:

has_many :product_features
has_many :features, :through => :product_features

只要你的 ProductFeature 模型有这个:

belongs_to :product
belongs_to :feature

并且您在 product_features (product_id, feature_id) 上有相应的列,那么您应该能够访问该产品的功能以及 Product 和 ProductFeature 上的所有属性。

看这里:

http://guides.rubyonrails.org/association_basics.html#the-has_many-through-association

编辑:这是按特征字段过滤的方法。

Product.joins(:features).where(:features => {:name => "Size"})

【讨论】:

  • 嗯。但这只会说:未知列'product_features.compare'
  • 你试过了吗,@MattHumphrey,还是只是猜测?
  • 如果您已经为 product_features 编写了添加比较字段并运行它的迁移,则不应该这样说。
  • 不,我试过了,我知道为什么。关系, features,实际上是 product_feature 关系。
  • 我已经用模型上下文 @JoshuaRieken 更新了问题
【解决方案3】:

@product.each |p| { p.features.where(:comparable =&gt; true) } 可能是你最好的选择,但我愿意接受启发。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-15
    • 2015-04-30
    • 2015-05-17
    • 2020-03-03
    相关资源
    最近更新 更多