カロリーメイトください

Barbaroi Ware(バルバロイ・ウェア)という名前でアプリ開発してます

『Ruby on Rails 5 アプリケーションプログラミング』を学習する5

Ruby on Rails 5アプリケーションプログラミング

Ruby on Rails 5アプリケーションプログラミング

序文

Ruby on Rails 5 アプリケーションプログラミング」学習5日目。
お金欲しい。

GitHub

github.com

客観的成果

  • 第3章
    • 3.3 詳細画面の作成(showアクション)
    • 3.4 新規登録画面の作成(new/create アクション)

(学習時間:4時間)

コード実装部分

↓/app/controllers/cds_controller.rb

class CdsController < ApplicationController
  # before_action: アクションメソッドの前に実行するメソッドを指定する
  # このようなメソッドをフィルターという
  before_action :set_cd, only: [:show, :edit, :update, :destroy]

  # 省略

  # GET /cds/new
  def new
    # 新規作成の場合は空のオブジェクトを渡す
    @cd = Cd.new
  end

  # 省略

  # POST /cds
  # POST /cds.json
  # _form.html.erbのフォームから
  # /cdsにPOSTで入力データが渡されて発火する
  def create
    # 入力されたデータからオブジェクトを作成する
    # cd_paramsはメソッドではなくその返り値
    # (cd_params()の括弧を省略した形)
    # インスタンス変数に代入しているのはエラー時の表示処理のため
    @cd = Cd.new(cd_params)

    # respond_toメソッドは指定されたフォーマットに応じて
    # 異なるテンプレートを呼び出す仕組み
    respond_to do |format|
      # 作成したオブジェクトを保存する
      # 成功したら
      if @cd.save
        # 指定されたフォーマットがHTMLなら
        # /{id値}にリダイレクトする
        # (@cdはオブジェクトのキー値と解釈される)
        # 現在のURLが/cdsであるから
        # /cds/{id値}にリダイレクトする
        # またオプションとしてデータを渡すことで
        # ビューテンプレートからローカル変数っぽく利用できる
        format.html { redirect_to @cd, notice: 'Cd was successfully created.' }
        # 指定されたフォーマットがJSONなら
        # show.json.builderで新規作成されたデータをJSON形式で出力する
        # status:はステータスコード
        # location:はリソース位置のURLを表す
        format.json { render :show, status: :created, location: @cd }
      # 失敗したら
      else
        # 指定されたフォーマットがHTMLなら
        # new.html.erbを再描画する
        format.html { render :new }
        # 指定されたフォーマットがJSONなら
        # エラー情報をJSON形式で書き出す
        # unprocessable_entityはデータを処理できなかったことを示す
        format.json { render json: @cd.errors, status: :unprocessable_entity }
      end
    end
  end

  # 省略

  private
    # Use callbacks to share common setup or constraints between actions.
    # フィルターとしてアクションの前に呼び出されるメソッド
    def set_cd
      # params: URL経由で渡されたパラメータを取得するメソッド
      # ここではオブジェクトのキー値を取得している
      # 取得したキー値をもとにfindメソッドで特定のオブジェクトを取得する
      @cd = Cd.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    # フォームからの入力値を取得する
    def cd_params
      # 定型句として覚えろ
      params.require(:cd).permit(:jan, :title, :price, :artist, :released, :is_major)
      # 具体的な戻り値は以下のようなハッシュになる
      # { 
      #   "id"=>"51848956", 
      #   "jan"=>"4988002756452", 
      #   "title"=>"充分未来",
      #   "price"=>2000,
      #   "artist"=>"集団行動",
      #   "released(1i)"=>"2018",
      #   "released(2i)"=>"2",
      #   "released(3i)"=>"7",
      #   "is_major"=>"0",
      # }       
    end
end

↓/app/views/cds/show.html.erb

<p id="notice"><%= notice %></p>

<p>
  <strong>Jan:</strong>
  <%= @cd.jan %>
</p>

<%# 省略 %>

<%# edit_cd_pathはビューヘルパーで %>
<%# 引数にidを渡すことで %>
<%# /cds/:id/editというパスを返す %>
<%# 引数のcdはやはりオブジェクトのキー値を表している %>
<%# ↓出力されるHTML %>
<%# <a href="/cds/51848956/edit">Edit</a> %>
<%= link_to 'Edit', edit_cd_path(@cd) %> |

<%# cds_pathもビューヘルパーで %>
<%# /cdsというパスを返す %>
<%# ↓出力されるHTML %>
<%# <a href="/cds">Back</a> %>
<%= link_to 'Back', cds_path %>

↓/app/views/cds/new.html.erb

<h1>New Cd</h1>

<%# 部分テンプレートに@cdを渡してhtmlを描画する %>
<%# _form.html.erbが部分テンプレートとして呼び出される %>
<%= render 'form', cd: @cd %>

<%# cds_pathはビューヘルパーで %>
<%# /cdsというパスを返す %>
<%# ↓出力されるHTML %>
<%# <a href="/cds">Back</a> %>
<%= link_to 'Back', cds_path %>

↓/app/views/cds/_form.html.erb

<%# ファイル名の先頭に_をつけることで部分テンプレートであることを宣言している %>

<%# モデルに関連づいたフォームを生成する %>
<%# 現在はform_forではなくform_withが推奨されている %>

<%# do~endはrubyではブロックと呼ばれ、ひとかたまりの処理を表す %>
<%# とりあえずdo~endは{}と同等のものとイメージしておく %>
<%# JavaScriptの無名関数みたいなものだろうか %>
<%# ブロックの概念はまだはっきりとはイメージできていないが %>
<%# 引数と同じようにform_withメソッドに渡されていると考えるべきであるようだ %>

<%# ↓出力されるHTML %>
<%# <form action="/cds" accept-charset="UTF-8" method="post"> %>
<%# <input name="utf8" type="hidden" value="&#x2713;" /> %>
<%# <input type="hidden" name="authenticity_token" value="6ZdmXguc0SGCJOO/eP3p24QMOctlyOw2/BFBPaowAjNPtd9jP0hDxv/VL9p5J0bdgdNv4vGQdhufZ6e0vjKnQw==" /> %>
<%# ブロック内の処理を反映する %>
<%# </form> %>

<%# <from>タグ以外に出力されているものは %>
<%# IEの古いバージョンに対応させる文字コード関連の処理と %>
<%# CSRF脆弱性対策っぽいです %>
<%= form_with(model: cd, local: true) do |form| %>

  <%# ↓入力値検証で発生したエラー情報を表示するためのコード %>
  <% if cd.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(cd.errors.count, "error") %> prohibited this cd from being saved:</h2>

      <ul>
      <% cd.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>
  <%# ↑ここまで %>

  <div class="field">
    <%# .labelも.text_fieldも.number_fieldも %>
    <%# .date_selectも.check_boxも.submitも %>
    <%# 全部ビューヘルパー %>
    <%# formはFormBuilderオブジェクトで %>
    <%# 出力しようとしているフォームを意味する %>
    <%# :janは引数として渡したオブジェクトのjanプロパティを表しているようだ %>
    <%# (シンボルなので値そのものではない) %>
    <%= form.label :jan %>
    <%= form.text_field :jan, id: :cd_jan %>
    <%# ↓出力されるHTML %>
    <%# <label for="cd_jan">Jan</label> %>
    <%# <input id="cd_jan" type="text" name="cd[jan]" /> %>
  </div>

  <div class="field">
    <%= form.label :title %>
    <%= form.text_field :title, id: :cd_title %>
  </div>

  <div class="field">
    <%= form.label :price %>
    <%= form.number_field :price, id: :cd_price %>
    <%# ↓出力されるHTML %>
    <%# <label for="cd_price">Price</label> %>
    <%# <input id="cd_price" type="number" name="cd[price]" />  %>
  </div>

  <div class="field">
    <%= form.label :artist %>
    <%= form.text_field :artist, id: :cd_artist %>
  </div>

  <div class="field">
    <%= form.label :released %>
    <%= form.date_select :released, id: :cd_released %>
    <%# ↓出力されるHTML %>
    <%# <label for="cd_released">Released</label> %>
    <%# <select id="cd_released_1i" name="cd[released(1i)]"> %>
    <%# <option value="2013">2013</option> %>
    <%# <option value="2014">2014</option> %>
    <%# ︙ %>
    <%# <option value="2017">2017</option> %>
    <%# <option value="2018" selected="selected">2018</option> %>
    <%# <option value="2019">2019</option> %>
    <%# ︙ %>
    <%# <option value="2023">2023</option> %>
    <%# </select> %>
    <%# <select id="cd_released_2i" name="cd[released(2i)]"> %>
    <%# <option value="1">January</option> %>
    <%# <option value="2">February</option> %>
    <%# <option value="3" selected="selected">March</option> %>
    <%# <option value="4">April</option> %>
    <%# ︙ %>
    <%# <option value="12">December</option> %>
    <%# </select> %>
    <%# <select id="cd_released_3i" name="cd[released(3i)]"> %>
    <%# <option value="1">1</option> %>
    <%# <option value="2">2</option> %>
    <%# ︙ %>
    <%# <option value="27">27</option> %>
    <%# <option value="28" selected="selected">28</option> %>
    <%# <option value="29">29</option> %>
    <%# <option value="30">30</option> %>
    <%# <option value="31">31</option> %>
    <%# </select> %>
  </div>

  <div class="field">
    <%= form.label :is_major %>
    <%= form.check_box :is_major, id: :cd_is_major %>
    <%# ↓出力されるHTML %>
    <%# <label for="cd_is_major">Is major</label> %>
    <%# <input name="cd[is_major]" type="hidden" value="0" /><input id="cd_is_major" type="checkbox" value="1" name="cd[is_major]" /> %>
  </div>

  <div class="actions">
    <%= form.submit %>
    <%# ↓出力されるHTML %>
    <%# <input type="submit" name="commit" value="Create Cd" data-disable-with="Create Cd" /> %>
  </div>

  <%# 最終的には以下のようなハッシュデータがサーバーに送られる %>
  <%# cd: { %>
  <%#   "id":51848956, %>
  <%#   "jan":"4988002756452", %>
  <%#   "title":"充分未来",%>
  <%#   "price":2000,
  <%#   "artist":"集団行動",%>
  <%#   "released":"2018-02-07",%>
  <%#   "is_major":true %>
  <%# } %>
<% end %>

実行結果

f:id:yjkym:20180328165609p:plain f:id:yjkym:20180328165611p:plain

感想

scaffoldで自動出力したソースコードにぽちぽちコメント付け。
一度、別の本でかんたんにさらったところだけど、より詳しく説明してくれてありがたい。
Rubyのブロックの概念の理解に手こずった。
JavaScriptの無名関数やコールバック関数のようなものとしてイメージするとしっくりいった気がする。
N予備校のスパルタのたまものである。
でもやっぱり手元にRubyのリファレンスも置いておきたいなぁ。
同じことをやるにも複数の記法が許容されてて、混乱しそうになっちゃう。
カロリーメイトください。

BGM

充分未来 / 集団行動 www.youtube.com