(翻訳)Spreeドキュメント - エクステンション(½)の続き。 にもかかわらず長かった。分割したほうがよかったかも。
※ 誤訳意訳多々注意
自分の残念な英語力ではぴんとこない箇所は英語のままpending。怪しい訳多し。
実践もしくは英語力の向上を伴って正しく理解することがあれば、加筆・修正する予定です。
この記事は2013/07/17現在のものです。
翻訳元: EXTENSIONS - SPREE DEVELOPER
エクステンションの作り方(original)
はじめに(original)
シンプルなエクステンションをつくってみましょう。ある商品がセール中であることを示したいとします。 商品にセール価格を設定して、”セール商品特集ページ”で表示されるようにしていきます。この例はSpreeの機構で適切なエクステンションをつくるのかをしる非常に良い例です。
エクステンションを生成するところから始めてみましょう。Spreeアプリケーションの外に用意したディレクトリで以下のコマンドを実行してください:
$ spree extension simple_sales
これでいくつかのファイルやディレクトリを含む、spree_simple_salesが作成されます。 生成されたディレクトリへ移動してください:
$ cd spree_simple_sales
Variantsへセール価格を追加(original)
まず最初にしなければならないのは、variantsへセール価格カラムを追加するマイグレーションを作成することです、
以下のコマンドを実行すると作成できます:
$ rails g migration add_sale_price_to_spree_variants sale_price:decimal
TODO: 上記のコマンドはエクステンションのディレクトリ内で実行してください。
価格を扱うのでマイグレーションファイルを編集して、:precision(有効桁数) と :scale(その内の小数部の桁数)を正しく調整する必要がありいます。
db/migrate/XXXXXXXXXXX_add_sale_price_to_spree_variants.rb
を以下のように編集してください:
class AddSalePriceToSpreeVariants < ActiveRecord::Migration
def change
add_column :spree_variants, :sale_price, :decimal, :precision => 8, :scale => 2
end
end
Spreeアプリケーションにエクステンションを追加(original)
エクステンションの開発を続ける前に、作成したSpreeアプリケーションへ追加してみましょう。これで開発中に、実際のSpreeストアでエクステンションがどのように動作するのかわかります。
Spreeアプリケーションの'mystore'ディレクトリのGemfileに以下のコードを追加してください:
gem 'spree_simple_sales', :path => '../spree_simple_sales'
:pathについては、作成したエクステンションの場所にあわせて適宜調整してください。 ‘mystore'のロケーションへの相対パスになるようにしてください。
さきほど追加したgemをbundle:
$ bundle install
最後にspree_simple_salesのジェネレーターでマイグレーションを実行してください(プロンプトには'yes'と答えてください):
$ rails g spree_simple_sales:install
HomeControllerへのアクションの追加(original)
’Spree::HomeController’を拡張して、セール中の商品を選択するアクションを追加していきます。
spree_simple_salesのルートディレクトリにいることを確認して、コントローラーデコレーターの為のディレクトリを作成してください:
$ mkdir -p app/controllers/spree
このディレクトリに'home_controller_decorator.rb'を作成して以下のようにコードを書いてください:
module Spree
HomeController.class_eval do
def sale
@products = Product.joins(:variants_including_master).where('spree_variants.sale_price is not null').uniq
end
end
end
これは'sale_price'を持っている商品だけを選択するでしょう。
'config/routes.rb'にこのアクションに対応したルートを追加する必要もあります。以下のように追記してください:
Spree::Core::Engine.routes.draw do
get "/sale" => "home#sale"
end
セール商品特集ページのビューを用意する(original)
セール価格を設定
現在、'variants'には"セール価格"という属性があるのでサンプルデータを更新して少なくとも1商品をセール中にしてみましょう。今は管理画面のインターフェイスに'セール価格'を用意していないので、とりあえずrails consoleを使用しておこなう必要があります。次のチュートリアルではDefaceによるオーバーライドを使用して機能的に追加する方法を紹介します。
まず、rails consoleを起動してください:
$ rails console
ここから選んだ商品にセール価格を設定してみます。注意: 手元の環境では以下のコードにある同じ商品ではないこともありますが、あまり気にしないでください。単に’セール商品特集ページ’に指定の商品を表示することさえできればいいのです。
> product = Spree::Product.first
=> #<Spree::Product id: 107377505, name: "Spree Bag", description: "Lorem ipsum dolor sit amet, consectetuer adipiscing...", available_on: "2013-02-13 18:30:16", deleted_at: nil, permalink: "spree-bag", meta_description: nil, meta_keywords: nil, tax_category_id: 25484906, shipping_category_id: nil, count_on_hand: 10, created_at: "2013-02-13 18:30:16", updated_at: "2013-02-13 18:30:16", on_demand: false>
> variant = product.master
=> #<Spree::Variant id: 833839126, sku: "SPR-00012", weight: nil, height: nil, width: nil, depth: nil, deleted_at: nil, is_master: true, product_id: 107377505, count_on_hand: 10, cost_price: #<BigDecimal:7f8dda5eebf0,'0.21E2',9(36)>, position: nil, lock_version: 0, on_demand: false, cost_currency: nil, sale_price: nil>
> variant.sale_price = 8.00
=> 8.0
> variant.save
=> true
ビューの作成(original)
現在、データベースにはセール価格の商品が少なくとも一つ存在しています。この商品が表示されるようにビューを作っていきましょう。
まず、必要となるビューディレクトリを作成します:
$ mkdir -p app/views/spree/home
次に、'app/views/spree/home/sale.html.erb'を作成して以下のようにコードを書きます:
<div data-hook="homepage_products">
<%= render 'spree/shared/products', :products => @products %>
</div>
'http://localhost:3000/sale'へアクセスすると、チュートリアルで'セール価格'を設定した商品がリスト表示されているはずです。しかし価格を見ると正しい価格が表示されていないことに気がつくでしょう。これは次のセクションで簡単に修正できます。
Variantsのデコレート(original)
'セール価格'を扱うエクステンションを修正してきましょう。
まず最初に、新しいdecoratorの為のディレクトリを作成します:
$ mkdir -p app/models/spree
次に、'app/models/spree/variant_decorator.rb'を作成して以下のように書きます:
module Spree
Variant.class_eval do
alias_method :orig_price_in, :price_in
def price_in(currency)
return orig_price_in(currency) unless sale_price.present?
Spree::Price.new(:variant_id => self.id, :amount => self.sale_price, :currency => currency)
end
end
end
ここではオリジナルのメソッドの’price_in’へ'orig_price_in'という別名をつけてオーバーライドしています。商品のマスタに'セール価格'があれば、その価格を返します。それ以外は元の’price_in’を返します。
デコレーターのテスト(original)
書いたコードをテストするのにいい方法があります。Spreeのコアな機能を変更したVariant decoratorは特に注意して書かなければなりません。variant_decorator.rbの1組みのシンプルなユニットテストを書いていきましょう。
テストアプリケーションの作成
エクステンションは完全なRailsアプリケーションではないので、エクステンションに対してテストするものが必要です。'test_app'というRakeタスクを実行することで、テストを実行する為のセットがspecディレクトリに生成されます。
エクステンションのルートディレクトリで以下のコマンドを実行してください:
$ bundle exec rake test_app
このコマンドの実行が完了した後に'rspec'を実行すると以下のように出力されます:
No examples found.
Finished in 0.00005 seconds
0 examples, 0 failures
グレート!テストを追加する準備をしましょう。以下のようにspecディレクトリに以下のようなディレクトリ構造をつくってください:
$ mkdir -p spec/models/spree
では、variant_decorator_spec.rbを作成してテストを追加していきます:
require 'spec_helper'
describe Spree::Variant do
describe "#price_in" do
it "returns the sale price if it is present" do
variant = create(:variant, :sale_price => 8.00)
expected = Spree::Price.new(:variant_id => variant.id, :currency => "USD", :amount => variant.sale_price)
result = variant.price_in("USD")
result.variant_id.should == expected.variant_id
result.amount.to_f.should == expected.amount.to_f
result.currency.should == expected.currency
end
it "returns the normal price if it is not on sale" do
variant = create(:variant, :price => 15.00)
expected = Spree::Price.new(:variant_id => variant.id, :currency => "USD", :amount => variant.price)
result = variant.price_in("USD")
result.variant_id.should == expected.variant_id
result.amount.to_f.should == expected.amount.to_f
result.currency.should == expected.currency
end
end
end
エクステンションのバージョン管理(original)
異なるバージョンのSpreeでは作成したエクステンションの振る舞いも変わってしまいます。エクステンションが、異なるバージョンのSpreeで動作するようにブランチを作成して活発にメンテナンスして対応したほうがいいでしょう。
Spree自体のバージョン付けに従うようにエクステンションのバージョン管理をすることを推奨します。作成したエクステンションがSpree 2.0.xへ対応しているのであれば、'2-0-stable'というブランチをつくっておけば、使用する側のユーザにもわかりやすくなります。 もし、1.3.xにしか対応していないのであれば、同様に'1-3-stable'ブランチをつくっておきます。
Spreeとエクステンションの間に一貫した命名規則を持っていれば戸惑うことは少なくなるでしょう。
まとめ(original)
このチュートリアルでは、エクスションをインストールする方法と、自分自身で作る方法を学びました。 Spreeの開発コンセプトとSpree内部のいくつかの仕組みについてふれることができました。
次のパートではこのエクステンションをDefaceによるオーバライドを用いて改善する方法を紹介します。