[英]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屬性將是:
@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.