2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rails 5.2 + Bulmaでajaxを使ってモーダルウィンドウUX

Last updated at Posted at 2019-05-02

Rails 5.2 で簡単なWikiサイトを作る - Part4

Rails 5.2 で簡単なWikiサイトを作る - リストViewを作るの続きです。

環境

  • Rails 5.2.2
  • ruby 2.5.1p57
  • psql (PostgreSQL) 10.4

前提条件

本記事では、Rails、ruby、PGのインストールの内容を含みません。

  • ruby のインストールは、こちらの記事がわかりやすかったです。
  • Ruby on Rails のインストールは、こちらの記事がわかりやすかったです。

CSSフレームワークは、bulmaを利用してます。

bulmaを導入する方法はこちら!

はじめに

git commit log

始める前に

CSS をネストで書きたいので postcss-nested を導入します。

yarn add postcss-nested

ルーティングを作ります

config/routes.rb
Rails.application.routes.draw do
-   get 'contents/index'
+   resources :contents
  root to: "pages#home"
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

現在の全てのパスはこんな感じ

$ rails routes
                   Prefix Verb   URI Pattern                                                                              Controller#Action
                 contents GET    /contents(.:format)                                                                      contents#index
                          POST   /contents(.:format)                                                                      contents#create
              new_content GET    /contents/new(.:format)                                                                  contents#new
             edit_content GET    /contents/:id/edit(.:format)                                                             contents#edit
                  content GET    /contents/:id(.:format)                                                                  contents#show
                          PATCH  /contents/:id(.:format)                                                                  contents#update
                          PUT    /contents/:id(.:format)                                                                  contents#update
                          DELETE /contents/:id(.:format)                                                                  contents#destroy
                     root GET    /                                                                                        pages#home
       rails_service_blob GET    /rails/active_storage/blobs/:signed_id/*filename(.:format)                               active_storage/blobs#show
rails_blob_representation GET    /rails/active_storage/representations/:signed_blob_id/:variation_key/*filename(.:format) active_storage/representations#show
       rails_disk_service GET    /rails/active_storage/disk/:encoded_key/*filename(.:format)                              active_storage/disk#show
update_rails_disk_service PUT    /rails/active_storage/disk/:encoded_token(.:format)                                      active_storage/disk#update
     rails_direct_uploads POST   /rails/active_storage/direct_uploads(.:format)                                           active_storage/direct_uploads#create

data-remote="true" でajaxを使えるようにするために、 rails-ujs を使います。

yarn add rails-ujs
./frontend/packs/application.js
import "init";
import "components/page/page"
import "components/contents/contents"

+ import Rails from 'rails-ujs';
+ Rails.start();

新規作成ボタンを作ります

./frontend/components/contents/_contents.html.erb
<div class="contents js-contents">
  ...
  <div class="contents--create-button js-contents--create-button">
    <%= link_to "+", new_content_path, remote: true, class: "contents--create-button--circle js-contents--create-button--circle button is-primary" %>
  </div>
</div>
./frontend/components/contents/contents.css
.contents { /* ボタンがテーブルにかからないように */
    padding-bottom: 60px;

    &--create-button { /* ボタンを右下に固定 */
         position: fixed;
         bottom: 5px;
         right: 5px;
         padding: 6px 10px;

        &--circle { /* ボタンを丸にして、中の「+」テキストをちょっと大きく */
             height: 60px;
             width: 60px;
             border-radius: 50%;
             font-size: 1.5em;
        }
    }
}

確認してみます

http://localhost:5000/contents/index

こんな感じになります

スクリーンショット 2019-04-29 19.10.59.png

モーダルで表示する作成ウィンドウを作ります

まずは、コンポーネントを作ります。

$ mkdir -p frontend/components/content-form
$ touch frontend/components/content-form/{content-form.css,content-form.js,_content-form.html.erb}
./frontend/components/contents/contents.js
import "./contents.css"
import "components/content/content"
+ import "components/content-form/content-form"
./frontend/components/content-form/content-form.js
import "./content-form.css"

モーダルViewを作ります。

./frontend/components/contents/_contents.html.erb
<div class="contents js-contents">
  ...
  <div class="contents-content-modal js-contents-content-modal modal">
    <div class="modal-background"></div>
    <div class="modal-card">
      <header class="modal-card-head">
        <p class="modal-card-title">コンテンツ</p>
        <button class="delete js-content-form--close-button"></button>
      </header>
      <div class="contents--content-form js-contents--content-form"></div>
    </div>
  </div>
</div>
./frontend/components/content-form/_content-form.html.erb
<%= form_with model: content do |form| %>
  <section class="modal-card-body">
    <div class="field">
      <label class="label">タイトル</label>
      <div class="control">
        <%= form.text_field :title, class: "input", placeholder: "Poii.ioはどんなサービスですか?" %>
      </div>
      <p class="help">タイトルを設定します。</p>
    </div>

    <div class="field">
      <label class="label">本文</label>
      <div class="control">
        <%= form.text_area :body, class: "textarea", rows: "3", placeholder: "Poii.ioとは、Wikiサービスです。様々なチャネルから検索することができます。" %>
      </div>
      <p class="help">本文を設定します。</p>
    </div>

    <div class="field">
      <div class="control">
        <label class="checkbox">
          <%= form.check_box :is_published %>
          公開しますか?
        </label>
      </div>
    </div>
  </section>
  <footer class="modal-card-foot">
    <%= form.submit content.id.present? ? "編集" : "作成", class: "button is-success" %>
  </footer>
<% end %>

:coffee:
form_for, form_tag は、Rails6で廃止されるようです。form_withを初めて使いました:scream_cat:

新規作成ボタンをクリックした時の処理を書きます

./app/controllers/contents_controller.rb
class ContentsController < ApplicationController
  ...
  def new
    @content = Content.new
  end
end
./app/views/contents/new.js.erb
document.querySelector(".js-contents--content-form").innerHTML = "<%= escape_javascript(c("content-form", content: @content)) %>";
document.querySelector(".modal").classList.add("is-active");

Controllerに作成時の処理を書く

Parameters: {"utf8"=>"✓", "authenticity_token"=>"G8KTmI4hUI5NT6BNR9mVwdP+gk/mgfGWd71IJJ9J7xo1C2G15r9jtSB3d29rhdokevYy5Ybb5dFeIwa+4LIP5Q==", "content"=>{"title"=>"テストタイトル", "body"=>"テスト本文テスト本文テスト本文テスト本文テスト本文テスト本文テスト本文テスト本文テスト本文v"}, "commit"=>"作成"}

上の params に合わせて、データを取得し、保存します。

./app/controllers/contents_controller.rb
class ContentsController < ApplicationController
  ...

  def create
    @content = Content.new(content_params)
    @content.save
  end

  private
    def content_params
      params.require(:content).permit(:title, :body, :is_published)
    end
end
./app/views/contents/create.js.erb
document.querySelector(".js-contents--table--content-row").insertAdjacentHTML('beforeend', "<%= j(c("content", content: @content)) %>");
document.querySelector(".modal").classList.remove("is-active");
document.querySelector(".js-contents--content-form").innerHTML = "";

編集時にも同じウィンドウを表示します

リストにて、編集リンクを作ります。

./frontend/components/contents/_contents.html.erb
<div class="contents js-contents">
  <table class="contents--table js-contents--table table is-fullwidth">
    <thead>
    <tr>
      <th><abbr title="Id">#</abbr></th>
      <th><addr title="Title">Title</addr></th>
      <th><addr title="Body">Body</addr></th>
      <th><addr title="IsPublished">Published?</addr></th>
+       <th></th>
    </tr>
    </thead>
...
./frontend/components/content/_content.html.erb
<tr class="content content--row">
  <th><%= content.id %></th>
  <td><%= content.title %></td>
  <td><%= content.body %></td>
  <td><%= content.is_published %></td>
+   <td><%= link_to "編集", edit_content_path(content), remote: true, class: "button is-success is-small" %></td>
</tr>

こんな画面になります。

スクリーンショット 2019-04-29 20.36.58.png

ajaxで、編集用のモーダルを修正します

Controllerの編集

./app/controllers/contents_controller.rb
class ContentsController < ApplicationController
+     before_action :set_content, only: [:edit, :update]

  ...
+   def edit
+   end

+   def update
+     @content.update(content_params)
+   end

  private
    ...
+     def set_content
+       @content = Content.find(params[:id])
+     end
end

ajaxの処理

$ touch app/views/contents/edit.js.erb
./app/views/contents/edit.js.erb
document.querySelector(".js-contents--content-form").innerHTML = "<%= escape_javascript(c("content-form", content: @content)) %>";
document.querySelector(".modal").classList.add("is-active");
./app/views/contents/update.js.erb
document.querySelector(".js-content-row--<%= @content.id %>").innerHTML = "<%= j(c("content", content: @content)) %>";
document.querySelector(".modal").classList.remove("is-active");
document.querySelector(".js-contents--content-form").innerHTML = "";

削除機能をつくりましょう

Controllerの編集

./app/controllers/contents_controller.rb
class ContentsController < ApplicationController
-   before_action :set_content, only: [:edit, :update]
+   before_action :set_content, only: [:edit, :update, :destroy]
  ...
+   def destroy
+     @content.delete
+     redirect_to contents_path
+   end
end

Viewの修正

<div class="contents js-contents">
  <table class="contents--table js-contents--table table is-fullwidth">
    <thead>
    <tr>
      <th><abbr title="Id">#</abbr></th>
      <th><addr title="Title">タイトル</addr></th>
      <th><addr title="Body">本文</addr></th>
      <th><addr title="IsPublished">公開</addr></th>
      <th></th>
+       <th></th>
    </tr>
<tr class="content content--row js-content-row js-content-row--<%= content.id %>">
  <th><%= content.id %></th>
  <td><%= content.title %></td>
  <td><%= content.body %></td>
  <td><%= content.is_published %></td>
  <td><%= link_to "編集", edit_content_path(content), remote: true, class: "button is-success is-small" %></td>
+   <td><%= link_to "削除", content_path(content), method: :delete, class: "button is-danger is-small" %></td>
</tr>

こんな感じの画面になります。

スクリーンショット 2019-05-03 03.10.36.png

最後に

git commit log

Wikiサービス作りました

(小さく告知させてください:ear:)
簡単なWiki検索を、社内コミュニケーションチャネルから検索できるツールで、「Poii.io」と言います。

NEXT!

検索ページを実装していこうと思います。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?