Rails mass assignment 赋值顺序

iwinux · 2012年08月09日 · 最后由 iwinux 回复于 2012年08月09日 · 3682 次阅读

如果我有一个 form:

= form_for @user do
  = text_field :email
  = text_field :name

那么在 controller 里执行 @user = User.new(params[:user])@user.update_attributes(params[:user]) 的时候,是不是可以保证 email 的赋值顺序先于 name 呢?

没有在官方文档找到有关的说明,仅有的线索:ActiveRecord::AttributeAssignment::ClassMethods#assign_attributes 方法在处理传入的 Hash 时保留了 key 的顺序。

try this:

attrs = [:email,:name].inject({}){ |_,i| _.merge({i=>params[:user][i]}) }
@user.update_attributes(attrs)
User.new(Hash[params[:user].sort])

email 比 name 小,each 的时候,会在前面

为什么会要求更新顺序啊?

#3 楼 @huobazi 我覆盖了某些字段的赋值方法,而这些方法需要读取其他字段的值做一些操作

表单传出来的参数一般来说是按顺序的,但如果表单提交前被 javascript 处理过 (例如 ajax form),表单参数会先存到在 js 对象中,最后拼出来的顺序是由 hash 算法决定,也就是和浏览器实现相关 ...

rack 解析请求,将参数填到 params 里面的顺序也是由 rack 的实现决定的... 某些 middleware 甚至会更改参数顺序。最后才看 active record 的实现...

所以这顺序就算你试验出一个来也不可靠 ... 可能 lz 是想重写 user.email= 方法,实现 "如果没有 name 就从 email 猜一个" 的效果?在 before_validation 里搞吧。你还可以利用 rails 提供的 user.name_changed?user.email_changed?

#5 楼 @luikore 谢谢解答~看来我想得太天真了……(还好突然想起这个问题)

email 和 name 这只是举个例子,实际情况比这个要复杂得多,照这么看的话,还是趁早移到 before_validation 里处理比较稳妥。

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