やりたいこと
この新規登録機能を、ページ遷移無し、モーダル表示に変更する。
目標物
はじめに、作成しているアプリが、home画面にproductとcustomerの2つの情報を表示していることから、controllerとviewの構成が少し複雑になりますことご了承願います。
Bootstrapのこちらを基に実装していく
ちなみに、Bootstrapをまんまコピーするとこちら
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@mdo">Open modal for @mdo</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@fat">Open modal for @fat</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@getbootstrap">Open modal for @getbootstrap</button>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">New message</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<form>
<div class="form-group">
<label for="recipient-name" class="col-form-label">Recipient:</label>
<input type="text" class="form-control" id="recipient-name">
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Message:</label>
<textarea class="form-control" id="message-text"></textarea>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Send message</button>
</div>
</div>
</div>
</div>
この中のよく分からないやつについて詳しく見てみる
data-toggle
カスタムデータ属性。何をするかを指定している。
この場合、”modal”
data-target
カスタムデータ属性。どの要素を開くかを指定している。
この場合、id=”exampleModal”
ボタンクリックで、id=”exampleModal”を持つモーダルが表示される。
data-whatever
カスタムデータ属性。
名前からすると、”何でも良い”
view: ボタンを変更
変更前
<div class="button_new">
<%= link_to new_customer_path do %>
<button type="button" class="btn btn-warning"><%= t('views.button.new_customer') %></button>
<% end %>
</div>
変更後
<div class="button_new">
<button type="button" class="btn btn-warning" data-toggle="modal" data-target="#customerModal" data-whatever="@customer"><%= t('views.button.new_customer') %></button>
</div>
view: モーダル表示部
変更前
ページ遷移表示時のnewのview
<div class="container">
<div class="customer_page">
<div class="set_center_outer">
<h2 class="page_title_en">New Customer</h2>
<h5 class="page_title_ja"><%= t("views.title.new_customer") %></h5>
</div>
<%= render "form", customer: @customer %>
<div class="set_center_outer">
<p><%= link_to t("views.button.back_home"), homes_path, class: "hover_background_none" %></p>
</div>
</div>
</div>
editと共通部をパーシャル化していたので、その部分も記載すると、、
<%= form_with(model: customer, local: true) do |form| %>
<div class="set_center_outer">
<div class="set_center_inner">
<% if customer.errors.any? %>
<div id="error_explanation">
<h2><%= customer.errors.count %> 件のエラーが発生しました</h2>
<ul>
<% customer.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
</div>
</div>
<div class="set_center_outer">
<div class="set_center_inner">
<div class="field">
<%= form.label t('views.title.customer_number') %>
<%= form.text_field :number, placeholder: '123-456' %>
</div>
<div class="field">
<%= form.label t('views.title.customer_name') %>
<%= form.text_field :name, placeholder: 'お客様名' %>
</div>
</div>
<div class="actions">
<%= form.submit %>
</div>
</div>
<% end %>
変更後
customerのnewビューでなく、homesのindexにモーダルコードを記述する。
<div class="modal fade" id="customerModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="set_center_outer">
<h2 class="page_title_en">New Customer</h2>
<h5 class="page_title_ja"><%= t("views.title.new_customer") %></h5>
</div>
<%= render "modal_customer_form", customer: @customer %>
</div>
</div>
</div>
こちらもまたform部をパーシャル化しているので、そちらも記述します。
<%= form_with(model: customer, remote: true) do |form| %>
<div id="modal_customer_messages-error">
<%= render 'layouts/error_messages', model: form.object %>
</div>
<div class="set_center_outer">
<div class="set_center_inner">
<div class="field">
<%= form.label t('views.title.customer_number') %>
<%= form.text_field :number, placeholder: '123-456' %>
</div>
<div class="field">
<%= form.label t('views.title.customer_name') %>
<%= form.text_field :name, placeholder: 'お客様名' %>
</div>
</div>
<div class="modal_submit">
<%= form.submit %>
</div>
</div>
<% end %>
form_withの”local: true”を”remote:true”にしているのもポイント!
controller
homesのindexのview内でモーダル表示をすることにより、newアクションで@customerが生成されるため、homes_controllerのindexに@customerを追加する。
class HomesController < ApplicationController
def index
@product = Product.new
@customer = Customer.new
@products = Product.all
@products = Product.search_product(params[:search]) if params[:search].present?
@q = Customer.ransack(params[:q])
@customers = @q.result(distinct: true).order(number: :asc)
end
end
customers_controllerのcreateアクションのsaveできなかったときのバリデーションエラーメッセージを非同期で表示するためにcreate部のcontrollerを変更する。
変更前
def create
@customer = current_user.customers.build(customer_params)
respond_to do |format|
if @customer.save
format.html { redirect_to @customer, notice: t('views.messages.create_customer') }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
変更後
def create
@customer = current_user.customers.build(customer_params)
respond_to do |format|
if @customer.save
format.html { redirect_to @customer, notice: t('views.messages.create_customer') }
else
format.js { render :error }
end
end
end
js
エラーメッセージをjsにレンダリングしているためerrorのjsファイルを作成
$("#modal_customer_messages-error").html("<%= j(render 'layouts/error_messages', model: @customer) %>");
CSS
最後に、CSSを少し整える
.modal-header {
border-bottom: none;
}
.modal-dialog {
max-width: 400px;
}
.modal_submit {
margin-bottom: 40px;
}
コメント