2015-06-29 2 views
1

У меня есть полиморфные ассоциации, которая выглядит следующим образом:Фильтрация полиморфного объединения по типу для представления

class Event < ActiveRecord::Base 
    belongs_to :eventable, :polymorphic => true 
end 

С кучей типов:

class Nap < ActiveRecord::Base 
    include Eventable 
end 

class Meal < ActiveRecord::Base 
    include Eventable 
end 

module Eventable 
    def self.included(base) 
    base.class_eval do 
     has_one :event, :as => :eventable, :dependent => :destroy 
     accepts_nested_attributes_for :event, :allow_destroy => true 

     scope :happened_at, -> (date) { 
     where("events.happened_at >= ? AND events.happened_at <= ?", 
     date.beginning_of_day, date.end_of_day).order("events.happened_at ASC") 
     } 

     base.extend(ClassMethods) 
    end 
    end 

    module ClassMethods 
    define_method(:today) do 
     self.happened_at(Date.today) 
    end 
    end 
end 

И так далее.

Вот другой конец отношений:

class Person < ActiveRecord::Base 
    has_many :events 

    has_many :meals, { 
    :through => :events, 
    :source => :eventable, 
    :source_type => "Meal" 
    } 
    has_many :naps, { 
    :through => :events, 
    :source => :eventable, 
    :source_type => "Nap" 
    } 
    has_many :moods, { 
    :through => :events, 
    :source => :eventable, 
    :source_type => "Mood" 
    } 
    has_many :notes, { 
    :through => :events, 
    :source => :eventable, 
    :source_type => "Note" 
    } 
    ... 
end 

Я хочу, чтобы захватить все события всех видов, принадлежащих к человеку для отображения на одном экране. Вот что я делаю:

def show 
    @events = Event.by_person(@person).happened_at(date) 

    @meals, @naps, @moods, @notes = [], [], [], [], [] 
    @events.each do |e| 
    @meals << e.eventable if e.eventable_type == 'Meal' 
    @naps << e.eventable if e.eventable_type == 'Nap' 
    @moods << e.eventable if e.eventable_type == 'Mood' 
    @notes << e.eventable if e.eventable_type == 'Note' 
    end 
end 

мне нужно отфильтровать по типу, потому что представление будет отображать атрибуты типа специфичные в каждой секции зрения.

Вопрос: Должна ли эта логика отфильтровывать коллекцию events по типу в свои собственные типы конкретных массивов в контроллере? Или в другом месте? Возможно, модель?

Я не хотел просто пропустить @events к виду и проверить тип теста в самом представлении. Это было неправильно.

+0

Я пытаюсь выяснить, если вы можете делать что-то странное в слое модели. Не могли бы вы добавить соответствующие выдержки из «Eventable» и «Person»? Я не совсем уверен в связях между ними. – lime

+0

Кроме того, вы думаете о еде, дремотах, настроениях и заметках как _events_? Или есть что-то большее для разделения между «Event» и «Eventable»? – lime

+0

Не могли бы вы показать, что написано в Eventable ... –

ответ

1

Вы можете использовать @events запрос, чтобы создать вложенный запрос без перебора (я предполагаю, что у вас есть обратный has_many :events, as: :eventable в каждом из ваших других моделей):

@events = Event.by_person(@person).happened_at(date) 

@meals = Meal.joins(:event).where events: { id: @events } 
@naps = Nap.joins(:event).where events: { id: @events } 

# etc. 
+0

Вау, это гораздо более красноречиво, чем мой код. Не уверен в эффективности 'group_by' против того, что я делал, но сейчас это не проблема. Q: Вы бы определили это в методе 'Event', если он будет использоваться из нескольких контроллеров? –

+0

Кроме того, обратите внимание, что в вашем примере '@ eventables' на самом деле является хешем' Events' --ie, вы не можете получить доступ к определенным свойствам типа, пока не сделаете что-то вроде: '@eventables [" Meal "] [0 ] .eventable.food' –

+0

Вы очень правы, извините, я пришел к этому слишком быстро. Я обновил свой ответ. – smathy

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