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 中的自定义命名属性的主要内容,如果未能解决你的问题,请参考以下文章

Powershell 中的自定义 XAML 命名空间

Rails 中的自定义错误页面?

Rails 中的自定义字段作为未来条目的模板

要映射到 rails 4 中的自定义路径的资源路由

Rails 中字段的自定义序列化

使用 Piwik + Ruby on Rails 跟踪目标转换中的自定义变量