miyazaki-dev

Rails5とBootetrapでモーダルウィンドウを作るまで

Ruby On Rails

[2017年に作成された記事です。]

Railsでmodalwindow

rails 5.1.1

こちらを参考に作成しています。

Rails5と BootstrapでAjax-modalform

とりあえず、scaffoldで作成。

rails g scaffold user name:string
rails db:migrate
rails s 

そしたら、app/views/users/index.html.erbの中身を確認し、

app/views/users/index.html.erb

<%= link_to 'New User', new_user_path %>

これをapp/views/users/index.html.erb

<%= link_to 'New User', new_user_path, class: "btn btn-lg btn-primary" %>

にします。

ただbootstrapに適用するためにclassをつけただけですね。

いよいよモーダル化

先ほどのlink_toでは、new.html.erbを呼び出す形になっていますのでそれをnew.js.erbに変えてしまおうということ。

やり方は簡単で、link_toのオプションにremote: trueを付け加えるのみ最終的にボタンは以下のようになります。

app/views/users/index.html.erb

<%= link_to 'New User', new_user_path, remote: true, class: "btn btn-lg btn-primary" %>

これでこのリンク、ボタンをクリックするとnew.js.erbが呼び出されるのでnew.js.erbを作成。

中身は、app/views/users/new.js.erb

$("#user-modal").html("<%= escape_javascript(render 'form') %>");
$("#user-modal").modal("show");

jquery少しかじってれば、なんとなく読めるかと思うのですが、user-modalでidに対して、新規作成用のformをレンダリングすると言ったもの。

そして、それを表示しましょうみたいなことをしています。 そしたら表示するhtmlを作成します。以下のコードを下の方にでも追加してみてください。

これは上記サイトとは違った部分になります。モーダルウィンドウのデザインに少し関わってくるっぽいところです。

app/views/users/index.html.erb

<div class="modal fade" id="user-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"></div>

モーダルウィンドウを表示する部分になりますね。

_form.html.erbの修正続いては、formの修正。

元から書いてあるformはここからサンプルコードを拝借して、修正した結果、以下のようになりました。

app/views/users/_form.html.erb

<div class="modal-dialog" role="document">
  <div class="modal-content">
    <%= form_with(model: user, remote: true) do |form| %>

    <% if user.errors.any? %>
      <div id="error_explanation">
        <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
        <ul>
          <% user.errors.full_messages.each do |message| %>
            <li><%= message %></li>
          <% end %>
        </ul>
      </div>
    <% end %>

    <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">&times;</span>
      </button>
    </div>
    <div class="modal-body">

      <div class="form-group field">
        <%= form.label :name , class: "form-control-label" %>
        <%= form.text_field :name, id: :user_name, class: "form-control" %>
      </div>
    </div>
    <div class="modal-footer actions">
      <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
      <%= form.submit class: "btn btn-primary"%>
    </div>
    <% end %>
  </div>
</div>

controllerの修正続いて、controllerの修正です。

リクエスト処理できるようにします。

  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        format.html { redirect_to @user, notice: 'User was successfully created.' }
        format.json { render :show, status: :created, location: @user }
        format.js { @status = "success"}
      else
        format.html { render :new }
        format.json { render json: @user.errors, status: :unprocessable_entity }
        format.js { @status = "fail" }
      end
    end
  end

create処理後にcreate.js.erbを呼び出す。

create.js.erbの作成、表示部分の作成create.js.erbは以下のようにする。

app/views/users/create.js.erb

<% if @status == 'success' %>
  $("tbody").append("<%= j(render("tr", user: @user)) %>");
<% elsif @status == 'fail' %>
  alert('error!');
<% end %>
$("#user-modal").modal("hide");

これは成功した場合と失敗した場合の処理。

続いて、表示の部分。

今回はuser登録となりますので、user一覧が表示される部分。

app/views/users/_tr.html.erb

<tr>  
  <td><%= user.name %></td>
  <td><%= link_to 'Show', user %></td>
  <td><%= link_to 'Edit', edit_user_path(user) %></td>
  <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?'} %></td>
</tr>

参考にしたサイトもここで終了と書かれていたので、これでいける!

と思ったらエラー発生。そんなにうまくいかないですよねー

意味わかんねーとしばらく悩んで、controllerを修正controllerのnewにjsを許可するコードが足りていないらしい。

よくわかっていないけど、どこかのサイトに落ちてたものをそのまま流用。(笑)

そのサイト思い出し次第修正しておきます。すみません。

app/views/controller/users_controller.rb

  def new 
	@user = User.new
    respond_to do |format| 
      format.html{ redirect_to @user, notice: 'User was successfully created.' }
      format.js {} 
    end
  end

とした。しかしながらまだエラーは直らない。

無事解決!最終的な_form.html.erb

3時間くらいいろいろ試行錯誤した結果、_form.htmlのuserに@が付いていないのが原因みたいで、@userとしたらうまくいった!

app/views/users/_form.html.erb

<div class="modal-dialog" role="document">
  <div class="modal-content">
    <%= form_with(model: @user, remote: true) do |form| %>
    
      <% if @user.errors.any? %>
        <div id="error_explanation">    
          <h2><%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:</h2>
          <ul>
            <% @user.errors.full_messages.each do |message| %>
              <li><%= message %></li>
            <% end %>
          </ul>
        </div>
      <% end %>
      
      <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">&times;</span>
        </button>
      </div>
    
      <div class="modal-body">
        <div class="form-group field">
         <%= form.label :name, class: "form-control-label"%>
         <%= form.text_field :name, id: :user_name, class: "form-control" %>
        </div>
      </div>
      
      <div class="modal-footer actions">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <%= form.submit class: "btn btn-primary"%>
      </div>
      
    <% end %>
  </div>
</div>

これにて終了。

よくわかってない部分も多いですが、とりあえず目標とする動くところまでは実装できました。

まだまだ勉強不足ですね。

少しずつ知識をつけていきます...!