Rails 6 でTodoApp作る part6

今回は、Taskテーブルにdone:booleanを加えて、todoリスト・doneリストに分ける

※次回予告は確定ではありません。

Taskテーブルにdoneカラムを追加

% rails g migration add_done_to_tasks done:boolean

そして、

  • デフォルトfalse

  • nullもfalse

を追加します

[ Migrationファイル ]

class AddDoneToTasks < ActiveRecord::Migration[6.0]
  def change
    add_column :tasks, :done, :boolean, default: false, null: false
  end
end
% rails db:migrate


Seedを変更

今のサンプルデータには、doneカラムの指定がないのでチョコっといじります。

[ db/seeds.rb ]

(省略)

users = User.all

# todoタスク
15.times do
title = Faker::Beer.brand
description = Faker::Movies::BackToTheFuture.quote
users.each { |user| user.tasks.create!(title: title, description: description) }
end

# doneタスク
15.times do
title = Faker::Beer.brand
description = Faker::Movies::BackToTheFuture.quote
users.each { |user| user.tasks.create!(title: title, description: description, done: true) }
end

doneカラムはdefault: trueとしました。 なので、todoタスク用のサンプルデータは特に変更しません。
doneタスク用のサンプルデータの方にだけdone: trueを指定しておきます。


Routingの編集

/tasks/indexでタスク一覧を表示しているが、

  • /tasks/todo -> todo一覧

  • /tasks/done -> done一覧

となるようにしたい!!


そこで、resourecesメソッドのcollectionを使います。

[ config/routes.rb ]

  resources :tasks do
    collection do
      get :todo, :done
    end
  end

collectionの他にmemberもありますが、今回は一覧ページを作りたいのでcollectionを使いました。

resourecesメソッドについて詳しくは↓

https://pikawaka.com/rails/resources#member%E3%81%A8collection


collectionにより、todoアクションdoneアクションが追加されます。

% rails routes | grep task
                           todo_tasks GET    /tasks/todo(.:format)                                                                    tasks#todo
                           done_tasks GET    /tasks/done(.:format)                                                                    tasks#done
                                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

こんな感じ〜


Controllerの編集

todoアクションとdoneアクションを実装していきます。

[ tasks_controller.rb ]

class TasksController < ApplicationController
  before_action :set_task, only: [:show, :edit, :update, :destroy]

  def index
    @q = current_user.tasks.ransack(params[:q])
    @tasks = @q.result(distinct: true).recent.page(params[:page]).per(10)
  end

  def todo
    @q = current_user.tasks.where(done: false).ransack(params[:q])
    @tasks = @q.result(distinct: true).recent.page(params[:page]).per(10)
  end

  def done
    @q = current_user.tasks.where(done: true).ransack(params[:q])
    @tasks = @q.result(distinct: true).recent.page(params[:page]).per(10)
  end

(省略)

indexの中身をtododoneに移植します。

そして

  • todoには、where(done: falseを加える

  • doneには、where(done: true)を加える

  • 移植が終わったらindexアクションを消す

これで、コントローラの準備はOk


Viewの実装

viewを修正していくう

まずは、tasks/index.html.slim

[ tasks/index.html.slim ]

ul.nav.nav-tabs.mb-3
  li.nav-item = link_to '新規登録', new_task_path, class: 'nav-link'
  li.nav-item = link_to 'Todoリスト', todo_tasks_path, class: 'nav-link'
  li.nav-item = link_to 'Doneリスト', done_tasks_path, class: 'nav-link'
.row.justify-content-end
  = search_form_for @q do |f|
    .form-inline
      = f.label :title_cont, 'タイトル', class: 'my-1 mr-2'
      = f.search_field :title_cont, class: 'my-1 mr-sm-2 form-control'
      = f.submit '検索', class: 'btn btn-primary my-1'
.mb-3
  = paginate @tasks
  = page_entries_info @tasks
table.table
  thead.thead-default
    tr
      th 状況
      th タイトル
      th 登録日
      th 編集日
      th
  tbody
    - @tasks.each do |task|
      tr
        td = task.done? ? 'Done' : 'Todo'
        td = link_to task.title, task
        td = task.created_at
        td = task.updated_at
        td
          = link_to '編集', edit_task_path(task), class: 'btn btn-primary mr-3'
          = link_to '削除', task, method: :delete, data: { confirm: "タスク「#{task.title}」を削除します。よろしいですか?" }, class: 'btn btn-danger'


修正内容

  • h1 タスク一覧を消す

  • navリンク

  • テーブル内th 状況 を追加

  • テーブル内td = task.done? ? 'Done' : 'Todo'を追加

4カ所変更を加えました。


そしたら、2つのファイルを作成

  • app/tasks/todo.html.slim

  • app/tasks/done.html.slim


[ app/tasks/todo.html.slim ]

h1 Todo一覧

= render 'index'

[ app/tasks/done.html.slim ]

h1 Done一覧

= render 'index'


はい。

tasks/index.html.slimをパーシャルにしてやろうか(デーモン)

tasks/index.html.slimをrenameしてtasks/_index.html.slimに変更します


todo一覧 f:id:yukitoku_sw:20200122211513p:plain

done一覧 f:id:yukitoku_sw:20200122211559p:plain

navのactiveのやり方がわからない・・・


次は、tasks/_form.html.slimを変更する

= form_with model: task, local: true do |f|
  .form-check.mb-2
    = f.label :done, class: 'form-check-label' do
      = f.check_box :done, class: 'form-check-input'
      | done
  .form-group
    = f.label :title, 'タイトル'
    = f.text_field :title, class: 'form-control', id: 'task_title'
  .form-group
    = f.label :description, '詳細'
    = f.text_area :description, class: 'form-control', id: 'task_description'
  .form-group
    = f.label :image, '画像'
    = f.file_field :image, class: 'form-control', id: 'task_image'
  = f.submit '登録', class: 'btn btn-success'

form内に.form-checkの部分を追加

ちょっとわかりにくいがまーよし

f:id:yukitoku_sw:20200122212549p:plain

新規登録時にdoneを付ければ、そのままdone一覧に入るし、doneを付けなければtodo一覧に入る。もちろんeditからdoenにチェックを入れればdone一覧に移動する


各ページに貼ったtasks_pathへのリンクを編集する

[ show.html.slim & edit.html.slim ]

.nav.justify-content-end
  - if @task.done?
    = link_to 'Done一覧', done_tasks_path, class: 'nav-link'
  - else
    = link_to 'Todo一覧', todo_tasks_path, class: 'nav-link'

これで、選択した@taskによってリンク先を変更することができる


ヘッダーとnew.html.slimにあるtasks_pathへのリンクには@taskが存在しないので、todo_tasks_pathを指定する


今回は以上です。

ありがとうございました!


次回、タイムゾーンを日本時間にする