前回から少し間があいて開催された4回目の参加です。
今回も強く思ったのは、自分ではひとつのテーマに取り組むのでいっぱいなのですが、もくもく会ではメンバー数分の成果も吸収できることがあるのでプログラミング、Ruby、Rails初学者としてはとても効率的ですし、継続的にモチベーションが注入されるので大満足の勉強会でした。 あと、もくもく後のビールは最高です。
概要
- 日時: 2013/07/20 (土) 13:00 - 19:00
- 東灘区民センター 8F 会議室5
- 告知
Wiki
自分のテーマについて
RailsのECアプリケーションであるSpreeを、エクステンションをつくることから始めて理解を深める。
つくるもの
Spreeでは販売する商品の販売開始日という値を設定できるか、その逆の終了日(期限)は設定できない
- 賞味期限(消費期限)のある商品を扱うことを想定して、販売期限を管理画面で設定できるようにする
- 販売期限を過ぎた商品は販売できないようにする
つくっていく。
1.エクステンションのbarebonesを生成
$ spree extension expiration_product
$ cd spree_expiration_product
Gemfileを更新してbundle install
source 'https://rubygems.org'
# Provides basic authentication functionality for testing parts of your engine
gem 'spree_auth_devise', :git => 'https://github.com/spree/spree_auth_devise.git', :branch => '2-0-stable'
group :test, :development do
gem 'pry-rails'
end
gemspec
$ bundle install
2.販売期限日カラム(expired_at)を追加する
$ bundle exec rails g migration add_expired_at_to_spree_variants expired_at:date
3.とりあえずSpreeアプリケーション側に追加しておく
$ cd spree_app
spree_app/Gemfileを編集
gem 'spree_expiration_product', :path => '../extensions/spree_expiration_product'
インストール
$ bundle install
$ bundle exec rails g spree_expiration_product:install
4. 期限切れの商品が表示されないようにする
コンソール商品を期限切れにしてみる
$ bundle exec rails console
> product = Spree::Product.first
> variant = product.master
> variant.expired_at = '2013/07/01'
> variant.save!
期限切れの商品を除外するスコープを追加する
$ cd ../extension/spree_expiration_product
商品一覧ページで表示させるProductのスコープがspree_coreのapp/models/products/scope.rbが定義されているのでこれをオーバライドすることにする
$ mkdir -p app/models/spree/products
$ touch app/models/spree/products/scopes_decorator.rb
販売期限内の商品を返すメソッド(Spree::Product.buyable)を追加し、既存メソッドの(Spree::Product.active)をオーバライドする
module Spree
Product.class_eval do
delegate_belongs_to :master, :expired_at
def self.buyable
joins(:variants_including_master).where('spree_variants.expired_at >= ?', Date.today)
end
# Override existing method
def self.active(currency = nil)
not_deleted.available(nil, currency).buyable
end
end
end
5.動いているかチェック
UIはまだ実装できていないのでコンソールで商品の販売期限を設定して、期限が過ぎた商品が表示されないようになっているかどうかチェック。
$ bundle exec rails console
Loading development environment (Rails 3.2.13)
[1] pry(main)> product = Spree::Product.first
Spree::Product Load (0.4ms) SELECT `spree_products`.* FROM `spree_products` LIMIT 1
Spree::Product::Translation Load (0.2ms) SELECT `spree_product_translations`.* FROM `spree_product_translations` WHERE `spree_product_translations`.`spree_product_id` = 1
=> #<Spree::Product id: 1, name: "るびー丼", description: nil, available_on: "2013-06-02 00:00:00", deleted_at: nil, permalink: "るびー丼", meta_description: nil, meta_keywords: nil, tax_category_id: 1, shipping_category_id: 1, created_at: "2013-07-13 07:58:07", updated_at: "2013-07-20 08:53:06">
[2] pry(main)> variant = product.master
Spree::Variant Load (0.4ms) SELECT `spree_variants`.* FROM `spree_variants` WHERE `spree_variants`.`product_id` = 1 AND `spree_variants`.`is_master` = 1 LIMIT 1
=> #<Spree::Variant id: 1, sku: "SKU-001", weight: nil, height: nil, width: nil, depth: nil, deleted_at: nil, is_master: true, product_id: 1, cost_price: #<BigDecimal:7fe54318bca0,'0.1E4',9(18)>, cost_currency: "JPY", position: 1, sale_price: nil, expired_at: "2013-06-01">
[3] pry(main)> variant.expired_at = '2013/06/01'
=> "2013/06/01"
[4] pry(main)> variant.save!
(0.2ms) BEGIN
Spree::Price Load (0.2ms) SELECT `spree_prices`.* FROM `spree_prices` WHERE `spree_prices`.`variant_id` = 1 AND `spree_prices`.`currency` = 'JPY' LIMIT 1
Spree::Product Load (0.4ms) SELECT `spree_products`.* FROM `spree_products` WHERE `spree_products`.`id` = 1 LIMIT 1
SQL (0.3ms) UPDATE `spree_products` SET `updated_at` = '2013-07-22 01:02:06' WHERE `spree_products`.`id` = 1
(0.7ms) COMMIT
=> true
意図通り、表示されなくなったことをhttp://localhost:3000で確認
今回はここでタイムオーバー。 ここまでの成果物はGithubにあげてあります。 aq2bq/spree_expiration_product
まとめ
実際にエクステンションを書いてみるとSpreeへの理解が少し深まりました。
- 既存のメソッドを上書きするのは今後のSpreeのアップデートに対応できなくなる可能性があるので、フックするなど他の方法を検討する必要あり
- #buyableのというメソッド名の意味が今回の意図に対して大きすぎるので、#not_expiredに変更する
- viewとcontrollerを実装する
- テストを書く
という方向で引き続きこのエクステンション開発を完結させていこうと思います。