代码之家  ›  专栏  ›  技术社区  ›  pchap10k

如何在Rails中动态调用attr_accessible?

  •  1
  • pchap10k  · 技术社区  · 17 年前

    class Child1 < Parent
      create_xml_field ["readings", "usage"]
    end

    我已经设法通过一个恶劣的工作环境使它工作。这个 创建xml字段 init_xml_字段 方法从内部调用 初始化后 方法

    class Parent < ActiveRecord::Base
    
      def self.create_xml_field(fields)
        @@xml_fields[self.name] = fields
      end
    
      def init_xml_fields(xml_fields)
        xml_fields.each do |f|
          f=f.to_sym
          self.class_eval do
            define_method(f) { ... } # define getter
            define_method(f) { ... } # define setter
            attr_accessible(f)       # add to mass assign OK list, does not seem to work!
          end
        end
      end
    
      protected
        def after_initialize
          init_xml_fields
        end
    end

    是否有人有过动态调用attr_acessible以允许在子类中进行大规模分配的经验?提前谢谢你!

    这篇文章是为了清晰而编辑的!

    2 回复  |  直到 17 年前
        1
  •  1
  •   kch    17 年前

    下面是我如何实现元编程部分,该部分创建访问器方法并将它们设置为attr_可访问项。

    require 'yaml'
    require 'rubygems'
    require 'active_support'
    require 'active_record'
    
    module Yamlable
      def self.included m
        m.extend ClassMethods
      end
    
      module ClassMethods
        def add_yaml_fields *args
          write_inheritable_array(:yaml_fields, args)
          attr_accessor(*args)
          attr_accessible(*args)
          before_save :serialize_yaml_fields
        end
      end
    
      def serialize_yaml_fields
        self.yamlable_column = read_inheritable_attribute(:yaml_fields)\
          .inject({}) { |h, a| h[a] = send(a); h }.to_yaml
      end
    
      def initialize(*args)
        super
        YAML::load(yamlable_column).each { |k, v| send("#{k}=", v) }
      end
    end
    
    class ParentModel < ActiveRecord::Base
      include Yamlable
      add_yaml_fields :foo, :bar
    end
    
    class ChildModel < ParentModel
    end
    
    # look, they're there:
    y ChildModel.read_inheritable_attribute(:yaml_fields)
    


    正常的 write_inheritable_attribute write_inheritable_* 将合并/合并到父类的值。


    所以,实际上,我的 add_yaml_fields

    class Parent
      add_yaml_attributes :foo
    
    class Child1 < Parent
      add_yaml_attributes :bar
    
    class Child2 < Parent
      add_yaml_attributes :baz
    

    这样,每个类的yaml属性将是:

    • 家长:傅
        2
  •  0
  •   pchap10k    17 年前

    @kch是正确的,但是我在使用时发现了一个问题 初始化(*args) 新的() 所以 初始化()

    改用 在初始化之后(*args) 如下图所示。

    def self.included m
        m.extend ClassMethods
      end
    
      module ClassMethods
        def add_yaml_fields *args
          write_inheritable_array(:yaml_fields, args)
          attr_accessor(*args)
          attr_accessible(*args)
          before_save :serialize_yaml_fields
        end
      end
    
      def serialize_yaml_fields
        self.yamlable_column = read_inheritable_attribute(:yaml_fields)\
          .inject({}) { |h, a| h[a] = send(a); h }.to_yaml
      end
    
      def after_initialize(*args)
        super
        YAML::load(yamlable_column).each { |k, v| send("#{k}=", v) }
      end
    end
    
    class ParentModel < ActiveRecord::Base
      include Yamlable
      add_yaml_fields :foo, :bar
    end
    
    class ChildModel < ParentModel
    end