Rails:如何动态检索多态模型的多态“_type”列名?

时间:2015-08-19 10:54:25

标签: ruby-on-rails ruby ruby-on-rails-4 polymorphism metaprogramming

我基本上想要创建一个将包含在所有多态模型中的关注点。这个问题需要有一个动态setter方法,它设置'_type'列的值。

module StiPolymorphable
  extend ActiveSupport::Concern

  included do
    define_method "#{magic_method_to_get_type_column}=" do |type_field|
      super(type_field.to_s.classify.constantize.base_class.to_s)
    end
  end
end

我基本上想要访问Parent实例的所有地址而不是Person实例。

示例 - 假设我有以下类

class Person < ActiveRecord::Base
end

class Parent < Person end
class Teacher < Person end

class Address < ActiveRecord::Base
  include StiPolymorphable

  belongs_to :addressable, polymorphic: true
end

现在,如果我尝试访问Parent的地址,它会给我零记录,因为addressable_type字段包含值'Person'。

 Parent.first.addresses => #<ActiveRecord::Associations::CollectionProxy []> 
 Person.first.addresses => #<ActiveRecord::Associations::CollectionProxy [#<Address id: .....>]> 

2 个答案:

答案 0 :(得分:0)

您可能有兴趣查看Modularity gem,以便在您包含模块时传递变量。但是哈文真的没有尝试过。希望它有所帮助。

答案 1 :(得分:0)

我们这样做:

module Shared::PolymorphicAnnotator
  extend ActiveSupport::Concern

  class_methods do
    # @return [String]
    #    the polymorphic _id column
    def annotator_id
      reflections[annotator_reflection].foreign_key.to_s
    end

    # @return [String]
    #    the polymorphic _type column
    def annotator_type
      reflections[annotator_reflection].foreign_type
    end 
  end

  included do
    # Concern implementation macro
    def self.polymorphic_annotates(polymorphic_belongs, foreign_key = nil)
      belongs_to polymorphic_belongs.to_sym, polymorphic: true, foreign_key: (foreign_key.nil? ? (polymorphic_belongs.to_s + '_id').to_s : polymorphic_belongs.to_s)
      alias_attribute :annotated_object, polymorphic_belongs.to_sym 

      define_singleton_method(:annotator_reflection){polymorphic_belongs.to_s} 
    end

    attr_accessor :annotated_global_entity 

    # @return [String]
    #   the global_id of the annotated object
    def annotated_global_entity
      annotated_object.to_global_id if annotated_object.present?
    end

    # @return [True]
    #    set the object when passed a global_id String
    def annotated_global_entity=(entity)
      o = GlobalID::Locator.locate entity

      write_attribute(self.class.annotator_id, o.id)
      write_attribute(self.class.annotator_type, o.class.base_class)
      true
    end
  end
end

在你的模特中:

class Foo
   include Shared::PolymorphicAnnotator
   polymorphic_annotates('belongs_to_name', 'foreign_key')
 end