Rails Polymorphic has_many

前端 未结 5 1513
眼角桃花
眼角桃花 2020-12-31 07:44

Using Ruby on Rails, how can I achieve a polymorphic has_many relationship where the owner is always of a known but the items in the association will be of some

相关标签:
5条回答
  • 2020-12-31 08:12

    You have to use STI on the producers, not on the products. This way you have different behavior for each type of producer, but in a single producers table.

    (almost) No polymorphism at all!

    class Product < ActiveRecord::Base
      # does not have a 'type' column, so there is no STI here,
      # it is like an abstract superclass.
      belongs_to :producer
    end
    
    class Bicycle < Product
    end
    
    class Popsicle < Product
    end
    
    class Producer < ActiveRecord::Base
      # it has a 'type' column so we have STI here!!
    end
    
    class BicycleProducer < Producer
      has_many :products, :class_name => "Bicycle", :inverse_of => :producer
    end
    
    class PopsicleProducer < Producer
      has_many :products, :class_name => "Popsicle", :inverse_of => :producer
    end
    
    0 讨论(0)
  • 2020-12-31 08:19
    class Note < ActiveRecord::Base
    
     belongs_to :note_obj, :polymorphic => true
     belongs_to :user
    
    
    end
    
    
    class Contact < ActiveRecord::Base
    
     belongs_to :contact_obj, :polymorphic => true
     belongs_to :phone_type 
    
    end
    
    
    
    class CarrierHq < ActiveRecord::Base
    
    
     has_many :contacts, :as => :contact_obj
     has_many :notes, :as => :note_obj
    
    
    end
    
    0 讨论(0)
  • 2020-12-31 08:31

    I find that polymorphic associations is under documented in Rails. There is a single table inheritance schema, which is what gets the most documentation, but if you are not using single table inheritance, then there is some missing information.

    The belongs_to association can be enabled using the :polymorphic => true option. However, unless you are using single table inheritance, the has_many association does not work, because it would need to know the set of tables that could have a foreign key.

    (From what I found), I think the clean solution is to have a table and model for the base class, and have the foreign key in the base table.

    create_table "products", :force => true do |table|
        table.integer  "derived_product_id"
        table.string   "derived_product_type"
        table.integer  "producer_id"
      end
    
      class Product < ActiveRecord::Base
        belongs_to :producer
      end
    
      class Producer < ActiveRecord::Base
        has_many :products
      end
    

    Then, for a Production object, producer, you should get the products with producer.products.derived_products.

    I have not yet played with has_many through to condense the association to producer.derived_products, so I cannot comment on getting that to work.

    0 讨论(0)
  • 2020-12-31 08:33

    Here is the workaround I'm currently using. It doesn't provide any of the convenience methods (collection operations) that you get from real ActiveRecord::Associations, but it does provide a way to get the list of products for a given producer:

    class Bicycle < ActiveRecord::Base
      belongs_to :producer
    end
    
    class Popsicle < ActiveRecord::Base
      belongs_to :producer
    end
    
    class Producer < ActiveRecord::Base
      PRODUCT_TYPE_MAPPING = {
        'bicycle' => Bicycle,
        'popsicle' => Popsicle
      }.freeze
      def products
        klass = PRODUCT_TYPE_MAPPING[self.type]
        klass ? klass.find_all_by_producer_id(self.id) : []
      end
    end
    

    Another downside is that I must maintain the mapping of type strings to type classes but that could be automated. However, this solution will suffice for my purposes.

    0 讨论(0)
  • 2020-12-31 08:34

    please take it on format

    class Bicycle < ActiveRecord::Base 
      belongs_to :bicycle_obj,:polymorphic => true 
    end 
    
    class Popsicle < ActiveRecord::Base
      belongs_to :popsicle_obj , :polymorphic => true 
    end 
    
    class Producer < ActiveRecord::Base 
      has_many :bicycles , :as=>:bicycle_obj 
      has_many :popsicle , :as=>:popsicle_obj 
    end 
    

    Use this code. If you have any problem with it, please leave a comment.

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