Ruby on Rails: :include on a polymorphic association with submodels

前端 未结 1 537
萌比男神i
萌比男神i 2020-12-09 12:42

When working with a polymorphic association, is it possible to run an include on submodels that are only present in some types?

Example:

class Contai         


        
相关标签:
1条回答
  • 2020-12-09 12:52

    Edited Answer

    I recently found out that Rails supports eager loading of polymorphic associations when you filter by the polymorphic type column. So there is no need to declare fake associations.

    class Container
      belongs_to :content, :polymorphic => true
    end
    

    Now query the Container by container_type.

    containers_with_food = Container.find_all_by_content_type("Food", 
                               :include => :content)
    
    containers_with_thing = Container.find_all_by_content_type("Thing", 
                               :include => :content)
    

    Old Answer

    This is a hack as there is no direct way to include the polymorphic objects in one query.

    class Container
      belongs_to :contents, :polymorphic => true
      # add dummy associations for all the contents.
      # this association should not be used directly
      belongs_to :food
      belongs_to :thing
    end
    

    Now query the Container by container_type.

    containers_with_food = Container.find_all_by_content_type("Food", 
                               :include => :food)
    
    containers_with_thing = Container.find_all_by_content_type("Thing", 
                               :include => :thing)
    

    That results in two SQL calls to the database ( actually it is 4 calls as rails executes one SQL for every :include)

    There is no way to do this in one SQL as you need different column set for different content types.

    Caveat: The dummy associations on Content class should not be used directly as it will result in unexpected results.

    E.g: Lets say the first object in the contents table contains food.

    Content.first.food # will work
    Content.first.thing
    

    The second call will not work. It might give you a Thing object with the same id as the Food object pointed by Content.

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