Rails: has_many through with polymorphic association - will this work?

后端 未结 2 786
广开言路
广开言路 2020-12-23 01:53

A Person can have many Events and each Event can have one polymorphic Eventable record. How do I specify the relationshi

相关标签:
2条回答
  • 2020-12-23 02:39

    You have to do:

    class Person < ActiveRecord::Base
      has_many :events
      has_many :meals, :through => :events, :source => :eventable,
        :source_type => "Meal"
      has_many :workouts, :through => :events, :source => :eventable,
        :source_type => "Workout"
    end
    

    This will enable you to do this:

    p = Person.find(1)
    
    # get a person's meals
    p.meals.each do |m|
      puts m
    end
    
    # get a person's workouts
    p.workouts.each do |w|
      puts w
    end
    
    # get all types of events for the person
    p.events.each do |e|
      puts e.eventable
    end
    
    0 讨论(0)
  • 2020-12-23 02:40

    Another option of this is to use a Single Table Inheritance (STI) or Multi Table Inheritance (MTI) pattern, but that requires some ActiveRecord/DB Table rework, but this may help others still finding this who are designing it for the first time.

    Here is the STI method in Rails 3+: Your Eventable concept becomes a class and needs a type column (which rails automatically populates for you).

    class Eventable < ActiveRecord::Base
      has_one :event
    end
    

    Then, your other two classes inherit from Eventable instead of AR::Base

    class Meal < Eventable
    end
    
    class Workout < Eventable
    end
    

    And your event object is basically the same, just not polymorphic:

    class Event < ActiveRecord::Base
      belongs_to :person
      belongs_to :eventable
    end
    

    This may make some of your other layers more confusing, if you've never seen this before and you're not careful. For example, a single Meal object can be accessed at /meals/1 and /eventable/1 if you make both endpoints available in the routes, and you need to be aware of the class you're using when you pull an inherited object (hint: the becomes method may be very useful if you need to override the default rails behavior)

    But this is a much cleaner deliniation of responsibilities as apps scale, in my experience. Just a pattern to consider.

    0 讨论(0)
提交回复
热议问题