タスク管理アプリを作ってみよう(続き)
1. 前置き
1. 前提・事前作業
- こっちの投稿
- 例によってドットインストールの写経
- #19 before_actionを使ってみようから実施
2. before_actionを使ってみよう
- Controllerの整備
-
/home/vagrant/taskApp/app/Constollers
のprojects_constroller.rb
を弄る。 - 下記コードが重複しているので整備する
ruby
@project = Project.find(params[:id])
-
before_action
を活用する - Actionで必ず実行されるべきことを
before_action
に定義することで、コードの重複を防ぐ
ruby
class ProjectsController < ApplicationController
# 共通処理を定義(各Actionでは`set_project` が呼ばれますよ、という宣言)
# 別途 `set_project` という関数を定義する
# 全Actionに適用するわけではないので、 `only` で実行するActionを限定する
before_action :set_project, only: [:show, :edit, :update, :destroy]
# 処理いろいろ・・・
private
# project_params を定義
def project_params
# projectでわたってきたもののうち、titleだけ使用
params[:project].permit(:title)
end
# before_actionで定義した処理の実装
def set_project
@project = Project.find(params[:id])
end
end
3. Tasksを設定していこう
-
機能を拡張する
-
projectに対してtaskを追加できるようにする
-
一旦railsをとめて、Modelを作成する
-
下記コマンドは以下の意味を持つ
-
Task
というモデルを作る -
title
というフィールドを持つ(String型は型の明記不要) -
done
というフィールドをboolean
型で持つ -
project
というフィールドを参照する
rails g model Task title done:boolean project:references
- でけた
invoke active_record
create db/migrate/20140426085349_create_tasks.rb
create app/models/task.rb
invoke test_unit
create test/models/task_test.rb
create test/fixtures/tasks.yml
- 生成されたマイグレーションファイルをチェック
-
/home/vagrant/taskApp/db/migrate
の~~~_create_tasks.rb
を開く -
t.boolean :done
はデフォルトでfalseにしておく
ruby
class CreateTasks < ActiveRecord::Migration
def change
create_table :tasks do |t|
t.string :title
t.boolean :done, default: false
t.references :project, index: true
t.timestamps
end
end
end
- マイグレーションファイルを読み込んで反映させる
rake db:migrate
- Controlloerをジェネレートする
rails g controller Tasks
Associationの設定をしよう
- ModelとかControllerとかできたので、ルーティングとか引き続きやっていく
- その前にModelの関連付けを行う
-
/home/vagrant/taskApp/app/models
のtask.rb
を見てみると、「projectに属してるよ」という明記がある。 -
/home/vagrant/taskApp/app/models
のproject.rb
も同様に、関連付け情報を記述する。
ruby(task.rb)
class Task < ActiveRecord::Base
belongs_to :project
end
ruby(project.rb)
class Project < ActiveRecord::Base
# taskと1対多で紐付く
has_many :tasks
# 必須制御
# 「project」を未入力の状態では保存できなくなる
# validates :title, presence: true
# エラーメッセージを定義(メッセージは独自定義)
validates :title,
presence: { message: "入力してください"},
length: {minimum: 3, message: "短すぎます"}
end
- ルーティングを行う
-
/home/vagrant/taskApp/config
のroutes.rb
を弄る
ruby(before)
resources :projects # Projectに関するルーティングを自動生成
ruby(after)
resources :projects do
resources :tasks, only: [:create, :destroy]
end
-
rake
で変更を反映
rake routes
- こんな感じになった
-
only: [:create, :destroy]
とすることで生成範囲を限定
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
4. Tasksの新規作成フォームを作ろう
- とりあえずさっき止めたサーバを実行
rails s
- ロジックを作成する
-
/home/vagrant/taskApp/app/views/projects
のshow.html.erb
を弄る。
ERB(show.html.erb)
<h1><%= @project.title %></h1>
<ul>
<!-- projectに紐付くtaskがあるだけループする -->
<% @project.tasks.each do |task| %>
<li>
<!-- taskのtitleを表示 -->
<%= task.title %>
</li>
<% end %>
<!-- 新規タスク登録フォーム -->
<li>
<%= form_for [@project, @project.tasks.build] do |f| %>
<%= f.text_field :title %>
<%= f.submit %>
<% end %>
</li>
</ul>
- 下記の通りタスク登録用のフォームが表示された(まだタスクは登録してないので登録フォームの1行だけ表示される)
5. Tasksを保存していこう
-
create
Actionを作っていく - ルーティングを確認
project_tasks POST /projects/:project_id/tasks(.:format) tasks#create
- フォームからわたってくるのはproject_idなので、それを使ってControllerを色々やっていく
-
/home/vagrant/taskApp/app/controllers
のtasks_controller.rb
を弄る
ruby
class TasksController < ApplicationController
# createアクションを追加
def create
# 画面からわたってきたIDからprojectをfindする
@project = Project.find(params[:project_id])
# taskを登録
@task = @project.tasks.create(tasks_params)
# 遷移先はプロジェクト詳細画面
redirect_to project_path(@project.id)
end
private
# task_params を定義
def tasks_params
# taskでわたってきたもののうち、titleだけ使用
params[:task].permit(:title)
end
end
- 動作確認。入力して、サブミットすると...
- 追加された
- さらに、バリデーションを追加する
- 必須入力チェックを追加
-
/home/vagrant/taskApp/app/models
のtask.rb
を弄る
ruby
class Task < ActiveRecord::Base
belongs_to :project # projectに属してるよ。という情報
# 必須チェック メッセージの設定はなし
validates :title,
presence: true
end
- 未入力状態でサブミットしても、データは登録されないでリダイレクトされる。
6. Tasksの削除をしてみよう
- 登録したタスクを削除する
-
/home/vagrant/taskApp/app/views/projects
のshow.html.erb
を弄る - の前に、
rake routes
でルーティングを確認
project_task DELETE /projects/:project_id/tasks/:id(.:format) tasks#destroy
-
project_id
とtask_id
が必要らしいので取得するようにする
ERB(show.html.erb)
<h1><%= @project.title %></h1>
<ul>
<!-- projectに紐付くtaskがあるだけループする -->
<% @project.tasks.each do |task| %>
<li>
<!-- taskのtitleを表示 -->
<%= task.title %>
<!-- 削除リンク(taskのプロジェクトIDとtaskIDを取得) -->
<%= link_to "[Delete]", project_task_path(task.project_id, task.id), method: :delete, data: {confirm: "are you sure?"} %>
</li>
<% end %>
<!-- 新規タスク登録フォーム -->
<li>
<%= form_for [@project, @project.tasks.build] do |f| %>
<%= f.text_field :title %>
<%= f.submit %>
<% end %>
</li>
</ul>
- これでとりあえず削除リンクが追加される。
-
さらにControllerにActionを追加する。
-
/home/vagrant/taskApp/app/views/controllers
のtasks_controller.rb
を弄る -
ルーティング情報によると
project_task DELETE /projects/:project_id/tasks/:id(.:format) tasks#destroy
- task_idがわたってきているので、これを使えばOK
ruby(tasks_controller.rb)
class TasksController < ApplicationController
# createアクションを追加
def create
# 画面からわたってきたIDからprojectをfindする
@project = Project.find(params[:project_id])
# taskを登録
@task = @project.tasks.create(tasks_params)
# 遷移先はプロジェクト詳細画面
redirect_to project_path(@project.id)
end
# destroyアクションを追加
def destroy
@task = Task.find(params[:id])
@task.destroy
redirect_to project_path(params[:project_id])
end
private
# task_params を定義
def tasks_params
# taskでわたってきたもののうち、titleだけ使用
params[:task].permit(:title)
end
end
- Deleteリンクを押下するとメッセージが上がるので、
- OKすると...
- 消せた