簡體   English   中英

如何在Rails中動態調用attr_accessible?

[英]How do you call attr_accessible dynamically in Rails?

我有一個相當獨特的類,它允許其子類聲明虛擬字段。 子級可以通過調用父類的方法來聲明存儲為XML的虛擬字段,如下所示:

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

我設法通過一個討厭的工作使其工作。 create_xml_field方法將字段名稱存儲在Class變量中(請參見下文)。 after_initialize方法內部調用init_xml_fields方法。

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以便在子類中進行批量分配的經驗? 先感謝您!

為了清楚起見,本文已被編輯!

這是我實現元編程部分的方式,該部分創建訪問器方法並將其設置為attr_accessibles。

我將XML的YAML inadad用作個人研究。 我什至繼續執行不必要的序列化部分,只是為了將您推向YAML。

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)

現在,如果您想知道為什么您的特定代碼無法正常工作,則必須發布更多代碼。


我應該在類的可繼承屬性上進行擴展。 它們有點像類變量,有點像類實例變量。

如果在類中定義可繼承屬性,則其所有子類都將共享它。 但是,如果您在子類中更新了sayd屬性,則該子類將復制原始屬性並對其進行更新,因此更新是專有的,並且不會影響繼承鏈中圍繞該屬性的其他類。

使用普通的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屬性將是:

  • 父母:foo
  • Child1:foo,bar
  • Child2:foo,baz

@kch是正確的,但是我發現了一個使用initialize(* args)的問題 ActiveRecord並不總是使用new()實例化模型對象,因此不一定總是調用initialize()方法。

而是使用after_initialize(* 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM