こちらの記事を読まれる方へ
こちらの記事はドットインストールの「Ruby on Rails4入門」の個人メモです。
ドットインストール:Ruby on Rails4入門
1.Ruby on Railsとはなにか?
Ruby on Rails
→RubyをもとにしたWebアプリケーションフレームワーク
公式サイトはこちら
→最新情報やドキュメントを見るときに便利っすよ。
ドットインストールでは、Todoアプリを作るよ。
前提知識は下記を勉強しておこう!
- Ruby
- HTML/CSS/JavaScript/jQuery
- sqlite/activerecord
ドットインストール(の環境)では、
rubyの2.0 railsは4.0らしいよ
2.DRY/CoC/MVCアーキテクチャとは何かを学ぶ、というか見る
用語説明
DRY
→Don’t Repeat Yourself
※同じことを2回かくのをやめろってことっす
CoC
→Convention over Configuration
※フォルダ構成、ファイル名、クラス名(規約)をきちんと守れってことっす
規約守らないとRails内の結びつけがこわれちゃいます
MVCアーキテクチャ
Model:データ
View:画面
Controller:ModelとViewをとりもつもの
3.こっからがRuby on Railsの本番っす
Railsをつかってアプリケーションをつくる
任意のディレクトリで
rails new "アプリケーション名"
上記のコマンドをつかう
※”アプリケーション名”には好きな名前「dotinstallapp」とかをいれよう。
ちょっと時間がかかるけど、ディレクトリが実行されるのを待ってから、完成したディレクトリに移動
cd dotinstallapp
これで「dotinstall」のディレクトリに移動できたので、
rails s
を実行
dotinstallの動画ではエラーが出てたが、自分の環境では出ず。
これからいじっていくフォルダは
- app
- config
- db
らしいよ
そうそう、ターミナルの画面はサーバー起動した後は、別タブで開くんやで。
4.Scaffoldを使ってみるの回
そもそもScafforldってなんや
Railsの仕組み。
シンプルな枠く組みを備えたアプリケーションを生成する仕組みのことでっせ。
サーバーが立ち上がってるところやから、CtrlキーとCキーで止めるで。
サーバーを止めたら
rails generate scaffold User name:string score:integer
を入力する。
これは、
rails generate scaffold
で、アプリケーションを生成し、
User name:string score:integer
の部分で管理したいものを書いている。
この場合、Userを管理し、属性を「name:string score:integer」として、文字列型で名前、整数型でスコアとしています。
先程のコマンドを実行すると、いろいろなファイルを作ってくれています。
その中で、
User name:string score:integer
db/migrateにこの設定(上のコード)でデータベースをうまいことしてくれ、というファイルができている。
マイグレーションファイルという。
マイグレーションファイルをデータベースに反映させるには、
rake db:migrate
を実行する必要がある。
そのあと、
rails s
で、サーバーを立ち上げる。
そして、ローカル環境で、
/userにアクセスし、新規作成、編集、消去の操作を試す。
→きちんとできてていた。
ここまでが、Scaffoldの説明。
シンプルなアプリだと簡単にできるけど、枠組みを変えたい場合はゼロから作成する必要がある。
それを5回目以降やっていくのがこの講座。
5.タスク管理アプリを作ってみよう!!のコーナー
このコーナーで作るアプリ
- アプリ名:Taskapp
- 機能:プロジェクトを多数作成、そのプロジェクト毎にタスク作成
- 機能2:プロジェクトの新規作成、編集、削除、タスクの完了、未完了の管理、追加、編集、削除
できたらいいな。
さてまずは、
rails new taskapp --skip bundle
今回は前回budle installをおこなっているので、
スキップできます。「–skip bundle」のオブションをつける。
完了したら、
rails s
でサーバーを立ち上げる※taskappのディレクトリ移動を忘れずに。
また今回も自分の環境ではエラーでず。
※ルビーレーサーというものをいじらず。なんでや?
つぎはプロジェクトを作ってくで
プロジェクトを新しく作るには?
手作業でアプリケーションを作るときは、Modelを作り、その後にControllerとViewを作る。
まずは、
rails generate
rails g
と打ち込む。※上下どっちでも大丈夫
ただ、これだけだとダメなので、
rails g model Project title
と打ち込む。
ここでの注意は、まずProjectに持たせた属性は文字列だが、
属性のデフォルトは文字列なので「title:string」の「:string」は省略されている。
Railsの規約により、Modelは単数形で、なおかつ最初は大文字
である。
これでマイグレーションファイルができるので、
rake db:migrate
でデータベースに反映させる。
6.【続き】rails db/rails consoleを使ってみる
まずはモデルの確認を行う。
ここで登場するのが、「Railsの管理コマンド」です。
今使っているデータベースにアクセス
rails db
実行するとsqliteが立ち上がる。
そこで
.schema
とすると、ちゃんと projects テーブルができていて、そこに自動的に id とか、title とか、created_at(作成された日)とか、updated_at(更新された日)のフィールドができているのを確認dきる。
title だけ指定すれば id などは全部自動で Rails が作ってくれる。賢いね。
今の段階では何もデータがないのでsqliteを終了する。
.exit
Rubyを使いながらProjectのModelをインタラクティブに操作できる
rails console
p = Project.new(title: "p1")
p.save
これで、オブジェクトを作成でき、idの設定ができる。
p
実際に出力してみると、
=> #<Project id: 1, title: "p1", created_at: "2016-01-12 20:31:51", updated_at: "2016-01-12 20:31:51">
こういった形で出力される。
また、
Project.create(title: "p2")
とすることで、「new」と「save」を一緒に実行してくれる
Project.all
で確認すると、
=> #<ActiveRecord::Relation [#<Project id: 1, title: "p1", created_at: "2016-01-12 20:31:51", updated_at: "2016-01-12 20:31:51">, #<Project id: 2, title: "p2", created_at: "2016-01-13 08:03:37", updated_at: "2016-01-13 08:03:37">]>
と、2つあることが確認できる。
→なんで「title:」のあと半角スペース空けてんの?
rails consoleは
quit
で終了できるよ。
データを確認するには
rails db
select * from projects
で、データベースを立ち上げた後、クエリで確認。
1|p1|2016-01-12 20:31:51.145094|2016-01-12 20:31:51.145094
2|p2|2016-01-13 08:03:37.761118|2016-01-13 08:03:37.761118
そうすると、データが2つあるのが分かる。
インタラクティブにModelの状態を確認したいときは、
こういったやり方があるので記憶しておくこと。
7.さて、Controllerでっせ
まずControllerを作るには
rails g controller Projects
でOK。
注意点は、Controllerを作るときは必ず複数形でつくること。
※ここの大文字はマストだったっけ??
これで、ControllerのファイルとViewに関するフォルダが作成される。
ここまでできたらファイルを確認する。
確認するファイルは。
taskapp→app→controllers→projects_controller.rb
tasukapp→config→routes.rb
まずは
resouces :projects
をファイルの三行目にかく。そのまえにスペースを作ること。
※いろいろ例もファイル内に記載されているので確認すること。
これで、projects に関するルーティング(URL の自動生成)をしてくれる命令ができる。
それを確認するために、
rake routes
を実行する。すると、
Prefix Verb URI Pattern Controller#Action
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
とでる。
「URI Pattern」→ブラウザからアクセスした時の URL
GET の方式で、/projects にいくと一覧を出してくれる
→一覧を出すためのロジックは、projects の controller の中の index action に書くという見方。
「Controller#Action」という書き方なので、「projects#index」で一覧を出したりだとか、もしくは新規作成には「projects#new」と「projects#create」を使うのですが、ここにある URL にアクセスして、実際に作っていくのは projects の controller で定義していくという意味。
→ここらへんようわからんな?
8.Projectの一覧を表示させよう!!
taskapp→app→controllers→projects_controller.rb
↑このファイルを編集する。
class ProjectsController < ApplicationController
def index
@projects = Project.all
end
end
こういう風にしてあげる。
内訳は、
まずindexアクションをつくる→Rubyで関数を書く。
@をつけた変数はViewの中で使える→インスタンス変数だから?
Projectの全部をひっぱってくるには「= project.all」とする。
そのあと、Viewを設定していく。
taskapp→app→views→projects
この階層にファイルを作るが、
Projects Controller の index アクションに対応する View は同じ名前の「index.html.erb」にすれば OK 。
→index.html.erbというファイルを作る。
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li><%= project.title %></li>
<% end %>
</ul>
ファイルの中には上記の様に記載する。
これは、プロジェクトの一覧を表示するための書き方。→「<h1>Projects</h1>」として、その下にリストで表示すれば良い。
ループをまわすので、Ruby の制御構造の「<% %>」の中に書いていく。
使えるのが @projects という変数なので、@projects の中身をループでまわしていく。
→「<% @projects.each do |project| %><li></li><% end %>」
制御構造を使うには「<% %>」の記法と、もう 1 つ「<%= %>」という記法も使えます。
「<%= %>」は何をやるかというと、次に書いた式を評価して、その内容を表示しなさいという事になります。
今回 Project のタイトルを表示したいので、
「<li><%= project.title %></li>」
とすれば OK 。
これで一覧のアクションが出来て、それに対する View が出来たので、ブラウザで /projects にアクセスすると、一覧が見られるはずです。
rails s
で確認
前回に作った「p1」「p2」が表示されているはず。
→表示されていた。
9.rootの設定をしよう!
ルーティングってなに?
この 「URL」 でアクセスしたらどのアクションが実行されるかというのを関連づけるためのものです。
例えば今回の場合、前回の作業で、/projects で一覧が表示されていたが、タスクアプリだから、「/」つまりトップページで、一覧が表示されている方が便利です。
その設定方法を見ていく。
→routes.rbで設定する。
このファイル内には例がたくさん記載されているのでコピペするのも良い手段。
Rails.application.routes.draw do
resources :projects
root 'projects#index'
end
/ の URL(ルート)のアクションを決めるのは「root ‘…’」という命令。
今回ルートに割り当てたいのが projects の index アクションなので、「root ‘projects#index’」とすれば OK。
「/」でアクセスしてみると一覧が表示されているかを確認する。
10.共通テンプレートを使ってみるの回
TOPのURLってヘッダーとかあるけどこれどこにあるん??
→app/views/layout/application.html.erb
このファイルに共通のヘッダーとかフッターが入っている。
<!DOCTYPE html>
<html>
<head>
<title>Taskapp</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
Viewの中に書いた内容は、<%= yield %>の中に反映される。
次は全ページ共通でロゴ画像を表示するというのをやってみる。
<!DOCTYPE html>
<html>
<head>
<title>Taskapp</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= image_tag "logo.png" %>
<%= yield %>
</body>
</html>
画像を表示するには img タグを書いていても良いが、
Rails の中に image_tag ヘルパーという、
img タグを簡単に書ける仕組みがあるので、
それをつかう。
<%= image_tag "logo.png" %>
これを記載すると、
app/assets/images を見に行ってくれて、imgタグに展開してくれるらしいよ。
※imagesのフォルダ内に画像をいれておいてね。
あと、サーバー起動した状態で、画像をフォルダに入れたら
エラーでた。再起動したらエラーでなかった。これそういうもんなん?
他にもスタイルシートとかJavaScriptの共通をいじれるテンプレがあるので、スタイルシートをいじっていこう。
※assetsのフォルダ内にあるよ。
body {background: #eee}
これで全体がグレーになった。
あとはページの一番下にリンクをつくろう!
<!DOCTYPE html>
<html>
<head>
<title>Taskapp</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= image_tag "logo.png" %>
<%= yield %>
<%= link_to "Home","/" %>
</body>
</html>
リンクもaタグをかいても良いが、Railsの便利な機能がある。
<%= link_to "Home","/" %>
この部分が、リンクヘルパーです。
<%= link_to "Home",projects_path %>
こういった書き方でもOKです。
ちなみにこの書き方にすると、/projectsにとびます。
この書き方はpathがどこにつながっているか、設定されているかを指定してあげる書き方なのですが、その定義は、「rake routes」のコマンドでひょうじされた表に定義されている。
rake routes
Prefix Verb URI Pattern Controller#Action
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
プロジェクトの一覧は、「/projects」で、Controller と action でいうと「projects#index」ですが、実は横に projects と書いてあります。
これに「_path」をつけると URL に変換してくれますので、それも覚えておきましょう。
他にも new_projects_path とか、edit_projects_path とかが使える。
この表はそういう意味だという事を覚えておくこと。
11.Projectsの詳細をいじっていくで
ProjectのタイトルをクリックしたらそのProjectの詳細にとぶのをつくってく
まずは、Viewから
app/views/projects/index.html.erb
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li><%= link_to project.title, project_path(project.id) %></li>
<% end %>
</ul>
link_toヘルパーを使用して、リンク先が「project_path」だが、「Project」のidを渡さないといけないので、
<%= link_to project.title, project_path(project.id)%>
これでOK。/project/1にリンクはられる。
そのあと、Controllerをいじって、project#showのアクションを創る必要がある。
app/controllers/projects_controller.rb で同じように作れば良いです。
class ProjectsController < ApplicationController
def index
@projects = Project.all
end
def show
@project = Project.find(params[:id])
end
end
これでOK
追加箇所は
def show
@project = Project.find(params[:id])
end
これで、URL で渡ってきた数字を params でとる事ができる。
このあと、showのViewをつくる。
app/views/projects の中の「index.html.erb」をコピーして、
show.html.erb を作りましょう。
<h1><%= @project.title %></h1>
プロジェクトの中身はまだタイトルしかないので、
これだけでOK。
こういう風に、詳細画面を作るときは一覧画面からリンクを張って、うまく routes を使って、Controller と View を書き換えていく流れを理解しておくこと。
12.新規作成フォームを作ろう
Projectを追加する
routing的には、
- projects/new をまずは作って、
- そこにフォームを設置して、
- その中身を POST で受け取って、
- projects#create で、データを保存する
まずは/projectsのリストの下に新規作成のためのリンクを追加する
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li><%= link_to project.title, project_path(project.id) %></li>
<% end %>
</ul>
<p><%= link_to "Add New", new_project_path %></p> #追加したやつ
これで、新規作成のためのリンクが完成。pタグ注意。
次は、「Add New」のリンク先は projects#new なので Controller と View を作ってあげる。
class ProjectsController < ApplicationController
def index
@projects = Project.all
end
def show
@project = Project.find(params[:id])
end
def new # ここから追加したやーつ
@project = Project.new
end
end
Controllerの方はこれでOK。newをつくってあげる。
次はnewのViewをつくってあげる。
→app/views/projects に new.html.erb を作ってあげる。
<h1>Add New</h1>
<%= form_for @project do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
タイトルを入力するためのテキストフィールド
→「<%= f.label :title %>」とすると、
title のためのラベルを作ってくれます。
「<br>」で改行。
「<%= f.text_field :title %>」とすると、入力フィールドが出来る。
最後に「<%= f.submit %>」としてサブミットボタンを付ける。
13.データを保存するで
projects/new で入力のためのフォームを提示できたから、
これを POST して、projects#create というアクションを作って、データを保存するで。
class ProjectsController < ApplicationController
def index
@projects = Project.all
end
def show
@project = Project.find(params[:id])
end
def new
@project = Project.new
end
# ここから追記した分
def create
@project = Project.new(project_params)
@project.save
redirect_to projects_path
end
private
def project_params
params[:project].permit(:title)
end
projects_controller.rb に「def create … end」と書く。
その中に「@project = Project.new()」として、引数にフォームから渡されたものを入れる。
とりあえず「project_params」といれる。
その後に「@project.save」とした、
プロジェクト一覧に行ってほしいので「redirect_to projects_path」とすれば OK です。
project_paramsはプライベート関数で定義するのが
代表的な手法になっている。→なんで?てかプライベート関数ってなに?
「private def project_params …」とした後、
その中に「params[:project].premit(:title)」と書いて、
project の title を返すよう設定する。
セキュリティ上、フォームから渡ってくるデータに関してフィルタリングを 1 回通して、それを渡すのが最近の作り方になっています。
これで、入力フォームで「p3」を入力してサブミットしたら、
新しくp3が作られとった。
新規追加の方法が以上。パラメーターをフィルタフィングするやり方と合わせて覚えておこう。→ちょっとようわからん?
14.Validationを設定しよう
validationとは
何らかのルールに沿わない場合は保存しない仕組み。
app/models/project.rb で validation を定義。
class Project < ActiveRecord::Base
validates :title, presence: true
end
上記はタイトルが空白だったらダメという設定.
対象となるのがtitle、ルールが「それがあるかどうか」= 「presence」で記載する。
これで、タイトルが空白ならデータが保存されず新規作成されなくなった。
次はエラーが出た場合は、一覧画面に戻らずに新規作成画面に遷移するように設定する。
→projects_controller.rb の「@project.save redirect_to projects_path」を変更する。
class ProjectsController < ApplicationController
def index
@projects = Project.all
end
def show
@project = Project.find(params[:id])
end
def new
@project = Project.new
end
#ここから
def create
@project = Project.new(project_params)
if @project.save
redirect_to projects_path
else
render 'new'
end
end
# ここまでが変更箇所
private
def project_params
params[:project].permit(:title)
end
end
データを保存するときに、validationが発動し、
真の場合は保存して、一覧画面に、
偽の場合は、保存されず新規作成画面へ
こういった具合に validation の結果に応じて画面の遷移を制御する。
※エラーメッセージがあれば尚便利。
15.エラーメッセージを表示する。
Viewをいじれば良い。
→view/projects/new.html.erb にかいていく
<h1>Add New</h1>
<%= form_for @project do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
# ここから追記
<% if @project.errors.any? %>
<%= @project.errors.inspect %>
<% end %>
# ここまで
</p>
<p>
<%= f.submit %>
</p>
<% end %>
validation エラーがあった場合、「@project.errors」にエラーメッセージが入るので、それがあるかどうかを条件分岐にする。
上記はエラーがあった場合それを表示するという処理。
@project.errors の中に何が入っているかを調べるには、
「<%= @project.errors.inspect %>」とすると分かりやすい。
一度、タイトルを空白にして新規作成してみると、
#<ActiveModel::Errors:0x007ff1201dbc80 @base=#<Project id: nil, title: "", created_at: nil, updated_at: nil>, @messages={:title=>["can't be blank"]}>
という感じで、@messagesの中に「can’t be blank」が入っているのが分かる。
それを実装していく
<h1>Add New</h1>
<%= form_for @project do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
<% if @project.errors.any? %>
<%= @project.errors.messages[:title][0] %> # ここ変更してる
<% end %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
こうすると「can’t be blank」と表示される
※空白で新規作成した場合。
これは presence に関連したデフォルトメッセージなので、
自分でメッセージを変更できる。
そういうときは、app/models/project.rb の「validates :title, presence: true」を変えれば OK。
class Project < ActiveRecord::Base
validates :title, presence: { message: "入力してください"}
end
これで、同じ操作をすると
「入力してください」と出る。
また、validationのルールはいくつも追加できる。
たとえば長さを三文字以上にする場合。
class Project < ActiveRecord::Base
validates :title, presence: { message: "入力してください"},
length: { minimum: 3, message: "短すぎ" }
end
こうすると、3文字以上でないと新規作成できない。※短すぎと出る
Validationルールのつけかたと、ルールはいくつでも追加できるということを記憶しておくこと。
16.編集フォームを作ってみる。
編集に関するルーティングは、
→
編集フォームを提示するのは「projects/:id/edit」
→editアクションを作ればよい。
また、実際に更新するときにはupdateというアクションもいるので、
これも創る必要あるよ。
まずはリンクからつくります。
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li>
<%= link_to project.title, project_path(project.id) %>
<%= link_to "[Edit]", edit_project_path(project.id) %> # ここ追記したで
</li>
<% end %>
</ul>
<p><%= link_to "Add New", new_project_path %></p>
これで編集のためのリンクができる
次にアクションをつくる。
app/controllers/projects_controller.rb で、「def edit …」としましょう。
class ProjectsController < ApplicationController
def index
@projects = Project.all
end
def show
@project = Project.find(params[:id])
end
def new
@project = Project.new
end
def create
@project = Project.new(project_params)
if @project.save
redirect_to projects_path
else
render 'new'
end
end
# ここからが追記箇所
def edit
@project = Project.find(params[:id])
end
# ここまで
private
def project_params
params[:project].permit(:title)
end
end
この追記により、編集対象が取れるようになる。
これでフォームつくる。
→app/views/projects の new.html.erb を複製して edit.html.erb を作る。
→といっても、h1をEditにへんこうするだけ。
これで、Editのリンクを押すと画面が表示されるようになった。
ちなみに、
新規作成画面では、Create Project
編集画面では→Update Project
と、なっている。
ここらへんの仕組みはRailsがスマートに作ってくれている。
次は編集と保存を試していきますー
17.データ更新していくで
まずはupdateのアクションを作ります。
# 追記した部分
def update
@project = Project.find(params[:id])
if @project.update(project_params)
redirect_to projects_path
else
render 'edit'
end
正常に更新された場合はプロジェクト一覧に戻って。
エラーが出た場合は、編集画面に戻ってなおかつエラーメッセージがでる。
→ほんまや
上手く動いてるのはええけど、
newとeditってフォーム同じやんな。
→書き方変更するで※DRYやで
→それ共通化っていうねんで。
edit.html.erbの共通の部分をコピーして
書き換える
<h1>Edit</h1>
<%= render 'form' %>
newの方も同じように
<h1>Add New</h1>
<%= render 'form' %>
そして共通部分のファイルを創る
→パーシャルと言い、renderで呼び出すためには、「_」をつけて、
その名前をつける。
今回の場合だと「_form.html.erb」とする
その中身は共通して表示させたい部分を入れる。
<%= form_for @project do |f| %>
<p>
<%= f.label :title %><br>
<%= f.text_field :title %>
<% if @project.errors.any? %>
<%= @project.errors.messages[:title][0] %>
<% end %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
これで、共通部分のファイルができた
試しに実行してみると、編集と新規作成画面できちんと同じ内容がひょうじされている。
18.データを削除しよう!
destroyというアクションをつくっていく。
まずはリンクをつくる。
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li>
<%= link_to project.title, project_path(project.id) %>
<%= link_to "[Edit]", edit_project_path(project.id) %>
<%= link_to "[Delete]", project_path(project.id), method: :delete, data: { confirm: "are you sure?" } %> # ここが追記部分。
</li>
<% end %>
</ul>
<p><%= link_to "Add New", new_project_path %></p>
「method: :delete」とすると、destroyアクションに結びつけてくれます。
また、そうした後にコンファームという確認画面を作りたいから
その後に「data: { confirm: “are you sure?” }」を入れる。
きちんと確認画面がでるようになったら
次はdestroyアクションを作成していきます。
いつもどおり、app/controllers/projects_controller.rb で
# 追記箇所
def destroy
@project = Project.find(params[:id])
@project.destroy
redirect_to projects_path
end
これで削除したあとに、一覧に戻るようになる。
削除するためのリンクとControllerの処理の仕方。
19.before_actionを使ってみよう!
今回はapp/controllerにある重複したコードをなくしていく。
重複してる箇所はどこか?
「@project = Project.find(params[:id])」のかしょ
→このControllerの中のアクションにある共通のものをまとめて処理するためのものがある。
→それがbefore_actionというもので、そこで定義したものに関しては、どのアクションでもそのアクションを実行する前に必ず実行されるものです。
共通処理をまとめて書着直したのがこちら
class ProjectsController < ApplicationController
before_action :set_project, only: [:show, :edit, :update, :destroy]
def index
@projects = Project.all
end
def show
end
def new
@project = Project.new
end
def create
@project = Project.new(project_params)
if @project.save
redirect_to projects_path
else
render 'new'
end
end
def edit
end
def update
if @project.update(project_params)
redirect_to projects_path
else
render 'edit'
end
end
def destroy
@project.destroy
redirect_to projects_path
end
private
def project_params
params[:project].permit(:title)
end
def set_project
@project = Project.find(params[:id])
end
end
やり方としては
1. 先頭に「before_action :set_project」という関数をつくる
2. 対象を限定するために「only [:show, :edit, :update, :destroy]」とする。※限定しない場合はいらない。
3. set_project の関数をクラス定義の最後に作る※プライベートのところで良い。他から参照されないため。
4. 共通処理の部分を消す。
スッキリしたコードで実行してみると全てきちんと実行された。
補足として、何らかのアクションの後に共通で実行したい処理を指定できる「after_action」もある。
20.Tasksの設定をしていこう
Projectがほとんどできたので、このProjectそれぞれに対してtaskを登録していく。
Tsskの登録
→Projectの詳細画面で追加
→一覧を表示
→削除
まずはサーバーを止めてModelをつくる。
rails g model Task title done:boolean project:references
「rails g model Task」としてあげましょう。
続けて「title」として、タイトルを持たせます。
続けて「done:boolean」として、それが終わったかどうかを boolean(真偽型)で管理。
続けて「project:references」とすると、Task を登録する時に Project に紐付いた形で Model を作ってくれる。
これで、マイグレーションファイルとTask用のModelができた。
Taskに関してはdbにマイグレーションファイルができているので確認する。
そして、defaultを設定する。
class CreateTasks < ActiveRecord::Migration
def change
create_table :tasks do |t|
t.string :title
t.boolean :done, default: false # defaultの設定を行う
t.references :project, index: true
t.timestamps null: false
end
add_foreign_key :tasks, :projects
end
end
なぜdefaultをfalseにするかというと、Taskを登録した瞬間にはTaskは完了していないため、done(終了しているかどうかの)デフォルト値はfalseになる。
rake db:migrate
マイグレーションファイルが完成したらマイグレーションを実行すること。
これでデータベースが完成。
次はコントローラーを作成。
rails g controller Tasks
これで作成完了。
次はルーティングの作成。
21.Associationの設定やで
ルーティングの前に、Modelの関連付けをやっておく
今Model(app/models)にはtask.rbとproject.rbがある。
class Task < ActiveRecord::Base
belongs_to :project
end
task.rbを確認すると、
belongs_to :project
と、記述されてる
これは、Projectに属しているという意味で、
Model作成時に、「project:references」と記載したのが反映されている。
しかし、project.rbは、taskに紐付いていないので
記載してあげないといけない。
class Project < ActiveRecord::Base
has_many :tasks # この部分追記
validates :title,
presence: { message: "入力してください"},
length: { minimum: 3, message: "短すぎ" }
end
関連性は、Project 1 つに対して Task が複数あるので、「has_many: tasks」と書く。
そうすると、色々あとから処理をしていく時に、
Project は Task に 1 対多の関係で結びついているとなる。
※必須。
次はルーティング。
config/routes.rb を見ていきましょう。
Rails.application.routes.draw do
resources :projects do
resources :tasks, only: [:create, :destroy]
end
root 'projects#index'
Project に関連した形で Task のルーティングを作っていく。
「resources :projects do …」の中に「resources :tasks」とすれば OK です。
今回は Project の一覧の中に Task を書くので、必要となるルーティングは新しく作るときと削除するときだけです。
→onlyの書き方を使う。
「resources :tasks, only: [:create, :destroy]」という書き方にしておいてください。
それができたら、下記コマンドを実行。
rake routes
Prefix Verb URI Pattern Controller#Action
project_tasks POST /projects/:project_id/tasks(.:format) tasks#create
project_task DELETE /projects/:project_id/tasks/:id(.:format) tasks#destroy
projects GET /projects(.:format) projects#index
POST /projects(.:format) projects#create
new_project GET /projects/new(.:format) projects#new
edit_project GET /projects/:id/edit(.:format) projects#edit
project GET /projects/:id(.:format) projects#show
PATCH /projects/:id(.:format) projects#update
PUT /projects/:id(.:format) projects#update
DELETE /projects/:id(.:format) projects#destroy
root GET / projects#index
task に関するものは create と destroy だけが定義されているのがわかるかと思います。
URL は、projects/:project_id/tasks で新規作成。
projects/:project_id/tasks/:id で削除。
22.Tasksの新規作成フォームを作ろう!
まずサーバーを立ち上げる。
Taskの詳細がほしいのでProjectの詳細に入れていく。
まだデータがないので表示はされない、ロジックだけ作成する。
app/views/projects/show.html.erb の h1 の下に一覧を入れる。
<h1><%= @project.title %></h1>
<ul>
<% @project.tasks.each do |task| %>
<li><%= task.title %></li>
<% end %>
<li>
<%= form_for [@project, @project.tasks.build] do |f| %>
<%= f.text_field :title %>
<%= f.submit %>
<% end %>
</li>
</ul>
タスク一覧
→project の中の task は「@project.tasks」で取ることができる。
→それに対してループを回す。
→「
- <% @project.tasks.each do |task| %> …」とする。
タスクがなかった場合の新規作成のフォームが必要だから。
Project に関連しつつ Task を作っていく。
※決まり文句的に覚えておいて頂きたいのですが)
「<%= form_for [@project, @project.tasks.build] do |f| %>」とすると、この Project と Task の受け皿ができます。
あとはテキストエリアとサブミットボタンを追加してOK。
次はcreateのアクションをTaskに創る
23.Taskを保存していこう
Task用のフォームができたから、Taskのcreateアクションを創る
→フォームから渡ってくるのはproject_idなのでそれを使ってControllerでいろいろやってく
app/controllers の中に tasks_controller.rb が作られています。
class TasksController < ApplicationController
def create
@project = Project.find(params[:project_id])
@task = @project.tasks.create(task_params)
redirect_to project_path(@project.id)
end
private
def task_params
params[:task].permit(:title)
end
end
「def create …」の中で、projectは
「@project = Project.find(params[:project_id])」で引っ張れる。
その Project 情報を元に Task を作っていく。
「@task = project.tasks.create(task_params)」
追加し終わったら詳細画面が表示されるようにする。
また、privateのところを
「def project_params …」を「def task_params …」に変更、
中身は「params[:task].permit(:title)」とすれば OK かと思います。
次はバリデーションを設定する。
エラーメッセージは表示させず、空欄だとNGにする。
class Task < ActiveRecord::Base
belongs_to :project
validates :title, presence: true;
end
task.rbに上記を記載することでOK
24.Taskの削除を行ないます。
作ったタスクを削除する機能追加
app/views/projects の show.html.erb を編集
<% @project.tasks.each do |task| %>
<li><%= task.title %>
<%= link_to "[Delete]", project_task_path(task.project_id, task.id), method: :delete, data: { confirm: "are you sure?" } %>
</li>
<% end %>
deleteリンクはコピーして流用
リンク先は、project_task_path
パラメーターとしてProject の id と Task の id が必要。
あとはdestroyメソッドをつくる。
def destroy
@task = Task.find(params[:id])
@task.destroy
redirect_to project_path(params[:project_id])
end
projects_controller.rbからコピーして流用。
「@task = Task.find(params[:id])」とする。
その後「@task.destroy」とする。
その後の飛ばし先はProject の詳細画面なので、
「redirect_to project_path(params[:project_id])」とする。
これで削除できーる。
25.check_box_tagをつかってチェックボックスつくーる
タスクといえばチェックボックス。
→実装していきましょう。
とりあえずここ、まずはViewでチェックボックスをつける
app/views/projects の show.html.erb
<%= check_box_tag '', '', task.done, {'data-id' => task.id, 'data-project_id' => task.project_id} %>
上記を追記。
フォームではなくチェックボックスが欲しい場合は
check_box_tagヘルパーを使用する。
idやvalueは必要ない。
最初の2つの引数は空白でOK
それがチェックされているかどうかは3番目の引数
→普通は、true/falesだが、task.doneでOK
その後にHTMLに渡したい属性をいくらでも追加できる。
今回は後で jQuery をうので、扱いやすいように task.id と project_id を data-id と data-project-id という属性で管理できるようにする。
ここまででチェックボックスが表示される。
ちなみにソースコードを見てみると
<input type="checkbox" name="" id="" value="" data-id="1" data-project_id="1" />
value とか name とかはないが、
data-id 属性と data-project_id 属性で、
Task の id と Project の id が管理できているのがわかる。
これらの値を使ってjQueryのAjaxで命令を投げるのをやってく。
<script>
$(function(){
$("input[type=checkbox]").click(function() {
$.post('/projects/xxx/tasks/xxx/toggle');
});
});
</script>
「$(“input[type=checkbox]“).click(function() { …」として、
チェックボックスがクリックされた場合に次のことをやりなさいという命令を書く。
→Ajax で POST を投げなさい、とする。
投げる先は「$.post(‘/projects/xxx/tasks/xxx/toggle’);」として、今回は toggle というアクションを付けてみる。
→クリックする度に、値が true と false で切り替わるものを作る。
POST先(「xxx」の部分)を入れるのは次回
26. toggleアクションを作ろう
チェックボックスをクリックしたときにPOSTが飛ぶようにする
<script>
$(function(){
$("input[type=checkbox]").click(function() {
$.post('/projects/'+$(this).data('project_id')+'/tasks/'+$(this).data('id')+'/toggle');
});
});
</script>
POST 先に Project の id と Task の id を入れたいので、
上の方でデータ属性を使ったので、次のようにする。
→
「’/projects/’+$(this).data(‘project_id’)+’/tasks/’+$(this).data(‘id’)+’/toggle’」とすれば OK かと思います。
この部分に命令を投げるが、ルーティングの定義がないのでまず定義を行う
→config/routes.rb
post 'projects/:project_id/task/:id/toggle' => 'tasks#toggle'
上記を追記。
特定の命令を特定のアクションに結び付けたい場合は、次のような書き方
GET ではなく POST で渡しているので、まず「post」
続けて「’projects/:project_id/tasks/:id/toggle’」とする。
これが jQuery から投げられるので、
続けて「=> ‘tasks#toggle’」としてtasks#toggle に渡す。
次にtasks_controller.rbでtoggleを創る。
def toggle
@task = Task.find(params[:id])
@task.done = !@task.done
@task.save
end
priveteの前につくる
toggle では、task.done が true だったら false、false だったら true に切り替えれば OK 。
「@task = Task.find(params[:id])」とし、
その後に「@task.done = !@task.done」として、
task.done を task.done の反対にする。
そして「@task.save」とすれば OK。
ルーティングを確認する。
rake routes
上手くtoggleができているので動作確認を次に行う。
27.Tasksの状況を切り替えよう
動作確認のためサーバーを起動し、
プロジェクトを選び、タスクを作成し、チェックを入れると
javascriptConsoleにエラーが出ている。
エラー内容を見るとrouteがマッチしていないよう。
routes.rbを確認
post '/projects/:project_id/tasks/:id/toggle' => 'tasks#toggle'
最初のprojectsの前に、「/」を追記。
再度試すと、今度はテンプレートがないと出る
→今回はtoggleをしたとしても、画面が遷移するわけでないので、
templateは使わない設定にしないといけない。
app/controllers/tasks_controller.rb の toggle のところで設定する。
def toggle
render nothing: true # 追記
@task = Task.find(params[:id])
@task.done = !@task.done
@task.save
end
この追記で「このアクションに関してはテンプレートは使いませんよ」という意味で、「render nothing: true」と設定する。
これで再度チェックボックスにチェック入れるとエラーはでない。
こういった具合にちゃんと進捗(done なのか、そうではないのか)をうまく管理できているのがわかるかと思います。
28.Tasksの数を表示させる。
せっかくなので、Project 一覧の所で Task の数をタイトルの後ろに表示してみる。
Viewをいじる
app/views/projects/index.html.erb ですね。
<h1>Projects</h1>
<ul>
<% @projects.each do |project| %>
<li>
<%= link_to project.title, project_path(project.id) %> (<%= project.tasks.count %>)
<%= link_to "[Edit]", edit_project_path(project.id) %>
<%= link_to "[Delete]", project_path(project.id), method: :delete, data: { confirm: "are you sure?" } %>
</li>
<% end %>
</ul>
<p><%= link_to "Add New", new_project_path %></p>
タイトルの後ろに「()」を付けて、その中に Task の数を表示
「<%= project.tasks.count %>」とすれば表示される
さて、最後に残りのタスク数も確認できるようにする
方法はいくつかあるけど、Modelsに書くのがおすすめ
class Task < ActiveRecord::Base
belongs_to :project
validates :title, presence: true
scope :unfinished, -> { where(done: false) } # 追記箇所
end
Models の中に検索条件のようなものを付けておくことができます。
app/models/task.rb の中で「scope :unfinished」として unfinished という scope を定義する。
書き方がちょっと特殊で、
「, -> { where(done: false) }」のように式を書く
done が false のものを検索条件として保存しなさいという意味
これをどこでも使うことができるので、例えば index.html.erb でつかう。
<%= link_to project.title, project_path(project.id) %> (<%= project.tasks.unfinished.count %>/<%= project.tasks.count %>)
「<%= project.tasks.unfinished.count %>」とすると、Task の中で終わっていないものの個数を出す。
以上でタスクアプリの作り方が終了。
他にも色々細かい所を詰めることができますが、Model、View、Controller、ルーティング、DB などを使いながら Rails を使ってアプリケーションを作っていく手順を紹介してきましたので、参考にしてみてください。