ruby on rails 屬於 MVC 框架, 對於簡單的應用三層可能就夠用了, 可是當應用愈來愈複雜可能就須要更多的抽象層來知足業務需求, 好比service, presenter 好比有些人認爲應用邏輯(業務邏輯)不該該放在數據層(Model),或者一個 Model 只應該管好他本身的事情,多個 Model 的融合須要另外的類來作代理。git
不少狀況下, view中會有這樣的相似寫法 @article.published? && @article.user_type == 'Admin'
也許能夠把他放到model中定義出一個方法, 好比github
class Artice < ActiveRecord::Base def published_by_admin? published? && user_type == 'Admin end end
或者你也能夠把他放到 helper中去 而後view中就能夠這樣用@article.published_by_admin
可是隨着邏輯愈來愈多, model中相似的方法也會愈來愈多, 可是model中應該主要用來放業務邏輯 因此須要額外抽象出presenter層來處理ruby
## 代碼連接 https://github.com/railscasts/287-presenters-from-scratch
class BasePresenter def initialize(object, template) @object = object @template = template end def object @object end private def self.presents(name) define_method(name) do @object end end def h @template end # this allows any template methods to be called directly from presenter code. def method_missing(*args, &block) # TODO check for @template.respond_to? and return raw values if nil @template.send(*args, &block) end end class UserPresenter < BasePresenter presents :user delegate :username, to: :user def full_name "#{first_name}-#{last_name}" end end # helper 中增長該方法 module ApplicationHelper def present(object, klass = nil) klass ||= "#{object.class}Presenter".constantize presenter = klass.new(object, self) yield presenter if block_given? presenter end end # in view <% present @user do |user_presenter| %> <p><%= user_presenter.fullname %></p> <% end %>
這樣無論是model 仍是 helper都會變得很乾淨, 最重要的是 變得更容易測試框架
推薦的gem Draper測試