Viewへの動的な処理の追加(その2)
までに、Actionへの動的な処理の追加方法、Viewでの動的処理の追加方法を学んできました。本項ではそれらの処理をもう少し深堀りする作業を行います。前項
具体的には、
・自己紹介ページの特技欄を配列で指定する
・女性の場合は、年齢を表示しない
・Actionで項目が指定されていない場合はViewに項目自体を表示しない
といった内容になります。
基本的に、今後はデータの定義はActionで行い、見た目の部分に関わるロジックはViewで行います。
現状のActionは、下の図のような状態
Viewは下の図のような状態になっているとします。
・自己紹介ページの特技欄を配列で指定する
app/controllers/top_controller.rbを開いてください。
現状、skills=“◯◯◯”となっていますが、今回は配列で指定するので下記のように配列として定義しましょう。
配列の中の文字列には好きな値を入れましょう。
class TopController < ApplicationController
def index
end
def profile
@user_name = "レイルズ"
@birthday = "1987/6/10"
@hometown = "滋賀県"
@skills = ["プログラミング", "詩の朗読", "ものまね"]
@remarks = "よろしくお願いいたします"
end
end
Rubyのカリキュラムでも学習しましたが、[1,2,3]というようにカンマ区切りの値を角括弧で括ると、Rubyでは配列として扱われます。
これをそのままブラウザで確認すると、下の図のように表示されてしまいます。
理想としては、特技の欄が一つずつ改行されて表示されてほしいですよね。
続いてViewに追加修正を行います。app/views/top/profile.html.erbを開き、特技の項目を配列の各値ごとにループで回して表示しましょう。
<div class="profile">
<h1>プロフィール</h1>
<div class="profile_image">
<%= image_tag 'noimage.png' %>
</div>
<div class="profile_detail">
<div class="label">ユーザー名</div>
<div class="value"><%= @user_name %></div>
</div>
<div class="profile_detail">
<div class="label">生年月日</div>
<div class="value"><%= @birthday %></div>
</div>
<%
date_format = "%Y%m%d"
birthday = @birthday.to_date
age = (Date.today.strftime(date_format).to_i - birthday.strftime(date_format).to_i) / 10000
%>
<div class="profile_detail">
<div class="label">年齢</div>
<div class="value"><%= age %></div>
</div>
<div class="profile_detail">
<div class="label">出身地</div>
<div class="value"><%= @hometown %></div>
</div>
<div class="profile_detail">
<div class="label">特技</div>
<% @skills.each do |skill| %>
<div class="value"><%= skill %></div>
<% end %>
</div>
<div class="profile_detail">
<div class="label">ひとこと</div>
<div class="value"><%= @remarks %></div>
</div>
</div>
ハイライトの部分が、Viewの修正箇所です。
Actionで定義したインスタンス変数をView側でeachを使ってループ処理を行っています。
ポイントとしては、特技というラベルをeach内に含んでいないところに注目してください。特技ラベルをeach内に含んだ場合の結果は下の図になります。
特技というラベルもループに含まれるため、重複して表示されてしまいます。
ループの種類ループの種類としては、each以外にもeach_width_indexや、each.with_index(n)というような方法も存在するので、調べて実施してみるのもよいでしょう。
・年齢の出し分け
続いて、女性の場合は年齢を表示しないよう編集していきます。
Viewにてif文で出し訳を行うのですが、Actionで性別に関するインスタンス変数を定義する必要がありますので、app/controllers/top_controller.rbを開き、genderというインスタンス変数を定義して下さい。値は「man」としておきます。
Viewにてif文で出し分けを行います。
app/views/top/profile.html.erbを開き、出し分けの処理を追記しましょう。
<div class="profile">
<h1>プロフィール</h1>
<div class="profile_image">
<%= image_tag 'noimage.png' %>
</div>
<div class="profile_detail">
<div class="label">ユーザー名</div>
<div class="value"><%= @user_name %></div>
</div>
<div class="profile_detail">
<div class="label">生年月日</div>
<div class="value"><%= @birthday %></div>
</div>
<% if @gender == "man" %>
<% date_format = "%Y%m%d" %>
<% birthday = @birthday.to_date %>
<% age = (Date.today.strftime(date_format).to_i -birthday.strftime(date_format).to_i) / 10000 %>
<div class="profile_detail">
<div class="label">年齢</div>
<div class="value"><%= age %></div>
</div>
<% end %>
<div class="profile_detail">
<div class="label">出身地</div>
<div class="value"><%= @hometown %></div>
</div>
<div class="profile_detail">
<% @skills.each do |skill| %>
<div class="label">特技</div>
<div class="value"><%= skill %></div>
<% end %>
</div>
<div class="profile_detail">
<div class="label">ひとこと</div>
<div class="value"><%= @remarks %></div>
</div>
</div>
上記の追加で、@genderというインスタンス変数の内容によって、表示するViewの内容を出し分けすることができます。
ポイントとしては、年齢を計算するロジックの外側にif文を記述するところです。if文を年齢計算ロジックの外側に配置することで、@genderが”man”ではない場合には計算を行う必要が無くなります。
処理の分岐本項では、if文を利用して出し分けを行っていますが、Rubyには逆の意味であるunlessという記法が存在します。
性別の定義性別の定義に関しては、本項では文字列でmanと記述していますが、一般的には数値で取り扱われる場合が多いです。また、性別の表記方法には国際基準が設けられており、下記のように定義付けされています。0=notknown(不明)1=male(男性)2=female(女性)9=notapplicable(その他)人間の性別に関する話はここでは行いませんが、3,4,5…以降にそれぞれのサービス毎に性別を追加できる拡張性があります。
Try*TryViewでの出し分けを行う*・Viewでの年齢表示を「男性は表示しない」に変更してみましょう。
・項目の表示・非表示
最後に、Actionにてインスタンス変数が定義されていない、もしくは空の場合の出し分けを行います。
まず、app/controllers/top_controller.rbを開き、各インスタンス変数の値を空にしましょう。
※いつでも戻せる状態にしておいて下さい。
ブラウザで確認すると、エラーにはならないですが、下の図のように、各項目が空の状態で表示されます。
続いて、Actionで出身地、ひとことの項目を未定義の状態にしてみましょう。
ブラウザで確認すると、エラーにはならず項目が空の状態と同じように扱えます。
※特技の項目はViewでeachという配列に依存する記法を行っているので、未定義にするとエラーになります。
上記のように、未定義状態でも基本的にはエラーにはなりません。しかし、未定義もしくは値が空だった場合は、できれば項目ラベル自体を表示しないほうがベターです。
なので、app/views/top/profile.html.erbを開き、ひとことの箇所を下記コードのように修正します。
<div class="profile">
<h1>プロフィール</h1>
<div class="profile_image">
<%= image_tag 'noimage.png' %>
</div>
<div class="profile_detail">
<div class="label">ユーザー名</div>
<div class="value"><%= @user_name %></div>
</div>
<div class="profile_detail">
<div class="label">生年月日</div>
<div class="value"><%= @birthday %></div>
</div>
<% if @gender == "man" %>
<% date_format = "%Y%m%d" %>
<% birthday = @birthday.to_date %>
<% age = (Date.today.strftime(date_format).to_i -birthday.strftime(date_format).to_i) / 10000 %>
<div class="profile_detail">
<div class="label">年齢</div>
<div class="value"><%= age %></div>
</div>
<% end %>
<div class="profile_detail">
<div class="label">出身地</div>
<div class="value"><%= @hometown %></div>
</div>
<div class="profile_detail">
<% @skills.each do |skill| %>
<div class="label">特技</div>
<div class="value"><%= skill %></div>
<% end %>
</div>
<% if @remarks.present? %>
<div class="profile_detail">
<div class="label">ひとこと</div>
<div class="value"><%= @remarks %></div>
</div>
<% end %>
</div>
if@remarks.present?endという記述を追加しました。
@remarksというインスタンス変数の値が空でなければ、endまでの内容を表示するという意味になります。
RubyonRailsではpresent?やblank?といったメソッドをよく利用するので下記のポイントをよく覚えておいてください。
if文でよく利用するメソッドblank?nil?というnilであればtrueを返すメソッドと、empty?という内容が空の場合にtrueを返すメソッドがありますが、blank?はその両方の特性を持ちます。つまり、変数の値が空、もしくはnilの場合にtrueを返します。また、blank?というメソッドはRubyonRailsが提供するメソッドなので、RubyonRails上でのみ使用することができます。present?上記のblank?の逆の特性を持つメソッドです。変数の内容が空でもnilでもない場合にtrueを返します。こちらもblank?同様に、RubyonRails上でのみ使用することができます。
Try*TryViewでの分岐を行い、項目の出し分けを行う*・出身地や特技などが未設定の場合は、項目と項目名を非表示にしてみましょう。