Ransack:如何使用不同的别名多次连接表?

假设我有:具有has_many关联的项:属性,那么我可以搜索具有名称’a_name’的属性和值’a_value’的所有项目,如下所示

q: { properties_name_eq: 'a_name', properties_value_eq: 'a_value' } 

现在,如果我想搜索具有名称为“a_name”且值为“a_value”的属性以及名称为“another_name”且值为“another_value”的属性的所有项目,该怎么办?

以下不起作用,因为它只连接属性表一次

 q: { g: { '0' => { properties_name_eq: 'a_name', properties_value_eq: 'a_value' }, '1' => { properties_name_eq: 'another_name', properties_value_eq: 'another_value'} } } 

生成的SQL看起来像这样

  SELECT DISTINCT "items".* FROM "items" LEFT OUTER JOIN "properties" ON "properties"."item_id" = "items"."id" INNER JOIN ((SELECT "items".* FROM "items")) AS sel_111 on sel_111.id WHERE (("properties"."name" = 'a_name' AND "properties"."value" = 'a_value') AND ("properties"."name" = 'another_name' AND "properties"."value" = 'another_value')) 

编辑:

为了更清楚地了解我的目标,我将在下面粘贴一个规范。

 Item.create name: 'ab', properties_attributes: [{ name: 'a', value: 'a1'}, {name: 'b', value: 'b1'}] Item.create name: 'a', properties_attributes: [{ name: 'a', value: 'a1'}] Item.create name: 'b', properties_attributes: [{name: 'b', value: 'b1'}] Item.create name: 'ax', properties_attributes: [{ name: 'a', value: 'a1'}, {name: 'b', value: 'x'}] Item.create name: 'bx', properties_attributes: [{ name: 'a', value: 'x'}, {name: 'b', value: 'b1'}] Item.create name: 'other', properties_attributes: [{ name: 'other', value: '123'}] get :index, q: { properties_name_eq: 'a', properties_value_eq: 'a1' } names = JSON.parse(response.body).map{|u| u['name']} expect(names).to match_array ['ab', 'a', 'ax'] # OK! get :index, q: { m: 'or', g: { '0' => { properties_name_eq: 'a', properties_value_eq: 'a1' }, '1' => { properties_name_eq: 'b', properties_value_eq: 'b1'} } } names = JSON.parse(response.body).map{|u| u['name']} expect(names).to match_array ['ab'] #FAILS! 

只需使用Model.search(params[:q].try(:merge, m: 'or')) ,使用您的示例:

 q: { m: 'or', g: { '0' => { properties_name_eq: 'a_name', properties_value_eq: 'a_value' }, '1' => { properties_name_eq: 'another_name', properties_value_eq: 'another_value'} } } 

您可以在此处找到更多信息

您需要查询的where or where级别,因为properties.name不能同时等于’a_name’和’another_name’。 不需要表的第二个别名。

您可以使用多个查询来解决此问题。

  1. 对于每个名称+值属性,使用此属性获取所有项目ID
  2. 将每个属性的结果ID与item_ids
  3. 在关于:items的最终查询中,添加子句WHERE id IN (item_ids)

这是执行步骤1和步骤2的代码示例:

 def property_item_ids(conditions) conditions.inject([]) do |result, (key, condition)| result.method(result.empty? ? '+' : '&').(Property.ransack(m: "and", g: condition).pluck(:item_id).to_a) end end 

获取包含所有属性的项ID:

 conditions = { '0' => { properties_name_eq: 'a', properties_value_eq: 'a1' }, '1' => { properties_name_eq: 'b', properties_value_eq: 'b1'} } item_ids = property_item_ids(conditions) 

对于第3步,使用item_ids调用item_ids

 q: { m: 'and', g: { '0' => { item_id_in: item_ids } } }