因为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模型了。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。