我有一个遗留表,我的rails应用程序与另一个应用程序共享。它有一个名为“class”的列。我第一次引用该模型中的任何属性时,出现错误。对属性的后续引用有效。有没有一个很好的解决方法,或者我应该修改使用此表的其他应用程序(呃)?
>> Member::Ssg.find(:first)
=> #<Member::Ssg ssg_key: #<BigDecimal:10b169688,'0.253E3',4(8)>, org_id: 2, academic_year: 2006, class: true, next_due_date: "2011-06-01", submitted_date: "2006-02-13", notes: nil, owner_id: "1">
>> Member::Ssg.find(:first).notes
NoMethodError: undefined method `generated_methods' for true:TrueClass
from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.8/lib/active_record/attribute_methods.rb:247:in `method_missing'
from (irb):2
>> Member::Ssg.find(:first).notes
=> nil
解: 我使用Bellmyer解决方案并将下面的代码添加到我的模型
class << self
def instance_method_already_implemented?(method_name)
return true if method_name == 'class'
super
end
end
答案 0 :(得分:9)
注意:请参阅本答案末尾的更新解决方案。出于历史原因离开原来过时的解决方案。
这经常出现(遗留列名称干扰ruby / rails),我可能只是从中创建一个插件。不过,这是你可以立即修复它的方法。在您的应用中创建此文件:
# lib/bellmyer/create_alias.rb
module Bellmyer
module CreateAlias
def self.included(base)
base.extend CreateAliasMethods
end
module CreateAliasMethods
def create_alias old_name, new_name
define_method new_name.to_s do
self.read_attribute old_name.to_s
end
define_method new_name.to_s + "=" do |value|
self.write_attribute old_name.to_s, value
end
end
end
end
end
现在,在您的模型中:
class Member < ActiveRecord::Base
include Bellmyer::CreateAlias
create_alias 'class', 'class_name'
end
create_alias的第一个参数是旧方法名称,第二个参数是您要调用它的新名称,它不会干扰rails。它基本上使用read_attribute
和write_attribute
方法与列进行交互,而不是使用ActiveRecord定义的ruby方法。请确保在任何地方都使用该字段的新名称,如下所示:
member.class_name = 'helper'
这适用于ruby 1.8,但我还没有测试过ruby 1.9。我希望这有帮助!
更新:我找到了一个更好的解决方案,适用于Rails 3,即safe_attributes gem。我写了一篇博客文章,解释了如何使用它,带有示例代码片段,以及一个完整的示例应用程序,您可以从github下载并使用它。这是链接:
答案 1 :(得分:0)
以下适用于 Rails 6.0.2.2
class ReasonCode < ApplicationRecord
class << self
def instance_method_already_implemented?(method_name)
return true if method_name == 'class'
super
end
end
def as_json(options={})
add_class = attributes.keys.include?('class')
if add_class
if options[:only]
add_class = Array(options[:only]).map(&:to_s).include?('class')
elsif Array(options[:except])
add_class = Array(options[:except]).map(&:to_s).exclude?('class')
end
end
options[:except] = Array(options[:except])
options[:except].push('class')
json = super(options)
json['class'] = attributes['class'] if add_class
json
end
end
改编自此答案 https://www.ruby-forum.com/t/activerecord-column-with-reserved-name-class/125705/2。添加 as_json 方法是因为将记录呈现为 json 会导致 SystemStackError(堆栈级别太深)。如果在 as_json 选项中指定,我按照 serialization code in the Rails repo 仅呈现类属性。