2016-03-06 57 views
0

我有一个使用has_many:through关联的标签的产品模型。我想根据选定的标签在展示页面上显示类似的产品(为每个产品选择标签)。Rails使用标签显示类似的产品

class Product < ActiveRecord::Base  
    has_many :product_tags 
    has_many :tags, through: :product_tags 
end 

比方说,我有3个产品,2个标签 - “狗”和“猫”(狗食品和猫的食物)。

产品1和2的标签设置为'狗'。产品3的标签设置为'猫'。

因此,产品1展示页面上的所需输出是产品2显示在“您可能还会感兴趣的项目”部分。产品3不应显示在那里。

在我的控制器中正确的方法是什么?

我的想法是,现在使用& - 运营商,即

(@product_1.product_tags & @product_2.product_tags).empty? 

,如果不为空,显示产品。但是,我如何在我的控制器中完成这个查询?

这是我尝试

def show 
    @product = Product.find(params[:id]) 
    @similar_products = Product.where(!(tags & @product.tags).empty?) 
    end 

但它显然不工作。如何访问查询中的关联模型?我发现this解决为好,但它不是为我工作:

Product.joins(:tags).where((:tags & @pr1.tags).empty?).all 
NoMethodError: undefined method `&' for :tags:Symbol 

回答

1

的问题与你的ActiveRecord的关系是你想的where子句中使用Ruby代码。它可以处理一个简单的哈希或一个SQL字符串,但没有像你所做的那么复杂。

但是,出于上述目的,我不想认为您需要为此查询;你可以用Ruby数组来完成。

如果Tag模型具有反比关系:

Class Tag 
    has_many :product_tags 
    has_many :products, through: :product_tags 
end 

...那么你应该能够用这种(让你的产品的标签的产品在map它开始使用Ruby的阵列,而不是一个ActiveRecord关系):

@similar_products = @product.tags.map(&:products).flatten.uniq - [@product] 

然后你只需要在显示他们的观点来遍历@similar_products


如果需要一个查询(例如,如果你的数据最终采取了大量的时间和内存来处理),你会想:

@similar_products = Product.joins(:tags).where('tags.id' => @product.tag_ids).where.not('products.id' => @product.id) 

(免责声明虽然:我还没有测试过。)


NB。如果您ProductTag模式上有没有其他逻辑,你可以用product_tag.rb分配完全,表重命名为products_tags(包括部分的多数和按字母顺序排列),并使用这些来代替:

class Product 
    has_and_belongs_to_many :tags 
end 
class Tag 
    has_and_belongs_to_many :products 
end 
+0

我想你”已经编辑并添加了这个部分:'where.not('products.id'=> @ product.id)'这实际上是超级有用的,我没有想到它:)我最终与查询一起去了,似乎对我来说更“正确”。 – mohnstrudel