使用 SimpleDelegator 裝飾模型

大多數 Rails 開發人員首先在模板中修改他們的模型資訊:

<h1><%= "#{ @user.first_name } #{ @user.last_name }" %></h1>
<h3>joined: <%= @user.created_at.in_time_zone(current_user.timezone).strftime("%A, %d %b %Y %l:%M %p") %></h3>

對於具有大量資料的模型,這可能很快變得麻煩並導致從一個模板到另一個模板的複製貼上邏輯。

此示例使用 stdlib 中的 SimpleDelegator

預設情況下,對 SimpleDelegator 物件的所有請求都將傳遞給父物件。你可以使用表示邏輯覆蓋任何方法,也可以新增特定於此檢視的新方法。

SimpleDelegator 提供了兩種方法:__setobj__ 用於設定要委託的物件,__getobj__ 用於獲取該物件。

class UserDecorator < SimpleDelegator
  attr_reader :view
  def initialize(user, view)
    __setobj__ @user
    @view = view
  end

  # new methods can call methods on the parent implicitly
  def full_name
    "#{ first_name } #{ last_name }"
  end

  # however, if you're overriding an existing method you need
  # to use __getobj__
  def created_at
    Time.use_zone(view.current_user.timezone) do
      __getobj__.created_at.strftime("%A, %d %b %Y %l:%M %p")
    end
  end
end

一些裝飾器依靠魔術來連線這種行為,但是你可以通過初始化頁面上的物件使表達邏輯的來源變得更加明顯。

<% user = UserDecorator.new(@user, self) %>
<h1><%= user.full_name %></h1>
<h3>joined: <%= user.created_at %></h3>

通過將對檢視物件的引用傳遞給裝飾器,我們仍然可以在構建表示邏輯時訪問所有其餘檢視助手,而無需包含它。

現在,檢視模板只關注將資料插入頁面,而且更加清晰。