2016-12-13 2 views
0

У меня есть проекты со многими материалами, и я пытаюсь сделать цепочку из области, чтобы фильтровать их:ActiveRecord has_many через прикован фильтр

project1, связанный с бумаги. project2, связанный с пластиком

, если пользователь нажмет на бумаги Я хочу, чтобы project1 и project2 отображается. Если после этого первого запроса пользователь нажмет на пластик Я хочу отфильтровать первый результат запроса с новым ограничением.

Другими словами, если я выбираю бумаги и пластмассовую Я только хочу, чтобы иметь PROJECT2 отображается.

Мои модели:

модель проекта

class Project < ApplicationRecord 
    has_many :project_materials 
    has_many :materials, through: :project_materials 

    scope :with_materials, -> (materials) { includes(:materials).where(materials: {id: materials}) } 
end 

Материал Модель:

class Material < ApplicationRecord 
    has_many :project_materials 
    has_many :projects, through: :project_materials 
end 

project_material Модель:

class ProjectMaterial < ApplicationRecord 
    belongs_to :project 
    belongs_to :material 
end 

Я попытался следующие в консоли рельсы:

p1 = Project.first 
p2 = Project.last 
m1 = Material.first 
m2 = Material.last 

p1.materials << m1 

p2.materials << m1 
p2.materials << m2 

f1 = Project.with_materials(m1) 
# which return p1 and p2 

f2 = f1.with_materials(m2) 
# which return nothings because of the following query 

'SQL (1.0ms) SELECT "projects"."id" AS t0_r0, "projects"."name" AS t0_r1, "projects"."difficulty" AS t0_r2, "projects"."status" AS t0_r3, "projects"."duration" AS t0_r4, "projects"."uuid" AS t0_r5, "projects"."slug" AS t0_r6, "projects"."created_at" AS t0_r7, "projects"."updated_at" AS t0_r8, "projects"."project_type_id" AS t0_r9, "materials"."id" AS t1_r0, "materials"."name" AS t1_r1, "materials"."created_at" AS t1_r2, "materials"."updated_at" AS t1_r3 FROM "projects" LEFT OUTER JOIN "project_materials" ON "project_materials"."project_id" = "projects"."id" LEFT OUTER JOIN "materials" ON "materials"."id" = "project_materials"."material_id" WHERE "materials"."id" = 5' 

заблаговременно.

+0

Вы не можете решить эту проблему исключительно на уровне модели. Вам нужно будет передать ограничение, используемое при первом запросе второго запроса, с помощью параметров или сеанса. – max

+0

hi проблема в том, что если я передаю оба ограничения в массиве, мои результаты - p1 и p2, потому что запрос будет использовать IN. – Mittcho

ответ

0

У меня есть решение, возможно, не самое элегантное, но, по крайней мере, оно работает.

def self.with_materials materials 
    materials = [materials].flatten.compact 

    sql = "SELECT project_id, count(material_id) FROM project_materials WHERE material_id IN (?) GROUP BY project_id HAVING count(material_id) > ?" 
    ids = ProjectMaterial.find_by_sql [sql, (materials), (materials.count - 1)] 
    ids.collect!{ |i| i.project_id } 

    where(id: ids) 
end 
Смежные вопросы