什么是Presenter
当你使用的models里面有很多view相关的逻辑的时候, 会觉得这块逻辑写在这个地方不太好。 很多人可能会把这些代码移到helper方法里面去,确实是可以的。但是当你view的逻辑复杂后, 可能你需要看看Presenter了。
Presenter是面向对象的方式实现view hepler。我就介绍下如何使用presenter重构helper 和model里面的一些方法。
重构views
例如我们需要显示一个博客文章的状态, 如果文章已经发表的话就显示发表的时间,否则显示为"Draft",
1 2 3 4 5 |
|
这时候看起来没有什么问题,如果需求改成希望把时间显示成xxx hours ago
的话,这时候如果使用
helper里面的time_ago_in_words
方法再方便不过了。但model里面不支持这个方法,所以我们移到
helper里面去。
1 2 3 4 5 6 7 8 9 |
|
这个方法确实解决了这个问题,但是helper有个缺点,把所有的helper方法都放到一个namespace下面了。 如果post有一个这样的方法,那该多方便。
创建第一个Presenter
我们来创建一个PostPresenter
(app/presenter目录下面)类来实现上面的需求。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
view_context
是ActionView的一个实例,这样的话我们才能使用time_ago_in_words
方法。
但是当我们想获取post的title的时候,这个persenter将无法获得。所以我们需要创建一个
BasePresenter来解决这个问题,所有的Presenter将会继承这个类。
1 2 3 4 5 6 7 8 9 10 |
|
通过继承SimpleDelegator类并且调用了super(@model)初始化方法,这个保证了如果我们调用的 方法在presenter里面不存在的话,就会调用model对应的方法。
并且定义了一个h方法来代替view。上面的ProjectPresenter将会重构成这样:
1 2 3 4 5 6 7 8 9 |
|
我们可以在controller里面初始化:
1 2 3 4 5 6 |
|
将presenter移出controller
上面的presenter在controller里面每次初始化感觉比较麻烦,现在我们通过定义一个helper方法, 来简化这个初始化。
1 2 3 4 5 6 7 |
|
上面通过传的model来实例化其对应的Presenter,然后通过block的方式实现你需要的调用。
1 2 3 |
|
定制的Presenter
上面的presenter都是默认认为是modle的名字加上Presenter,如果post还有一个定制的 AdminPostPresenter该如何实现呢?其实很简单,present再加一个参数就搞定了,代码如下。
1 2 3 4 5 6 7 |
|
调用的地方写成present(@post, AdminPostPresenter)
这样就可以了。
总结
使用Presenter极大的分离了model里面view相关的逻辑,也给测试带来了方便。也有类似的gem 例如draper实现了差不多的功能。如果你的view和model有相关的代码,可以考虑使用Presenter 来重构一下吧。