通过rails中的has_many与模型关联的多个连接记录ID搜索模型

时间:2016-02-04 03:29:12

标签: ruby-on-rails ruby ruby-on-rails-3 postgresql activerecord

我的产品型号设置如下:

class Product < ActiveRecord::Base
  has_many :product_atts, :dependent => :destroy
  has_many :atts, :through => :product_atts
  has_many :variants, :class_name => "Product", :foreign_key => "parent_id", :dependent => :destroy
end

我想搜索与多个属性相关联的产品。

我想也许这会奏效:

Product.joins(:product_atts).where(parent_id: params[:product_id]).where(product_atts: {att_id: [5,7]})

但这似乎没有找到我要找的东西。这适用于ID或ID。

所以我尝试了以下内容:

Product.joins(:product_atts).where(parent_id: 3).where(product_atts: {att_id:  5}).where(product_atts: {att_id:  7})

但这也不起作用,它返回0结果。

所以我的问题是如何通过传入同一模型类型的多个连接模型的属性来寻找模型?

SOLUTION:

 att_ids = params[:att_ids] #This is an array of attribute ids
 product = Product.find(params[:product_id]) #This is the parent product
 scope = att_ids.reduce(product.variants) do |relation, att_id|
   relation.where('EXISTS (SELECT 1 FROM product_atts WHERE product_id=products.id AND att_id=?)', att_id)
 end

 product_variant = scope.first

1 个答案:

答案 0 :(得分:1)

这是一个看似简单的请求,实际上非常棘手SQL的工作原理。联接总是只加入,而你的WHERE子句一次只能查看一行(因此为什么你的期望不能像你期望的那样工作 - - 一行不可能为同一列提供两个值。

在处理原始SQL时,有很多方法可以解决这个问题,但在Rails中,我发现最简单(不是最有效)的方法是使用EXISTS关键字嵌入子查询。将其包含在处理任意数量的所需att_ids的解决方案中,您将获得:

scope = att_ids_to_find.reduce(Product) do |relation, att_id|
  relation.where('EXISTS (SELECT 1 FROM product_atts WHERE parent_id=products.id AND att_id=?)', att_id)
end

products = scope.all

如果您不熟悉reduce,那么它正在进行的是Product,然后为每个where添加一个Product.where(...).where(...).where(...)条款att_id。最终结果类似'use strict'; app.controller('editTaskCtrl', ['$scope', '$http', '$routeParams', function($scope, $http, $routeParams){ var taskid = $routeParams.id; $http.get('https://api.mongolab.com/api/1/databases/dothis/collections/newtask?q={"_id":'+taskid+'}&apiKey=_______-yyNsxk___-____21jxrS___').success(function (data, status, headers, config) { $scope.lists = data; console.log(data); }).error(function (data, status, headers, config) { alert(status); }); }]); ,但您不必过于担心。当与范围和其他连接混合使用时,此解决方案也可以正常工作。