PeaceJet

証券会社で証券外務員(転職しました!)をやりながら、マーケティングやデータ分析・UI/UX改善などを行っています。

Rails で Javascript と Cookie を使って閲覧履歴あるいは最近見た記事を表示できるようにしてみた。



RailsJavascriptCookieを使って閲覧履歴・最近記事を見たを実装してみた

閲覧履歴の実装については、何通りか考えられると思いますが、今回は単純なものを作るとしてCookieを使用して構築しようと思います。

データストア

今回はCookieを使用しましたが、その他にもSessionを使ったりWebStorageであるLocalStorageを使用したりという選択肢が考えられると思います。 このほかに、ActiveRecordを使用してDBへ格納するということも考えられますが、仮に実装しようとした場合、かなりコストが掛かるので、しっかりとしたコスト計算と判断が必要です。

代表的な3つ

それぞれ、メリット・デメリットがあると思います。 今回は、Cookieを使用して構築してみたいと思います。

注意点

Cookie情報は、ユーザーから丸見えになりますから、利用判断の目安は重要な情報ではなく変更されてもアプリケーションに影響しないような場合に限られるでしょう。

現場で使える Ruby on Rails 5速習実践ガイド

現場で使える Ruby on Rails 5速習実践ガイド

考え方

今回はShowメソッドが呼ばれたときに動作するようにしました。 Showされたときに表示される商品名称だけを保存。 そして、別のページを見たときに閲覧履歴に商品名称が表示される・・・という感じで構築してみます。

ロジック

  1. 単純に商品名称をStringをカンマでつなげて、Cookieへ格納します。

  2. コントローラーでカンマを区切りとして、配列にします。

  3. 最後に配列データをViewへ渡します。

実装

それでは、始めます。

Version

$ ruby -v
ruby 2.4.3

$ rails -v
5.2.0

Javascript

今回は、Cookieを利用しやすくために「js_cookie_rails」を使用します。

gem 'js_cookie_rails', '~> 2.2'

github.com

Controller

コントローラーはシンプルです。 Showが呼ばれたら、Viewに対してCookieに保存されているデータを配列にして返します。

  def show
    @recently_visit = cookies[:item_name].split(',') if cookies[:item_name]
  end

View

Viewを書く際、私はいつもテンプレートエンジンであるSlimを使用しています。

  <!-- Slim -->
  = @recently_visit.nil? ? "閲覧履歴はありません" : @recently.each {|item| item }
    - @recently_visit.each do |item|
      = link_to(Product.find_by('product_name=?', item).product_name, product_detail_path(item)) unless @recently.nil?
         br/

Ruby on Rails 5の上手な使い方 現場のエンジニアが教えるRailsアプリケーション開発の実践手法 (Web Engineer's Books)

Ruby on Rails 5の上手な使い方 現場のエンジニアが教えるRailsアプリケーション開発の実践手法 (Web Engineer's Books)

Javascript

jQueryを使用しています。

;(function() {
  $(document).on("turbolinks:load", function() {
    let item = "",
      itmes = "",
      split = [];
    // Product.nameで商品名称を取得
    item = "#{{@product.name}}";
    // Cookieからproduct_namesに関するデータを取得します。
    items = Cookies.get("product_names");
    // undefinedでなければデータがproduct_nameに入っている。
    if (items != undefined) {
      items = items + "," + item;
      split = items.split(",");
      // 重複を除去します。
      dup = split.filter(function(a, c, b) {
        return b.indexOf(a) === c;
      });
      Cookies.set("product_names", dup.join(","));
    } else {
      Cookies.set("product_names", item);
    }
  });
}.call(this));

実装は簡単で、流れはソースの中に書いておきました。

まとめ

実は、Sessionを使った方が、もう少しコストを抑えて書くことが可能と思います。 ただ、ブラウザが閉じたらセッションも閉じてしまうので、場合によると思いました。 Cookieも4KBまでですし・・・。

変なところでハマった

表示がなぜか配列に入った状態で表示されてしまうということ。 その原因を調べて解決しました。

qiita.com