2014-06-23 4 views
1

У меня есть приложение Rails4 со следующими моделями:Получить список полиморфных отношений в Rails 4

1. Systems (has many devices, has many parameters through devices) 
2. Devices (belongs to a system, has many parameters) 
3. Parameters (belongs to a Device) 
4. Events (polymorphic - Systems, Devices and Parameters can have events) 

Когда создается событие, булево поле (по событию) присваивается значение. False указывает на сбой.

У меня есть рамки на моих событий, чтобы показывать только провал событий:

scope :failing, -> { where(okay: false).order('created_at desc') } 

Я могу получить события следующим образом:

System.events.failing 
Device.events.failing 
Parameter.events.failing 

Я пытаюсь вернуть список систем, где либо :

1. the most recent event for the system has failed 
2. the most recent event for any of it's devices has failed 
3. the most recent event for any parameters of it's devices have failed 

Я написал этот (ужасный) SQL-запрос, который при выполнении в консоли возвращает систему мс как массив:

"SELECT * FROM Systems WHERE Systems.id IN (SELECT Devices.system_id FROM Devices WHERE Devices.id IN (SELECT Parameters.device_id FROM Parameters JOIN EVENTS ON Parameters.id=Events.eventable_id WHERE Events.okay ='f')) OR Systems.id IN (SELECT Devices.system_id FROM Devices JOIN Events ON Devices.id=Events.eventable_id WHERE Events.okay='f')") 

мне нужно либо определить область на модели системы или методу класса возвращает список «неудовлетворительные» систем. Вы можете помочь?

ответ

1

Вы можете смешивать соединения и слияние (слить ИНЕК из области видимости):

class System 
    # 1. the most recent event for the system has failed 
    scope :with_failing_events, -> { joins(:events).merge Event.failing } 
    # 2. the most recent event for any of it's devices has failed 
    scope :with_failing_devices, -> { joins(devices: :events).merge Event.failing } 
    # 3. the most recent event for any parameters of it's devices have failed 
    scope :with_failing_parameters, -> { joins(devices: { parameters: :events }).merge Event.failing } 
end 

Обратите внимание, что прохождение хэша joins позволяет кратно присоединиться, или, по крайней мере, кажется, работают в приложении Сейчас я работаю (Rails 4.0.5 postgresql).

Чтобы отфильтровать только последнее событие (предупреждения не работает в Postgres, непроверенное на других адаптерах), вы могли бы добавить к этим запросам:

System.joins(:events).merge(Event.failing).where events: { updated_at: 'MAX("events"."updated_at")' } 

В любом случае, вы можете объединить все эти области действия с OR следующим образом:

class System 
    scope :failing, -> do 
    where(
     [ 
     with_failing_events, 
     with_failing_devices, 
     with_failing_parameters 
     ].map(&:where_clauses).join(' OR ') 
    ) 
    end 
end 
+0

Возможно, вы захотите посмотреть ответ @ jearlu. Это избавит вас от ненужных и неэффективных «соединений». – nicooga

1

Один из вариантов, который немного упростил бы вещи, заключался бы в добавлении внешнего ключа system_id в таблицу событий. Затем вы можете сделать следующее:

Event.where(system_id: [system_id], okay: false).order('created_at DESC') 

ПРИМЕЧАНИЕ: Я бы не определяет никаких отношений для этого нового внешнего ключа, я бы просто использовать его для фильтрации таблицы событий.

Смежные вопросы