论坛首页 编程语言技术论坛

在rails中优雅的进行模型校验

浏览 19499 次
该帖已经被评为精华帖
作者 正文
   发表时间:2009-09-05   最后修改:2009-09-05
liuqiang 写道
见你LS的LS的LS,已经说了

你感兴趣可以试下老王的方法,看看能不能把所有model的出错信息全部调出来。

快客王的做法只对他举的例子中的那种关联实用,对像下面的关联就没办法了:
@user = User.new(params[:user])
@account = @user.build_account(params[:account])
@profile = @user.build_profile(params[:profile])


至于是不是能把错误信息全调出来没有试验。。。

楼主的方法的确不错。但是unless ... else看着很不爽,稍微改了一下:
if [@user, @city, @order].select{|model| model.valid? == false}.empty?
   ...
else
   ...
end  

由于实际中可能需要加验证码,再提供一个带验证码(用的simple capatcha插件)的版本:
if mutiple_model_with_captcha_valid?(:user, @user, @city, @order)
   ...
else
   ...
end
 

#带验证码复合表单提交前验证
  def mutiple_model_with_captcha_valid?(with_captcha_model, *models)
    valid_results = models.map do |model|
      if ActiveSupport::ModelName.new(model.class.name).singular == with_captcha_model.to_s
        model.valid_with_captcha?
      else
        model.valid?
      end
    end
    valid_results.include?(false) ? false : true
  end




0 请登录后投票
   发表时间:2009-09-07  
如果多个模型间是有关联的话,可以设置autosave:
Validation is performed on the parent as usual, but also on all autosave enabled associations. If any of the associations fail validation, its error messages will be applied on the parents errors object and validation of the parent will fail.


详细用法见:
http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html

如果没有直接关联的话,更优雅点的写法:
if [@user, @city, @order].all?(&:valid?)
  [@user, @city, @order].map(&:save)
end
0 请登录后投票
   发表时间:2009-09-07  
rainchen 写道
如果多个模型间是有关联的话,可以设置autosave:
Validation is performed on the parent as usual, but also on all autosave enabled associations. If any of the associations fail validation, its error messages will be applied on the parents errors object and validation of the parent will fail.


详细用法见:
http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html

如果没有直接关联的话,更优雅点的写法:
if [@user, @city, @order].all?(&:valid?)
  [@user, @city, @order].map(&:save)
end

这里用all?方法看似不错,可是却有一些问题,原因如下:
all?和any?方法很懒堕,不能把所有的model都验证一遍。
简单举个例子:

irb(main):007:0> [nil,1,nil].all?{|item| puts item.nil?}
true
=> false


返回结果是没有错,但是没有达到全部验证的目的,同样的any?也一样
所以这个需求用map和select是不错的选择。
0 请登录后投票
   发表时间:2009-09-07  
Hooopo 写道
rainchen 写道
如果多个模型间是有关联的话,可以设置autosave:
Validation is performed on the parent as usual, but also on all autosave enabled associations. If any of the associations fail validation, its error messages will be applied on the parents errors object and validation of the parent will fail.


详细用法见:
http://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html

如果没有直接关联的话,更优雅点的写法:
if [@user, @city, @order].all?(&:valid?)
  [@user, @city, @order].map(&:save)
end

这里用all?方法看似不错,可是却有一些问题,原因如下:
all?和any?方法很懒堕,不能把所有的model都验证一遍。
简单举个例子:

irb(main):007:0> [nil,1,nil].all?{|item| puts item.nil?}
true
=> false


返回结果是没有错,但是没有达到全部验证的目的,同样的any?也一样
所以这个需求用map和select是不错的选择。



all?是遵从短路法则,只要其中一个item是false,后面items的就短路了,既然其中一个都不能通过校验了,其他的也没必要校验了,当然,如果要一次过给出所有错误信息,那就collect 所有errors
0 请登录后投票
   发表时间:2009-09-07  
liuqiang 写道

 

gigix 写道
liuqiang 写道
呵呵,针对20个表单的过滤器,代码肯定不止20行,2者代码都不是很多,没必要斤斤计较啦,综合考虑,您再仔细琢磨琢磨,哪种方法比较爽

8行
class TransactionFilter
  def filter(controller)
    return yield if controller.request.get?
    ActiveRecord::Base.transaction do
      yield
    end
  end
end

你大概还需要2~3行把它声明在application.rb里面
作为比较,我这个项目大概有150~200个action

重点在于:
(1)重复
(2)不必要的思考

 

 好吧,比吧,unless [@user, @city, @order].map(&:valid?).include?(false)  这是个条件表达式,不算一行代码,所以我这个是0行代码 

注意,您还是把您这个方法的调用,也说明下

 

PS:才发现我们的做法可能并不冲突

感觉问题不在性能方面,即使有文件操作也可以把上传图片操作放到下一步来做(实际上很多网站是这样做的)。

而真正的问题是如何让数据库事物保障和页面的错误回显这两个正交需求得到统一。

或许楼主的做法和gigix的结合一下会是一个完美的方案。

0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics