Rails migration 和model 的validations检查冲突时

今天,干活的时候,遇到这样的一个问题,我们的一个系统有很多版本,有些客户由于种种原因始终使用的是比较早期的版本,姑且说2.03版本吧。

有这样一个migration


class AddFreqAnalyzers < ActiveRecord::Migration
#055_add_freq_analyzers.rb
def self.up
add_column :analyzers, :start_freq, :int
add_column :analyzers, :stop_freq, :int
startFreq=ConfigParam.get_value(ConfigParam::StartFreq);
stopFreq=ConfigParam.get_value(ConfigParam::StopFreq);
puts startFreq
puts stopFreq
Analyzer.find(:all).each { |a|
a.start_freq=startFreq;
a.stop_freq = stopFreq;
a.save
}
1;
end

def self.down
remove_column :analyzers, :start_freq
remove_column :analyzers, :stop_freq
end
end

主要的作用是添加了两个字段和给这个字段赋值。

然后,我们2.06版本的时候给一个model加了一个字段,很正常的我们给这个字段加了validation的保存检查。然后,我们测试升级

class AddWebApiUrl < ActiveRecord::Migration
#085_add_web_api_url.rb
def self.up
add_column :analyzers, :api_url, :string, :null => true
end

def self.down
remove_column :analyzers, :api_url
end
end

并且在model中增加检查如下:
  validates_format_of     :api_url,
:with =>/(^(rubyscript:|http:\/\/|https:\/\/)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)|^about:blank$|^$/ix


然后,一直没有什么问题,包括正常的升级。然而,在一个用户那里他们的系统是2.02的那么系统升级的话,就会把migration从040一直运行。结果报了错,如下:

[quote]== 55 AddFreqAnalyzers: migrating =============================================
-- add_column(:analyzers, :start_freq, :int)
-> 0.0136s
-- add_column(:analyzers, :stop_freq, :int)
-> 0.0033s
2000000.0
52000000.0
rake aborted!
undefined method `api_url' for #<Analyzer:0x2aaaae4533b8>[/quote]


错误提示是没有定义api_url方法,实际上055版本的migrate根本没有api_url的字段,只有到085才有,可是代码里已经有了validation的检查,所以,升级过程就出错了。这样的错误还真奇怪了一阵子,最后,怎么解决的呢:

  validates_format_of     :api_url,
:with =>/(^(rubyscript:|http:\/\/|https:\/\/)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$)|^about:blank$|^$/ix,
:if => Proc.new { |record| record.respond_to? :api_url}


这就和
  validates_format_of     :email,
:with => /(\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z|^$)/i,
:if => Proc.new { |analyzer|analyzer.email.length >0 }

一样表示只有特定条件才进行检查。


下面是同样的例子:

class CreateVendors < ActiveRecord::Migration
def self.up
create_table :vendors do |t|
t.string :name
t.string :email
end a = Vendor.new(:name => “Fred Flinstone”, :email => “fred@example.com”)
a.save!
b = Vendor.new(:name => “Barney Ruble”, :email => “barney@example.com”)
b.save
end
def self.down
drop_table :vendors
end
end



model:

validates_presence_of :rating, :on => :create, :message => "can't be blank"



出错提示:

[quote]$ rake db:migrate
(in .... )
== 2 CreateVendors: migrating =======================================
rake aborted!
Validation failed: Rating can't be blank(See full trace by running task with --trace)[/quote]

解决如下:


  validates_presence_of :rating, :on => :create, :message => "can't be blank",
:if => Proc.new { |record| record.respond_to? :rating }


原文作者的解释关于respond_to?
[quote]responds_to asks the Rails model: “Do you have a method named ‘rating’?”. Because Rails magically creates methods for every column an entity has in the database, Rails will either have that method (because it has been defined in the database), or not (because no such column exists). So we only run the validation if we have the column, avoiding the mess with trying to validate data that doesn’t make sense (yet). [/quote]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值