新手问题 关于 Rails Validations 的几点疑问。

vivijie · 2013年12月08日 · 最后由 vivijie 回复于 2013年12月08日 · 2550 次阅读

再次吐槽 Ruby China 对 Markdown 的支持: 排版的版本 http://vivijie.github.io/blog/2013/12/08/about-rails-validations/


今天做 Kevin gotealeaf 课后作业,有一个关于 validations 的题目:

** How exactly do Rails validations get triggered? Where are the errors saved? Why we need the ‘render’ to show the validation messages on the user interface? **

下面是我自己的理解,欢迎高手拍砖。

假设我们有一个 Category 类,变量是 name,在 model 文件里设置了 validates。

2.0.0-p247 :019 >   Category
=> Category(id: integer, name: string, created_at: datetime, updated_at: datetime) 

model/category.rb

class Category < ActiveRecord::Base
  validates      :name, presence: true
end 

** 1. How exactly do Rails validations get triggered? **

查了 Rails 的文档,ActiveRecord::Base 中包括有:

  • ActiveRecord::AutosaveAssociation

  • ActiveRecord::Validations.

ActiveRecord::AutosaveAssociation 中有如下描述:

If validations for any of the associations fail, their error messages will be applied to the parent.

所以,如果没有对 name 进行赋值,save 的时候 ActiveRecord::AutosaveAssociation 发现 validations fail 了,产生了 error messages。

** 2. Where are the errors saved? **

2.0.0-p247 :023 >   category.errors
=> #<ActiveModel::Errors:0x007fec3dbda728 @base=#<Category id: nil, name: "zoe", created_at: nil, updated_at: nil>, @messages={}> 

发现 errors 是保存在@messages里面的。

下面看一下 messages 的内容是怎么产生的。

参照文档,自定义了 model 中的 validates。要求 name 首字母以 z 开头的时候,报错。

class Category < ActiveRecord::Base 
  validates_each :name do |record, attr, value|
    record.errors.add attr, 'starts with z.' if value.to_s[0] == 'z'
  end 
end

在 console 中查看:

2.0.0-p247 :013 > category.name = 'zoe'
 => "zoe"
2.0.0-p247 :014 > category.valid?
 => false
2.0.0-p247 :015 > category.errors.messages
 => {:name=>["starts with z."]}
2.0.0-p247 :016 > 

errors messages 修改成功。推断validates :name, presence: true 会生成默认的 messages:name:["can't be blank”]。我们可以自己写 validations 方法。

** 3. Why we need the ‘render’ to show the validation messages on the user interface? **

查了下 rails controller 的生命周期:

When your application receives a request, the routing will determine which controller and action to run, then Rails creates an instance of that controller and runs the method with the same name as the action.

在下一个页面请求的时候,controller 的生命周期结束。@messages@controller的实例变量,会随着@controller的销毁而销毁。所以要用 render 来 hold 住页面,让页面不刷新。

** 不理解的地方: **

  1. If validations for any of the associations fail, their error messages will be applied to the parent.

这里的 parent 指的是 errors 还是@messages呢?

  1. 下面这块代码怎么称呼
<ActiveModel::Errors:0x007fec3dbda728 @base=#<Category id: nil, name: "zoe", created_at: nil, updated_at: nil>, @messages={}> messages={}> 

好像你成功避开了正确的 Markdown 语法?建议重新编排下。

#1 楼 @chunlea 可能是 ruby china 不支持代码块吧。

#2 楼 @vivijie 支持的啊。但是好像不支持缩进的代码格式化,可以使用 GFM 中的代码格式化。或者参考 http://ruby-china.org/topics/13152 (也就是编辑框的右上的图标)

#3 楼 @chunlea 改好了。挺反人类的。一个是需要手动一个一个处理。再一个是内容多的时候,需要翻上去点插入代码按钮。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号