#はじめに
こんにちは!
DMM WEBCAMP Advent Calendar 2020の8日目を担当することになりました。
メンターの@ta-igaです。
プログラミングを初めてまず最初に作るアプリはtodoアプリなのではないでしょうか。一度理解してしまえばなんてことはない簡単なアプリですが理解するまでが意外と大変だと思います。そんなtodoアプリをrailsとbootstrapを使って制作していきましょう!
完成品はこちら↓
https://railsboottodo.herokuapp.com/tasks
#バージョン
Rails 6.0.3.4
Ruby 2.6.3
Bootstrap 3.3.6
#MVCとルーティング
まず最初にアプリの構造の説明をしていきます。皆さんMVC処理の流れとか説明できますか?MVCとはModel、Veiws、Controllerの3つの頭文字を取ったものです。アプリを利用する際、自分が指定したページ(URL)にいくまでパソコンの中では、Routing→Controller→Model→Viewsという順番に情報が処理されます。これをまず頭に入れておきましょう。これから複数の機能を作成していきますが、基本的にこの4つのページを編集していきます。
それぞれの機能について簡単に説明していきます。
ルーティング(Routing)
ユーザー側がブラウザを経由してアクセスしたURLとコントローラーのアクションを結びつける役割。
コントローラー(Controller)
ユーザーからのリクエストをModelやViewと連携させる役割。司令塔のようなところ。1つのControllerの中にユーザーからのリクエストに対して具体的な処理を実行する「アクション」が用意されている
モデル(Model)
データベースを管理するところ。コントローラーからの指示を受けデータの削除や追加をなどを行う。
ビュー(Views)
最終的な描画を担当するところ。私たちが普段パソコンで目にしている画面がこれになります。モデルからひっぱり出された情報を元に画面を表示しています。
ざっくりとこんな感じです。
こちらの記事だと画像とか使って詳しく書いてあるので参考にしてみてください。(著作権とかよくわかんないのでこの記事では画像使えませんでした🙇♂️)
#プロジェクトの作成
それでは早速進めていきましょう。ターミナルに
$rails new todo-app
と打ってプロジェクトを作成させます。途中、passwordを求められますので忘れずに入力してください。その際、入力した文字が画面に表示されませんが構わずに続けてEnterを押して進んでください。
Webpacker successfully installed 🎉 🍰
と表示されればプロジェクト作成は完了です。ケーキ食べたい...(途中Warningがたくさん出てくるかもしれませんがErrorと出てこない限りは全部無視してしまって大丈夫です。)その後
$cd todo-app
と入力してtodo-appに移動しましょう。(この後の作業は全てtodo-appに移動している前提で行います。)
##モデルの作成
モデルを作成していきます。モデルは単数形で頭文字を大文字にするのがルールです。ここではtitleをstring型、bodyをtext型にして作っていきたいと思います。ターミナルで以下を実行してください。
$rails g model Task title:string body:text
できたらその後以下でマイグレートしましょう。(もし間違えて作成してしまった場合には、gをdに変えて実行すれば消すことができます。)
$rails db:migrate
##コントローラの作成
コントローラを作ります。コントローラは複数形で全て小文字にするのがルールです。
$rails g controller tasks
これで、大まかな構造を作ることができました。(もし間違えて作成してしまった場合には、モデルと同じくgをdに変えて実行すれば消すことができます。)
#トップ画面 ~index~
まずトップ画面を作成していきたいと思います。トップ画面にはやること一覧を表示させます。これにはindexアクションを用いましょう。ここではすべてのタスクをTask.allで取得します。
class TasksController < ApplicationController
def index
@tasks = Task.all
end
end
次にviewを作成していきましょう。viewsフォルダのなかのtasksフォルダの中にindex.html.erbというファイルを作りましょう。(controlを押しながらクリックすれば作成できます。)ファイルを作ることができたら以下を記述しましょう。
<h1>やること一覧</h1>
<table>
<thead>
<tr>
<th>やること</th>
<th>詳細</th>
</tr>
</thead>
<tbody>
<% @tasks.each do |task| %>
<tr>
<td><%= task.title %></td>
<td><%= task.body %></td>
</tr>
<% end %>
</tbody>
</table>
次に大事なルーティングを作成しましょう。以下のように記述してください。
resources :tasks
なんとなんとrailsだとこの1行でindex,new,create,edit,update,show,destroyの主要な7つのアクション一気に作ることができます。(今回showは使いませんが...)rails便利!
これからは、localhost:3000/tasksと打てば今作成している画面を確認できるようになります。エラーが起きていないか常に確認しながら進めていきましょう。
#新規作成機能 ~new,create~
ここからは新規作成機能を作っていきましょう。まずはコントローラに記述をしていきます。
class TasksController < ApplicationController
def index
@tasks = Task.all
end
#ここから追加
def new
@task = Task.new
end
def create
@task = Task.new(task_params)
if @task.save
redirect_to tasks_path #セーブできたらindexページに行く
else
render 'new' #できなかったらnewページのまま
end
end
private
def task_params
#モデル作成時に作ったやつ
params.require(:task).permit(:title, :body)
end
end
ここではストロングパラメータというものを使って、Taskモデルを作成した際にできたtaskテーブルににtitle(やること)とbody(詳細)を保存します。ストロングパラメータについて詳しく知りたいかたはこちらを参照してください。そして「redirect toとrenderの違いって何??」と思ったセンスの良いかたはこちらを参照してください。
viewを作成します。
<h1>やること新規作成</h1>
<%= link_to '一覧へ', tasks_path %>
<%= form_with model: @task do |f| %>
<div class="field">
<%= f.label :やること %><br>
<%= f.textarea_field :title %>
</div>
<div class="field">
<%= f.label :詳細 %><br>
<%= f.text_field :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
form_withを使ってデータを送信させます。form_withについて詳しく知りたいかたはこちら
これによって送信されたデータは、createアクションへ運ばれます。
ここで、フォームが空欄だった場合に送信できないようにしておきましょう。この機能をバリデーションと呼びます。
class Task < ApplicationRecord
validates :title, presence: true
validates :body, presence: true
end
詳しい説明はここでは省きますが、これで空欄のままsubmitを押しても送信されないようになります。バリデーションについて詳しく知りたい方はこちら
最後にindexのページ(やること一覧のページ)に新規作成ページへのリンクを貼り付けましょう。ターミナルで
$rails routes
と打ってみてください。すると、
tasks GET /tasks(.:format) tasks#index
POST /tasks(.:format) tasks#create
new_task GET /tasks/new(.:format) tasks#new
edit_task GET /tasks/:id/edit(.:format) tasks#edit
task GET /tasks/:id(.:format) tasks#show
PATCH /tasks/:id(.:format) tasks#update
PUT /tasks/:id(.:format) tasks#update
DELETE /tasks/:id(.:format) tasks#destroy
...
と出てきたと思います。このtasks#newの左側にあるnew_taskにpathをくっつけたのがnewページに行くためのリンクになります。そのため、
<h1>やること一覧</h1>
<%= link_to '新規作成', new_task_path %> #追加
<table>
<thead>
<tr>
<th>やること</th>
<th>詳細</th>
</tr>
</thead>
<tbody>
<% @tasks.each do |task| %>
<tr>
<td><%= task.title %></td>
<td><%= task.body %></td>
</tr>
<% end %>
</tbody>
</table>
これで新規作成機能は終わりです。
#編集機能 ~edit,update~
続いて、編集機能を作成していきたいと思います。編集にはeditアクションとupdateアクションを使用します。コントローラーにこの2つのアクションを記述していきましょう。
class TasksController < ApplicationController
def index
@tasks = Task.all
end
def new
@task = Task.new
end
def create
@task = Task.new(task_params)
if @task.save
redirect_to tasks_path
else
render 'new'
end
end
#ここから追加
def edit
@task = Task.find(params[:id])
end
def update
@task = Task.find(params[:id])
if @task.update(task_params)
redirect_to tasks_path #updateできたらindexページに行く
else
render 'edit' #できなかったらeditページのまま
end
end
#ここまで
private
def task_params
params.require(:task).permit(:title, :body)
end
end
ここで新しく、find(params[:id])というコードが出てきましたね。これは投稿され情報に付けられたidを探し出すコードです。例えば、「ケーキを買う」という内容を編集したいのにボタン押したら隣に記述していた「部屋の掃除をする」という内容が画面に出てきたらもう訳わかんないですよね。ここではこのfind(params[:id])を使って編集したい内容を正しく呼び出せるようにしています。(ちなみにrailsというフレームワークを使っているからこの1行だけで情報を呼び出せるのであり、使はなければSQLという言語をゴリゴリ書く必要があります。railsすげえ。)
次にviewsファイルを作成していきましょう。
<h1>やること編集</h1>
<%= form_with model: @task do |f| %>
<div class="field">
<%= f.label :やること %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :詳細 %><br>
<%= f.text_field :body %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
入力フォームなのでnew.html.erbと同じコードですね。最後に一覧画面に編集画面へのリンクを付け加えて終了です。
<h1>やること一覧</h1>
<%= link_to '新規作成', new_task_path %>
<table>
<thead>
<tr>
<th>やること</th>
<th>詳細</th>
</tr>
</thead>
<tbody>
<% @tasks.each do |task| %>
<tr>
<td><%= task.title %></td>
<td><%= task.body %></td>
<td><%= link_to '編集', edit_task_path(task) %></td> #追加
</tr>
<% end %>
</tbody>
</table>
pathはターミナルでrails routesと打って確認してみてください。(新規作成機能作る時に一回やったやつ。)edit画面へ遷移する時にはidが必要なので今この情報を持っているtaskを最後につけることを忘れずに。
これで編集機能は終わりです。
#削除機能 ~destroy~
最後は削除機能を作成していきます。コントローラーにdestroyアクションを追加しましょう。
class TasksController < ApplicationController
def index
@tasks = Task.all
end
def new
@task = Task.new
end
def create
@task = Task.new(task_params)
if @task.save
redirect_to tasks_path
else
render 'new'
end
end
def edit
@task = Task.find(params[:id])
end
def update
@task = Task.find(params[:id])
if @task.update(task_params)
redirect_to tasks_path
else
render 'edit'
end
end
#ここから追加
def destroy
@task = Task.find(params[:id])
@task.destroy
redirect_to tasks_path
end
#ここまで
private
def task_params
params.require(:task).permit(:title, :body)
end
end
ここではfind(params[:id])で削除する情報を見つけて、destroyで削除しています。
一覧画面に削除ボタンを付けましょう。
<h1>やること一覧</h1>
<%= link_to '新規作成', new_task_path %>
<table>
<thead>
<tr>
<th>やること</th>
<th>詳細</th>
</tr>
</thead>
<tbody>
<% @tasks.each do |task| %>
<tr>
<td><%= task.title %></td>
<td><%= task.body %></td>
<td><%= link_to '編集', edit_task_path(task) %></td>
<td><%= link_to '削除', task, method: :delete, data: { confirm: 'You sure?' } %></td>
</tr>
</tr>
<% end %>
</tbody>
</table>
ここではpath名ではなく、method: :deleteと記述することでdestroyアクションを呼びます。そして、data: { confirm: 'You sure?' }と記述することで確認のモーダルウィンドウを出すことができます。
以上でtodoアプリの機能は全て作ることができました。お疲れ様でした。🍰
#Bootstrapを使ってレイアウトを整えよう
これでtodoアプリは完成したのですが、レイアウトがちょっと味気ないですよね...そこでBootstrapというcssのフレームワークを導入してレイアウトを整えていきましょう!
ここではざっくりとしか説明しないので詳しく知りたい方はこちらを参照してみてください。
##下準備
gem 'bootstrap-sass', '~> 3.3.6'
gem 'jquery-rails'
と入力し、
$bundle install
としましょう。途中passwordを求められると思うので指示通り入力してください。
次にRailsアプリの作成時に生成されるapplication.css
をapplication.scss
にリネームしてください。このファイルはapp/assert/stylesheet/の下にあります。
ファイル名を変更できたら、
@import "bootstrap-sprockets";
@import "bootstrap";
これらを追加してください。
そして、最後にapplication.jsを編集します。
//= require jquery
//= require bootstrap-sprockets
またこれらをを追加してください。これでrailsでbootstrapを使うための下準備が完了しました。
##レイアウトを整える
早速やっていきましょう。
まず、画面が左に偏っていると思うので真ん中にいい感じになるようにしましょう。(語彙力なくてごめんなさい。)application.html.erbにある<%= yield %>を以下のようにdivタグで囲んで下さい。
<div class="container">
<%= yield %>
</div>
この<%= yield %>には、各ページで表示されるhtmlファイルの内容が入ってきます。そのため、ここを編集するだけで全ページに編集を適用させることができます。
これで、レイアウトがいい感じに画面の真ん中にあると思います。
次に一覧ページのtableタグを以下のように編集してください。
<table class="table table-striped">
</table>
これで投稿された内容の背景が交互に変わり見やすくなっていると思います。(これすごいですよね。初めて使った時感動しました。)
そして最後にボタンをいい感じにしておきましょう。一覧画面にある、新規作成ボタン、編集ボタン、削除ボタンを以下のようにclassを付けて編集してみてください。
<%= link_to '新規作成', new_task_path, class: "btn btn-primary" %>
<%= link_to '編集', edit_task_path(task), class: "btn btn-success" %>
<%= link_to '削除', task, method: :delete, data: { confirm: 'You sure?' }, class: "btn btn-danger" %>
ついでに新規作成画面と編集画面にある「一覧へ」ボタンも編集してみましょう。
<%= link_to '一覧へ', tasks_path, class: "btn btn-info" %>
フォームのボタンも編集することができます。こちらのサイトに色々載ってあるので余裕のある方はやってみてください。
これで使いやすいいい感じのレイアウトになったと思います。お疲れ様でした!
#最後に
これで良さげなtodoアプリを作ることができました。たかがtodoアプリではありますが重要な要素がたくさん詰まっているので1つ1つ確認してみてください。
以上、最後まで読んでいただきありがとうございました!!!🍰🍰