ユカシカド エンジニアブログ

体の栄養状態を把握する検査サービス VitaNoteを開発するエンジニアのブログ

(翻訳)Spreeドキュメント - Viewのカスタマイズ

※ 誤訳意訳多々注意

自分の残念な英語力ではぴんとこない箇所は英語のままpending。怪しい訳多し。

実践もしくは英語力の向上を伴って正しく理解することがあれば、加筆・修正する予定です。

この記事は2013/07/13現在のものです。

翻訳元:VIEW CUSTOMIZATION - SPREE DEVELOPER

概要(original)

SpreeではViewの拡張や入れ替えが可能です。このガイドでは利用できるオプションと以下の項目について説明します。

  • Defaceを使ったViewのカスタマイズ
  • Viewのテンプレートをまるごと入れ替える方法

Defaceを使う方法(original)

DefaceはViewファイルを直接編集することなくErbテンプレートのカスタマイズを可能にする、Rails3のライブラリです。DefaceではCSS3標準セレクタで要素(Rubyブロックを含む)を指定して、マッチする全ての要素に対して様々なアクションを実行することができます。

例)購入ページ
<%= render 'spree/shared/error_messages', :target => user %>
<h2><%= Spree.t(:registration) %></h2>
<div id="registration" data-hook>
  <div id="account" class="columns alpha eight">
    <!-- TODO: add partial with registration form -->
  </div>
  <% if Spree::Config[:allow_guest_checkout] %>
    <div id="guest_checkout" data-hook class="columns omega eight">
      <%= render 'spree/shared/error_messages', :target => order

<h2>
<%= Spree.t(:guest_user_account) %>

</h2>
<%= form_for order, :url => update_checkout_registration_path, :method => :put, :html => { :id => 'checkout_form_registration' } do |f| %>
        <p>
          <%= f.label :email, Spree.t(:email) %><br />
          <%= f.email_field :email, :class => 'title' %>
        </p>
        <p><%= f.submit Spree.t(:continue), :class => 'button primary' %></p>
      <% end %>
    </div>
  <% end %>
</div>

div#registrationの前にコードを挿入したい場合は以下のようにして上書きすることができます。

Deface::Override.new(:virtual_path  => "spree/checkout/registration",
                     :insert_before => "div#registration",
                     :text          => "<p>Registration is the future!</p>",
                     :name          => "registration_future")

このよう上書きすると“registration”をidに持つdiv要素の前に、

<p>Registration is the future!</p>

が挿入されます。

指定できるアクション

DefaceはCSSセレクタにマッチする要素にアクションを割り当てます。以下のアクションはCSSセレクタで指定した要素を

例)
:remove => “p.junk”
:insert_after => “div#wow p.header”
:insert_bottom => “ul#giant-list”

Defaceが現在サポートしているアクション

  • :remove - 指定したセレクタにマッチする全ての要素を削除します。
  • :replace - 指定したセレクタにマッチする全ての要素を指定したコンテンツに置き換えます。
  • :insert_after - 指定したセレクタにマッチする全ての要素の後に指定したコンテンツを挿入します。
  • :insert_before - 指定したセレクタにマッチする全ての要素の前に指定したコンテンツを挿入します。
  • :insert_top - 指定したセレクタにマッチする全ての要素の先頭の子要素として、指定したコンテンツを挿入します。
  • :insert_bottom - 指定したセレクタにマッチする全ての要素の最後の子要素として、指定したコンテンツを挿入します。
  • :set_attributes - 指定したセレクタにマッチする全ての要素に:attributesで指定した属性をセット(もしくは追加)します。

全ての要素に適用できるわけではありません。例として、:insert_top と :insert_bottom で指定される要素は子要素を持つ親要素である必要があります。

コンテンツの提供方法

Defaceはコンテンツを指定する3つの方法を提供しています。

DefaceがErbを用いてコンテンツをオーバーライドするのはHTMLだけではありません。オリジナルのErbコンテキストでアクセス可能な全ての変数へもアクセスできます。

要素を指定する方法

While Deface allows you to use a large subset of CSS3 style selectors (as provided by Nokogiri), the majority of Spree’s views have been updated to include a custom HTML attribute (data-hook), which is designed to provide consistent targets for your overrides to use.

例) spree/products/show.html.erb:
<div data-hook="product_show" itemscope itemtype="http://schema.org/Product">
<% body_id = 'product-details %>

<div class="columns six alpha" data-hook="product_left_part">
  <div class="row" data-hook="product_left_part_wrap">
    <div id="product-images" data-hook="product_images">
      <div id="main-image" data-hook>
      <%= render 'image' %>
      </div>

      <div id="thumbnails" data-hook>
        <%= render 'thumbnails', :product => product %>
      </div>
    </div>

    <div data-hook="product_properties">
      <%= render 'properties' %>
    </div>
  </div>
</div>

<div class="columns ten omega" data-hook="product_right_part">
  <div class="row" data-hook="product_right_part_wrap">
    <div id="product-description" data-hook="product_description">
      <h1 class="product-title" itemprop="name"><%= accurate_title %></h1>

      <div itemprop="description" data-hook="description">
        <%= product_description(product) rescue Spree.t(:product_has_no_description) %>
      </div>

      <div id="cart-form" data-hook="cart_form">
        <%= render 'cart_form' %>
      </div>
    </div>
    <%= render 'taxons' %>
  </div>
</div>

</div>

例を見ての通り、'data-hook'にはいくつかの使用方法があります。

  • id属性がない要素では'data-hook'属性に、idに含まれるような値が入っています。
  • id属性を持つ要素では通常、'data-hook'属性に値はありません。
  • 時折、id属性を持つ要素の'data-hook'属性に要素のIDとは違う値が含まれていることがあります。これは通常、0.60.xの古いフックの名前から'data-hook'への移行をサポートするためのものです。

可能であれば、'data-hook'を使って要素を指定したほうがいいでしょう。上記のproducts/show.html.erbをベースにいくつかの例を紹介します。

  • :replace => “[data-hook=’product_show’]”
  • :insert_top => “#thumbnails[data-hook]”
  • :remove => “[data-hook=’cart_form’]”

以下のように両方のセレクタスタイルの組み合わせを使用することでで変更から確実に保護することもできます。

  • :insert_top => “[data-hook=’thumbnails’], #thumbnails[data-hook]”

Rubyブロックを指定する方法

Defaceは元のErbコンテンツ(and importantly not against the finished / generated HTML)に対してパスした全てのセレクタを評価します。 In order for Deface to make ruby blocks contained in a view parseable they are converted into a pseudo markup as follows:

以下のようなErbファイルが与えられた場合:
<% if products.empty? %>
    <%= Spree.t(:no_products_found) %>
<% elsif params.key?(:keywords) %>
    <%= Spree.t(:products) %>
<% end %>
Defaceでは以下のように見えるでしょう:
if products.empty?
    Spree.t(:no_products_found)
elsif params.key?(:keywords)
    Spree.t(:products)
end
そこで以下の例のようにCSS3の標準セレクタRubyコードブロックを指定することができます:
:replace => “code[erb-loud]:contains(‘t(:products)’)”
:insert_before => “code[erb-silent]:contains(‘elsif’)”

View upgrade protection

可能な限り安全な方法でSpreeのバージョンをアップグレードする為に、Defaceでは移行しつつある元のコンテンツの文字列を含ませることができる、:originalオプションをサポートしています。 When Deface is applying the override it will ensure that the current source matches the value supplied and will output to the Rails application log if they are differen

These warnings are a good indicator that you need to review the source and ensure your replacement is adequately replacing all the functionality provided by Spree. これはアップグレード後の予期しない問題を減らしてくれるでしょう。 Once you’ve reviewed the new source you can update the :original value to new source to clear the warning.

Defaceはホワイトスペースの違いによる警告を減らす為に、現在の値と:originalの値を比較する前に全てのホワイトスペースを削除します。

Organizing Overrides

The suggested method for organizing your overrides is to create a separate file for each override inside the app/overrides directory, naming each file the same as the :name specified within.

Using this method will ensure your overrides are compatible with future theming developments (editor).

Defaceの詳しい情報

詳しい情報といくつかのオーバーライドのサンプルはGithub上のREADMEを参照してください。 Deface Test Harness でもセレクタの使い方を試してみたり、Defaceどのように動作するか確認することができます。

テンプレートの置き換え(original)

カスタマイズ内容によっては実体のあるViewを必要とし、Defaceによるオーバーライドでは不便な場合があります。Spreeでは、アプリケーションをによるViewの複製やSpree内で同じ名前のファイルを完全に置き換えるエクステンションもサポートしています。 管理インターフェイスを含むSpreeのデフォルトViewをオーバーライドするには、単純に同じ名前のファイルをapp/viewsに作成するだけです。

例としてメインのレイアウトテンプレートをオーバーライドするには

YOUR_SITE_OR_EXTENSION/app/views/spree/layouts/spree_application.html.erb

を作成します。

※ バージョンが合わない場合にデバッグが大変なことになるので、自分のアプリケーションやエクステンションに正しいバージョンのViewを確実にコピーするようにしてください。 運用中のSpreeのロケーションや、適切なファイルをコピーするのに'bundle show spree'で確認することをおすすめします。

テンプレートの置き換えによる弊害

自分のアプリケーションやエクステンションでView全体をコピーして使用していると、Spreeを新しいバージョンにアップグレードする時には慎重にメンテナンスしてください。別のバージョンへアップグレードするときには、新しいバージョンのSpreeと自分のローカルバージョンに変更を確実に反映させるように必要なテンプレートを比較する必要があります。

この為、できる限りDefaceを使ってカスタマイズすることを強く推奨します。