Rails 中的自定义命名属性
Posted
技术标签:
【中文标题】Rails 中的自定义命名属性【英文标题】:Custom Named Attributes in Rails 【发布时间】:2010-11-06 01:09:46 【问题描述】:是否可以在 ActiveRecord 中自定义/覆盖属性的名称,使其与数据库中的列名不匹配?
我的具体案例涉及一个遗留列“修订”,我目前无法删除。列名与acts_as_audited 冲突。当然,在我的迁移完成之前,我需要的遗留代码会出错。
我想要的解决方案是覆盖该列的属性名称,并更新调用它的少数区域。因此允许遗留列与acts_as_audited 一起存在。
【问题讨论】:
【参考方案1】:我没有使用acts_as_audited
,但我假设它的实现覆盖了该列的访问器。在这种情况下,您应该能够执行以下操作:
class ActiveRecord::Base
def self.name_column(column_name, new_name)
define_method(new_name) read_attribute column_name
define_method("#new_name=") |value| write_attribute column_name, value
define_method("#new_name?") attribute_present? column_name
end
end
这些将直接访问column_name
中命名的列,而无需通过覆盖的访问器。
哦,奖励重复破坏元编程答案:
class ActiveRecord::Base
def self.name_column(column_name, new_name)
'' => :read_attribute,
'=' => :write_attribute,
'?' => :attribute_present? .each do |suffix,method|
define_method("#new_name#suffix") |*args| send method, column_name, *args
end
end
end
只是因为我喜欢展示它是如何做到的。
【讨论】:
这给了我一个错误:NoMethodError: undefined method 'define_method' define_method 是私有的,因此您需要在要添加该方法的类的上下文中。 (我将其拆分以使某些区域更可重用) def after_initialize name_column 'revision', 'legacy_revision' end def name_column(column_name, new_name) '' => :read_attribute, '=' => :write_attribute, “?” => :attribute_present? .each 做 |suffix,method| add_method(Document, "#new_name#suffix") |*args|发送方法, column_name, *args end end def add_method(c,m,&b) c.class_eval define_method(m, &b) end 很抱歉。应该是一个类方法,但我把它变成了一个实例方法。现在你应该可以在课堂环境中做这件事了,你会没事的。【参考方案2】:创建迁移以将列从修订重命名为您想要的任何内容。 然后,您可以声明一个 attr_accessor :revision 并使用它,而无需将属性映射到数据库字段。
【讨论】:
attr_accessor 不能与acts_as_audited 一起使用,b/c 它对任何正在审计的模型都有一个属性修订。该覆盖导致我的问题。属性本身需要一个新名称,但我正在尝试在不更改数据库的情况下完成此操作。我把它作为最后的手段。以上是关于Rails 中的自定义命名属性的主要内容,如果未能解决你的问题,请参考以下文章