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のインストールの内容を含みません。
CSSフレームワークは、bulmaを利用してます。
bulmaを導入する方法はこちら!
はじめに
始める前に
CSS をネストで書きたいので postcss-nested
を導入します。
yarn add postcss-nested
ルーティングを作ります
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
import "init";
import "components/page/page"
import "components/contents/contents"
+ import Rails from 'rails-ujs';
+ Rails.start();
新規作成ボタンを作ります
<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>
.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
こんな感じになります
モーダルで表示する作成ウィンドウを作ります
まずは、コンポーネントを作ります。
$ mkdir -p frontend/components/content-form
$ touch frontend/components/content-form/{content-form.css,content-form.js,_content-form.html.erb}
import "./contents.css"
import "components/content/content"
+ import "components/content-form/content-form"
import "./content-form.css"
モーダルViewを作ります。
<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>
<%= 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 %>
form_for
, form_tag
は、Rails6で廃止されるようです。form_with
を初めて使いました
新規作成ボタンをクリックした時の処理を書きます
class ContentsController < ApplicationController
...
def new
@content = Content.new
end
end
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
に合わせて、データを取得し、保存します。
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
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 = "";
編集時にも同じウィンドウを表示します
リストにて、編集リンクを作ります。
<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>
...
<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>
こんな画面になります。
ajaxで、編集用のモーダルを修正します
Controllerの編集
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
document.querySelector(".js-contents--content-form").innerHTML = "<%= escape_javascript(c("content-form", content: @content)) %>";
document.querySelector(".modal").classList.add("is-active");
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の編集
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>
こんな感じの画面になります。
最後に
Wikiサービス作りました
(小さく告知させてください)
簡単なWiki検索を、社内コミュニケーションチャネルから検索できるツールで、「Poii.io」と言います。
NEXT!
検索ページを実装していこうと思います。