打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Ruby on Rails处理遗留数据库的问题

因为RoR有自己的一套命名机制,而且存在命名空间污染的问题,在处理遗留数据库的时候往往产生问题。比如下面的两例:一个是errors字段,一个是type字段。

>> oo.save
NoMethodError: undefined method `clear' for0:Fixnum
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/validations.rb:1027:in`valid_without_callbacks?'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/callbacks.rb:286:in`valid?'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/validations.rb:1008:in`save_without_dirty'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/dirty.rb:79:in`save_without_transactions'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:179:in`send'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:179:in`with_transaction_returning_status'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/abstract/database_statements.rb:66:in`transaction'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:129:in`transaction'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:138:in`transaction'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:178:in`with_transaction_returning_status'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:146:in`save'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:158:in`rollback_active_record_state!'
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/transactions.rb:146:in`save'

这个错误莫名其妙,它报告说数字0没有方法clear,0的ruby类型为Fixnum。查询google也找不到结果。查看validations.rb发现代码如下:

1026    def valid?
1027      errors.clear

1044    def errors
1045      @errors ||=Errors.new(self)
1046    end

通过再次查看数据库表定义发现了错误的原因。本来是应该执行@errors实例的clear方法,可是因为数据库中有errors字段,变成了执行该属性的clear方法。通过查资料,看源码,都没找到在ror中如何自定义数据库字段的映射。最多只有自定义数据库表名,比如通过set_table_name。经过多次尝试,比如更改has_attribute?的实现
    def has_attribute?(attr_name)
      if attr_name == "errors"
    return false;
      end
     @attributes.has_key?(attr_name.to_s)
    end

或者更改attributes_from_column_definition的实现,

def attributes_from_column_definition
 self.class.columns.inject({}) do|attributes, column|
    attributes[column.name] = column.default unlesscolumn.name == self.class.primary_key or column.name =="errors"
    attributes
  end
end

结果都不行。这样虽然没有了errors属性,可是保存的时候报错ActiveRecord::MissingAttributeError:missing attribute: errors。最后发现,下面的修改可以工作。

class SmsOut <ActiveRecord::Base
      def errors
        super
      end
end

>> oo.errors
=>#<ActiveRecord::Errors:0x47fa644@errors={},@base=#<SmsOut id: 1,recipient: "123456", text:"hello,world", create_date: "2009-03-2714:59:42",originator: "", encoding: "U",status_report: 0, flash_sms: 0,src_port: -1, dst_port: -1,sent_date: nil, ref_no: nil,priority: 0, status: "U",errors: 0, gateway_id:"*">>
>> oo.read_attribute("errors")
=> 0

 

另外一个表出现了另一个错误:

>>SmsIn.find_by_originator("123456")

ActiveRecord::SubclassNotFound:The single-table inheritance mechanism failed to locate thesubclass: 'I'. This error is raised because thecolumn 'type' is reserved for storing the class in case ofinheritance. Please rename this column if you didn't intend it tobe used for storing the inheritance class or overwriteSmsIn.inheritance_column to use another column for thatinformation.
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:1579:in`instantiate'
...
        fromf:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/base.rb:1800:in`method_missing'

  通过查看SmsIn的字段果然发现有个字段名字为"type",ROR默认用这个字段来处理继承。

>> SmsIn.column_names
=> ["id", "process", "originator", "type","encoding", "message_date", "receive_date", "text","original_ref_no", "original_receive_date", "gateway_id"]

因为数据库结构是不能更改的,只能更改ror的定义。

class SmsIn <ActiveRecord::Base
    self.inheritance_column = ""
end

这样可以正常使用SmsIn模型了。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Nimble Method: Guerrilla's Guide to Optimizing Rails Applications
使用 ActiveScaffold 增强 Ruby on Rails 的功能
ActiveScaffold本地化
新手RoR十分钟初体验Step By Step rails Ruby
sahi学习笔记
RubyGems简介
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服