Rails 使用 Setter 方法代替 Before Validation

zlx_star · 2016年01月29日 · 最后由 hooopo 回复于 2016年01月30日 · 2454 次阅读

今天看到这篇文章:http://blog.arkency.com/2016/01/drop-this-before-validation-and-use-method/

文中作者建议使用 setter 方法

class Something
  def title=(val)
    @title = val.strip
  end
end

来代替以下这种 validation:

class Something
  before_validation :strip_title

  def strip_title
    self.title = title.strip
  end
end

对此我有疑惑,希望大家能分析一下这两种做法的优劣。

我感觉这是在给自己埋炸弹...

it explodes when val is nil.

有这需求的话用 callback 一样能做到

It’s less magic

这不叫 magic,叫 convention . 人家好不容易给你抽象出来你又打回去。一个 Rails 程序员看到 title 空白被 strip 了,你猜猜他会去找 callback 还是去找一个 damn setter?

It works in more cases.

But why? 这点跟第一点根本就是矛盾的

总之我看不出一点好处来,也许作者的 case 比较特别吧,但我觉得如果不是确实必要就别耍猴子这应该很明显...尤其是框架已经给出解决方案的时候。

2 楼 已删除
class Something
  def title=(val)
    write_attribute :title, val.strip
  end
end

Rails 5 中有了另一种写法:attribute :title, StripString.new.

setter 要比 callback 清晰不少。

#1 楼 @blacktulip 我也倾向于不要去覆盖 setter 方法,而且有些 Gem 会覆盖这些方法

#3 楼 @42thcoder Rails 5 中的写法应该是这类 validation 的最佳替代方案了

所以为什么是strip_title 而不是strip

快速开发还是 before_validation 更好一些,不用去修改原始的代码段,越少的源代码修改意味着越少的 bug。

万一有地方 something[:title] = 这样赋值呢

#8 楼 @huacnlee 这样就爆炸了,不过这种写法还是不建议的

在 setter 出错比在 validation 出错要早一点点,越早出错越容易找出来

#10 楼 @ericguo 好神奇,这也有 Gem 来做

原文说的其实是需求和实现不对等:

需求是 before set,实现是 before validate。用 before validate 来实现带来耦合,即:关掉 validate,strip title 逻辑也被关掉了。

从代码执行角度,在 set 和 validate 之间执行的代码读取到的是未 strip 的 title,这也不是需求的本意。

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