Rails中名为“class”的列的旧表

时间:2010-10-28 14:51:42

标签: ruby-on-rails

我有一个遗留表,我的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

2 个答案:

答案 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_attributewrite_attribute方法与列进行交互,而不是使用ActiveRecord定义的ruby方法。请确保在任何地方都使用该字段的新名称,如下所示:

member.class_name = 'helper'

这适用于ruby 1.8,但我还没有测试过ruby 1.9。我希望这有帮助!

更新:我找到了一个更好的解决方案,适用于Rails 3,即safe_attributes gem。我写了一篇博客文章,解释了如何使用它,带有示例代码片段,以及一个完整的示例应用程序,您可以从github下载并使用它。这是链接:

Legacy Database Column Names in Rails 3

答案 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 仅呈现类属性。