按类型过滤视图的多态关联

时间:2015-06-29 18:07:07

标签: ruby-on-rails polymorphic-associations

我有一个多态关联,如下所示:

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传递给视图,并在视图中进行类型测试。这似乎不对。

1 个答案:

答案 0 :(得分: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.