学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Rails導入編 | カート機能の実装 | 18 | Ajax

↓↓クリックして頂けると励みになります。



17 | カートの仕上げ】 << 【ホーム】 >> 【19 | Ajaxリクエスト送信





Ajax(Asynchronous JavaScript and XML)は、クライアントサイドで非同期通信を可能にするための技術です。
Railsでは、Ajaxを使ってページの一部を非同期的に更新することができます。

具体的には、RailsではUJS(Unobtrusive JavaScript)と呼ばれる手法を用いて、Ajaxリクエストを簡単に扱うことができます。
これにより、ページ全体を再読み込みすることなく、特定の部分だけを更新することができます。


カートをAjaxスタイルにします。
トップページのサイドバーに現在のカートを配置します。


その後、ページ全体を再表示しなくてもサイドバー内のカートを更新できるようにします。
まずはカートをトップページに移動させます。
これには部分テンプレートを使います。


部分テンプレートとはビューの一部を専用のファイルに収めたものです。
別のテンプレートやコントローラから部分テンプレートを呼び出す(レンダリングする)ことができ、部分テンプレートは自身をレンダリングして結果を返します。
通常テンプレートの名前と区別するためファイルの検索時に部分テンプレートの名前の先頭に自動的にアンダーズコア(_)を追加します。

コントローラー

まずはmarketsコントローラの変更を行います。
「SampleCart/app/controllers/markets_controller.rb」ファイルを以下のように編集します。
「include CurrentCart」と「before_action :set_cart」の記述を追加しています。


記述追加 【SampleCart/app/controllers/markets_controller.rb】

class MarketsController < ApplicationController

  include CurrentCart
  before_action :set_cart

  def index
    @goods = Good.order(:title)
  end
end



各商品の「カートに入れる」ボタンを押した時に、トップページにリダイレクトされるよう、line_itemsコントローラーを編集します。
「SampleCart/app/controllers/line_items_controller.rb」ファイルの32行目の記述を変更しています。


記述変更 【SampleCart/app/controllers/line_items_controller.rb】32行目

class LineItemsController < ApplicationController

  include CurrentCart
	before_action :set_cart, only: [:create]
  before_action :set_line_item, only: %i[ show edit update destroy ]

  # GET /line_items or /line_items.json
  def index
    @line_items = LineItem.all
  end

  # GET /line_items/1 or /line_items/1.json
  def show
  end

  # GET /line_items/new
  def new
    @line_item = LineItem.new
  end

  # GET /line_items/1/edit
  def edit
  end

  # POST /line_items or /line_items.json
  def create
    good = Good.find(params[:good_id])
    @line_item = @cart.add_good(good)

    respond_to do |format|
      if @line_item.save
        format.html { redirect_to markets_index_url, notice: "商品をカートに追加しました。" }
        format.json { render :show, status: :created, location: @line_item }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /line_items/1 or /line_items/1.json
  def update
    respond_to do |format|
      if @line_item.update(line_item_params)
        format.html { redirect_to line_item_url(@line_item), notice: "Line item was successfully updated." }
        format.json { render :show, status: :ok, location: @line_item }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @line_item.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /line_items/1 or /line_items/1.json
  def destroy
    @line_item.destroy!

    respond_to do |format|
      format.html { redirect_to line_items_url, notice: "Line item was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_line_item
      @line_item = LineItem.find(params[:id])
    end

    # Only allow a list of trusted parameters through.
    def line_item_params
      params.require(:line_item).permit(:good_id)
    end
end


ビュー

「SampleCart/app/views/carts/_cart.html.erb」ファイルの内容を以下の記述に編集します。
「SampleCart/app/views/carts/show.html.erb」ファイルの内容をほとんどコピーしただけですが、一部レイアウトの記述を変えています。


記述編集 【SampleCart/app/views/carts/_cart.html.erb】

<div class="container">
  <div class="card">
    <div class="card-body">
      <div class="card-title h5 mb-4"><strong>現在のカート</strong></div>
      <% @cart.line_items.each do |item| %>
        <div class="card mb-2">
          <div class="card-body">
            <div><strong><%= item.good.title %></strong></div>
            <span class="badge bg-warning"><%= number_to_currency(item.good.price) %></span>
            × 
            <span class="badge bg-primary"><%= item.quantity %></span>

            <div class="badge bg-danger w-100 mt-3">小計:<%= number_to_currency(item.total_price) %></div>
          </div>
        </div>
      <% end %>
      <div class="container mt-4">
        <span class="badge bg-secondary">合計金額</span> <span class="badge bg-success fs-5"><%= number_to_currency(@cart.total_price) %></span>
      </div>
      <div class="mt-4">
        <%= button_to 'カートを空にする', @cart, method: :delete, class: 'btn btn-outline-danger', data: { turbo: false }, form: { onSubmit: "return check()" } %>
      </div>

    </div>
  </div>
</div>

<script>
  function check(){
    if(window.confirm('カートを空にしますか?')){ 
      return true;
    }
    else{
      window.alert('キャンセルされました'); 
      return false; 
    }
  }
</script>



「SampleCart/app/views/carts/show.html.erb」ファイルを作成したレンダーファイルを読み込む内容に編集します。


記述編集 【SampleCart/app/views/carts/show.html.erb】

<%= render @cart %>



次にトップページの左にテンプレートを組み込みます。
「SampleCart/app/views/markets/index.html.erb」ファイルを以下のように編集します。


記述編集 【SampleCart/app/views/markets/index.html.erb】5行目

<div class="container mt-4">
    <div class="row">
        <!-- 右側(カート)-->
        <div class="col-md-4">
            <div id="cart" class="carts">
                <%= render @cart %>
            </div>
        </div>
        <!-- 左側(商品リスト) -->
        <div class="col-md-8">
            <div class="row">
                <% @goods.each do |good| %>
                    <div class="col-md-4">
                        <div class="card">
                            <img src="<%= good.image_url %>" class="card-img-top">
                            <div class="card-body">
                                <h6 class="card-title"><strong><%= good.title %></strong></h6>

                                <div class="badge bg-danger fs-6">
                                    <%= good.price %></div>
                                <br/>
                                <div class="badge bg-secondary">
                                    <%= good.maker %>
                                </div>
                                <div class="badge bg-primary">
                                    <%= good.category %>
                                </div>
                                <div class="mt-4">
                                    <%= link_to "この商品の詳細", good, class: "btn btn-success" %>
                                </div>
                                <div class="mt-4">
                                    <%= button_to 'カートに入れる', line_items_path(good_id: good ), class: "btn btn-warning" %>
                                </div>
                            </div>
                        </div>
                    </div>

                <% end %>
            </div>
        </div>        
    </div>
</div>



ブラウザでカートの表示と動作を確認してみます。
http://localhost:3000/

カート表示と動作確認
カート表示と動作確認



17 | カートの仕上げ】 << 【ホーム】 >> 【19 | Ajaxリクエスト送信




↓↓クリックして頂けると励みになります。