使用联接过滤 - Rails

时间:2016-02-16 13:53:38

标签: sql ruby-on-rails activerecord

我有两个模型ProductProductProperties。因此,我将产品的属性存储在与另一个模型Properties

关联的“产品属性”模型中

如何实现查找具有属性(A或B或C)AND(X或Y或Z)的产品的范围

我目前拥有的过滤器就是这样 -

    scope :product_type_filter, lambda {|property_id|
      return nil if property_id.blank?
      joins(:product_properties).where('product_properties.property_id IN (?)', property_id).distinct
    }

    scope :metal_filter, lambda {|property_id|
      return nil if property_id.blank?
      joins(:product_properties).where('product_properties.property_id IN (?)', property_id).distinct
    }

并产生以下SQL - SELECT DISTINCT "products".* FROM "products" INNER JOIN "product_properties" ON "product_properties"."product_id" = "products"."id" AND "product_properties"."deleted_at" IS NULL WHERE "products"."deleted_at" IS NULL AND (product_properties.property_id IN ('504')) AND (product_properties.property_id IN ('520'))

但它并没有真正起作用,因为它正在寻找一个同时具有值​​504和520的产品属性,这将永远不会存在。

非常感谢一些帮助!

3 个答案:

答案 0 :(得分:1)

所以这是我使用的连接 -

    def  self.find_with_properties property_ids, group_name
      joins(:product_properties).joins('JOIN product_properties '+group_name+' ON '+group_name+'.product_id = products.id  AND '+group_name+'.property_id IN ('+property_ids.to_s.tr('[', '').tr(']', '').tr('"', '') +')')
    end

答案 1 :(得分:0)

首先,我认为你不应该使用范围来完成这个任务你应该创建一个Class方法来完成它。当涉及复杂逻辑时,不使用范围是最佳实践。

其次,上面提到的代码并没有错。关于把他们称错了。我认为你正在超越范围。

根据定义,上述范围都是相同的,因此您不需要定义两次。试试这个

def  self.find_with_properties property_ids
     joins(:product_properties).where('product_properties.property_id IN (?)', property_ids)
end

并称之为

Product.find_with_properties([1,2,3]).find_with_properties([4,5,6]).uniq

如果'A' , 'B' , 'C'是属性名称,那么您应该这样做:

self.find_by_properties_names(property_names)
  self.joins(:product_properties=>[:property]).where("properties.name   IN(?)",property_names)
end

然后可以像

一样打电话
Product.find_by_properties_names(["A","B","C"]).find_by_properties_names(["C","D","E"])

答案 2 :(得分:0)

试试这个

scope :product_type_filter, ->(f_property_ids, s_property_ids) { joins(:product_properties).where('product_properties.property_id IN (?) AND product_properties.property_id IN (?)', f_property_ids, s_property_ids).distinct }

使用2个参数调用scope

@products = Product.product_type_filter([1,2,3], [4,5,6])