Spreeにリコメンド(関連商品)を表示する機能を追加しましょう。
このエクステンションを使用します。
エクステンションのインストール
Githubに書いてあるとおりです。まずはGemfileに以下を記載。branch
の部分はSpreeのバージョンにあわせて書き換えてください。
gem 'spree_related_products', github: 'spree-contrib/spree_related_products', branch: '3-0-stable'
次にこれらのコマンドを実行。
bundle install
bundle exec rails g spree_related_products:install
bundle exec rake db:migrate
以上です。rails s
でサーバーを起動してみましょう。
管理者画面の商品ページに新しく「Related product」タブが登場し、こんな感じで関連商品の設定ができるようになります。
ただ他のエクステンション等と異なり、このエクステンションにはデフォルトのビューが作られていません。
管理画面は上の写真のようにインストール後すぐに使えるようになるのですが、エンドユーザー向けのページはコードを書く必要があるので注意してください。
RelationモデルとRelationTypeモデルについて
このエクステンションを使うと、関連する商品だけでなく、その関係性まで一緒に定義できるなど高機能で融通の効く設計となっています。その反面、概念が少々わかりにくいのでちょっとだけ解説しておきます。
このエクステンションで新しく作るモデルは2つ。Spree::RelationType
とSpree::Relation
です。
商品同士の関連を定義するのはSpree::Relation
で、親商品の外部キー:relatable_id
と子商品の外部キー:related_to_id
があります。関係性自体は多対多の自己参照モデルですね。
さらにSpree::Relation
は、外部キーrelation_type_id
を持ち、Spree::RelationType
に一対多でbelongs_to
します。そしてSpree::RelationType
は、アクセサリー、類似商品、セット商品など商品同士の関連性を定義しています。
つまり、ひとつの商品がアクセサリーとしての関連商品、類似商品としての関連商品などなど、タイプの異なる複数の関連商品を持つ構造になります。
ビューの作成
とりあえずさくっと表示だけしてみましょう。
partial挿入用のDefaceを作成。
Deface::Override.new(
virtual_path: 'spree/products/show',
name: 'add_relations',
insert_after: '[data-hook="product_properties"]',
partial: 'spree/shared/relations'
)
partialファイルを作成。
<h3 class="product-section-title"><%= Spree.t(:related_products) %></h3>
<ul class="list-group">
<% @product.relations.each do |r| %>
<li class="list-group-item"><%= link_to r.related_to.name, r.related_to %></li>
<% end -%>
</ul>
表示されました!
なお、@product.relations
のメソッド名はRelationType
のタイプ名をそのまま使用できるみたいです。例えば'Accessories'といったタイプ名にしておくと、@product.accessories
といったメソッドで表示できちゃうようですね。
日本語化
どのみちビューは自分で作らなければならないので無くても困ることはなさそうですが、一応日本語用のロケールファイルを作りましたので公開しておきます。
そのままconfig/locales
に設置するだけで管理画面が翻訳されるかと思います。
ついでに
なお節々のカラムからわかるように、このエクステンションのRelationはポリモーフィックでSpree::Product
以外のモデルも扱えるようになってるみたいです。私も詳しく検証してないのですが、よくわからない場合は気にせず使ってしまって大丈夫そうですね。
ハマった点
原因はわからないのですが、特定の条件下で関連商品設定画面を開こうとするとNoMethodError in Spree::Admin::Products#related
が発生することがあるようです。
undefined method `empty?' for nil:NilClass
Extracted source (around line #6):
4 <%= csrf_meta_tag %>
5
6 <% if @relation_types.empty? %>
7 <div class="alert alert-warning no-objects-found">
8 <%= Spree.t(:no_relation_types) %>
9 </div>
以下のGithub issueを参考に修正しました。
undefined method `empty?' for nil:NilClass #118
Spreeアプリケーション内に下記のファイルを設置すると動きます。
Spree::Admin::ProductsController.class_eval do
def related
load_resource
@relation_types = Spree::Product.relation_types
end
end