# 現場Railsの復習アプリを作ろう
## アプリケーション作成の準備
### Bootstrapの導入をしよう
- Bootstrapを使えるように設定してください。
- `app/views/layouts/application.html.erb`を下記で書き換えてください。
```erb
<!DOCTYPE html>
<html>
<head>
<title><%= t('title') %></title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<div class="app-title navbar navbar-expand-md navbar-light bg-light">
<div class="navbar-brand"><%= t('title')%></div>
</div>
<div class="container p-2">
<%= yield %>
</div>
</body>
</html>
```
### I18nの設定をしよう
- `config/locales/hi.yml`を作成して下記を記入してください
```yml
hi:
activerecord:
errors:
messages:
record_invalid: '𓂋𓇋𓎡𓍯𓂋𓂧_𓇋𓈖𓆑𓄿𓃭𓇋𓂧%{errors}'
restrict_dependent_destroy:
has_one: "𓂋𓇋𓋴𓏏𓂋𓇋𓎡𓏏_𓂧𓇋𓏤𓇋𓈖𓂧𓇋𓈖𓏏_𓂧𓇋𓋴𓏏𓂋𓍯𓇋%{record}"
has_many: "𓂋𓇋𓋴𓏏𓂋𓇋𓎡𓏏_𓂧𓇋𓏤𓇋𓈖𓂧𓇋𓈖𓏏_𓂧𓇋𓋴𓏏𓂋𓍯𓇋%{record}"
formats:
default: "%Y/%m/%d"
long: "%Y𓇋%m𓅓%d𓂧(%a)"
short: "%m/%d"
errors:
format: "%{attribute}%{message}"
messages:
accepted: 𓄿𓎡𓎡𓇋𓏤𓏏𓇋𓂧
blank: 𓃀𓃭𓄿𓈖𓎡
confirmation: 𓎡𓍯𓈖𓆑𓇋𓂋𓅓𓄿𓏏𓇋𓍯𓈖
empty: 𓇋𓅓𓏤𓏏𓇋
equal_to: 𓇋𓏘𓅱𓄿𓃭_𓏏𓍯%{count}
even: 𓇋𓆑𓇋𓈖
exclusion: 𓇋𓎡𓋴𓎡𓃭𓅱𓋴𓇋𓍯𓈖
greater_than: 𓎼𓂋𓇋𓄿𓏏𓇋𓂋_𓏏𓎛𓄿𓈖%{count}
greater_than_or_equal_to: 𓎼𓂋𓇋𓄿𓏏𓇋𓂋_𓏏𓎛𓄿𓈖_𓍯𓂋_𓇋𓏘𓅱𓄿𓃭_𓏏𓍯%{count}
inclusion: 𓇋𓈖𓎡𓃭𓅱𓋴𓇋𓍯𓈖
invalid: 𓇋𓈖𓆑𓄿𓃭𓇋𓂧
less_than: 𓃭𓇋𓋴𓋴_𓏏𓎛𓄿𓈖%{count}
less_than_or_equal_to: 𓃭𓇋𓋴𓋴_𓏏𓎛𓄿𓈖_𓍯𓂋_𓇋𓏘𓅱𓄿𓃭_𓏏𓍯%{count}
model_invalid: '𓅓𓍯𓂧𓇋𓃭_𓇋𓈖𓆑𓄿𓃭𓇋𓂧: %{errors}'
not_a_number: 𓈖𓍯𓏏_𓄿_𓈖𓅱𓅓𓃀𓇋𓂋
not_an_integer: 𓈖𓍯𓏏_𓄿𓈖_𓇋𓈖𓏏𓇋𓎼𓇋𓂋
odd: 𓍯𓂧𓂧
other_than: 𓍯𓏏𓎛𓇋𓂋_𓏏𓎛𓄿𓈖%{count}
present: 𓏤𓂋𓇋𓋴𓇋𓈖𓏏
required: 𓂋𓇋𓏘𓅱𓇋𓂋𓇋𓂧
taken: 𓏏𓄿𓎡𓇋𓈖
too_long: 𓏏𓍯𓍯_𓃭𓍯𓈖𓎼%{count}
too_short: 𓏏𓍯𓍯_𓋴𓎛𓍯𓂋𓏏%{count}
wrong_length: 𓅱𓂋𓍯𓈖𓎼_𓃭𓇋𓈖𓎼𓏏𓎛%{count}
helpers:
select:
prompt: 𓋴𓇋𓃭𓇋𓎡𓏏
submit:
create: 𓎡𓂋𓇋𓄿𓏏𓇋
submit: 𓋴𓅱𓃀𓅓𓇋𓏏
update: 𓅱𓏤𓂧𓄿𓏏𓇋
time:
am: 𓄿𓅓
formats:
default: "%Y𓇋%m𓅓%d𓂧(%a) %H𓎛%M𓅓%S𓋴 %z"
long: "%Y𓇋%m𓅓%d𓂧 %H:%M"
short: "%m/%d %H:%M"
pm: 𓏤𓅓
title: 𓎛𓇋𓇋𓂋𓍯𓃭𓇋𓄿𓆑
```
- `config/initializers/locale.rb`を作成して下記を記入してください
```ruby
Rails.application.config.i18n.default_locale = :hi
```
## タスクモデルを作成する
### モデルとmigrationファイルの作成
- コマンドを使ってTaskモデルのファイルとtasksテーブル用のmigrationファイルを作成してください
- Taskはnameカラムを持つ(string型, NULLを許可しない, デフォルト値なし)
- Taskはdescriptionカラムを持つ(text型, NULLを許可する, デフォルト値なし)
- 必要があればtasksテーブル用のmigrationファイルを修正してください
- コマンドを実行してデータベースにテーブルを追加してください
### タスクモデルの翻訳設定の追加
- 下記を参考にして`config/locales/hi.yml`に翻訳設定を追加してください(コメントの日本語は書かないでください)
```yml
hi:
activerecord:
errors:
messages:
record_invalid: '𓂋𓇋𓎡𓍯𓂋𓂧_𓇋𓈖𓆑𓄿𓃭𓇋𓂧%{errors}'
restrict_dependent_destroy:
has_one: "𓂋𓇋𓋴𓏏𓂋𓇋𓎡𓏏_𓂧𓇋𓏤𓇋𓈖𓂧𓇋𓈖𓏏_𓂧𓇋𓋴𓏏𓂋𓍯𓇋%{record}"
has_many: "𓂋𓇋𓋴𓏏𓂋𓇋𓎡𓏏_𓂧𓇋𓏤𓇋𓈖𓂧𓇋𓈖𓏏_𓂧𓇋𓋴𓏏𓂋𓍯𓇋%{record}"
#<ここからmodelとattributesを追加してください
models:
task: 𓏏𓄿𓋴𓎡
attributes:
task:
id: 𓇋𓂧
name: 𓈖𓄿𓅓𓇋
description: 𓂧𓇋𓋴𓎡𓂋𓇋𓏤𓏏𓇋𓍯𓈖
created_at: 𓎡𓂋𓇋𓄿𓏏𓇋𓂧_𓄿𓏏
updated_at: 𓅱𓏤𓂧𓄿𓏏𓇋𓂧_𓄿𓏏
#ここまで>
formats:
default: "%Y/%m/%d"
long: "%Y𓇋%m𓅓%d𓂧(%a)"
short: "%m/%d"
〜これ以下は省略しています〜
```
### タスクモデルのバリデーション設定
- nameは空(nilや空白)では登録できない用にしてください
- nameは100文字以上の文字数を登録できない用にしてください
- descriptionは1000文字以上の文字数を登録できない用にしてください
### 確認
- rails consoleを使ってTaskモデルのインスタンスが作成できるか確認してみましょう
- `Task.new`
- rails consoleを使ってTaskモデルのバリデーションがちゃんと設定されているか確認してみましょう(ファラオしか読めませんが雰囲気で)
```ruby
task = Task.new(name: 'a'*101, description: 'b'*1001)
task.valid?
task.errors.full_messages
```
## コントローラーの作成とビュー
### タスクモデルの翻訳設定の追加
- 下記を参考にして`config/locales/hi.yml`に翻訳設定を追加してください(コメントの日本語は書かないでください)
```yml
hi:
activerecord:
errors:
messages:
record_invalid: "𓂋𓇋𓎡𓍯𓂋𓂧_𓇋𓈖𓆑𓄿𓃭𓇋𓂧%{errors}"
restrict_dependent_destroy:
has_one: "𓂋𓇋𓋴𓏏𓂋𓇋𓎡𓏏_𓂧𓇋𓏤𓇋𓈖𓂧𓇋𓈖𓏏_𓂧𓇋𓋴𓏏𓂋𓍯𓇋%{record}"
has_many: "𓂋𓇋𓋴𓏏𓂋𓇋𓎡𓏏_𓂧𓇋𓏤𓇋𓈖𓂧𓇋𓈖𓏏_𓂧𓇋𓋴𓏏𓂋𓍯𓇋%{record}"
models:
task: 𓏏𓄿𓋴𓎡
attributes:
task:
id: 𓇋𓂧
name: 𓈖𓄿𓅓𓇋
description: 𓂧𓇋𓋴𓎡𓂋𓇋𓏤𓏏𓇋𓍯𓈖
created_at: 𓎡𓂋𓇋𓄿𓏏𓇋𓂧_𓄿𓏏
updated_at: 𓅱𓏤𓂧𓄿𓏏𓇋𓂧_𓄿𓏏
formats:
default: "%Y/%m/%d"
long: "%Y𓇋%m𓅓%d𓂧(%a)"
short: "%m/%d"
errors:
format: "%{attribute}%{message}"
messages:
accepted: 𓄿𓎡𓎡𓇋𓏤𓏏𓇋𓂧
blank: 𓃀𓃭𓄿𓈖𓎡
confirmation: 𓎡𓍯𓈖𓆑𓇋𓂋𓅓𓄿𓏏𓇋𓍯𓈖
empty: 𓇋𓅓𓏤𓏏𓇋
equal_to: 𓇋𓏘𓅱𓄿𓃭_𓏏𓍯%{count}
even: 𓇋𓆑𓇋𓈖
exclusion: 𓇋𓎡𓋴𓎡𓃭𓅱𓋴𓇋𓍯𓈖
greater_than: 𓎼𓂋𓇋𓄿𓏏𓇋𓂋_𓏏𓎛𓄿𓈖%{count}
greater_than_or_equal_to: 𓎼𓂋𓇋𓄿𓏏𓇋𓂋_𓏏𓎛𓄿𓈖_𓍯𓂋_𓇋𓏘𓅱𓄿𓃭_𓏏𓍯%{count}
inclusion: 𓇋𓈖𓎡𓃭𓅱𓋴𓇋𓍯𓈖
invalid: 𓇋𓈖𓆑𓄿𓃭𓇋𓂧
less_than: 𓃭𓇋𓋴𓋴_𓏏𓎛𓄿𓈖%{count}
less_than_or_equal_to: 𓃭𓇋𓋴𓋴_𓏏𓎛𓄿𓈖_𓍯𓂋_𓇋𓏘𓅱𓄿𓃭_𓏏𓍯%{count}
model_invalid: "𓅓𓍯𓂧𓇋𓃭_𓇋𓈖𓆑𓄿𓃭𓇋𓂧: %{errors}"
not_a_number: 𓈖𓍯𓏏_𓄿_𓈖𓅱𓅓𓃀𓇋𓂋
not_an_integer: 𓈖𓍯𓏏_𓄿𓈖_𓇋𓈖𓏏𓇋𓎼𓇋𓂋
odd: 𓍯𓂧𓂧
other_than: 𓍯𓏏𓎛𓇋𓂋_𓏏𓎛𓄿𓈖%{count}
present: 𓏤𓂋𓇋𓋴𓇋𓈖𓏏
required: 𓂋𓇋𓏘𓅱𓇋𓂋𓇋𓂧
taken: 𓏏𓄿𓎡𓇋𓈖
too_long: 𓏏𓍯𓍯_𓃭𓍯𓈖𓎼%{count}
too_short: 𓏏𓍯𓍯_𓋴𓎛𓍯𓂋𓏏%{count}
wrong_length: 𓅱𓂋𓍯𓈖𓎼_𓃭𓇋𓈖𓎼𓏏𓎛%{count}
helpers:
select:
prompt: 𓋴𓇋𓃭𓇋𓎡𓏏
submit:
create: 𓎡𓂋𓇋𓄿𓏏𓇋
submit: 𓋴𓅱𓃀𓅓𓇋𓏏
update: 𓅱𓏤𓂧𓄿𓏏𓇋
time:
am: 𓄿𓅓
formats:
default: "%Y年%m月%d日(%a) %H時%M分%S秒 %z"
long: "%Y𓇋%m𓅓%d𓂧 %H:%M"
short: "%m/%d %H:%M"
pm: 𓏤𓅓
title: 𓎛𓇋𓇋𓂋𓍯𓃭𓇋𓄿𓆑
#<ここから
tasks:
new:
title: 𓎡𓂋𓇋𓄿𓏏𓇋 𓈖𓇋𓅱 𓏏𓄿𓋴𓎡
index_link: 𓇋𓈖𓂧𓇋𓎡𓋴
create:
success_create_task: 𓎡𓂋𓇋𓄿𓏏𓇋𓂧 𓏏𓄿𓋴𓎡
failure_create_task: 𓆑𓄿𓇋𓃭𓅱𓂋𓇋 𓎡𓂋𓇋𓄿𓏏𓇋 𓏏𓄿𓋴𓎡
index:
title: 𓏏𓄿𓋴𓎡 𓇋𓈖𓂧𓇋𓎡𓋴
new_link: 𓈖𓇋𓅱
edit_link: 𓇋𓂧𓇋𓏏
destroy_link: 𓂧𓇋𓋴𓏏𓂋𓍯𓇋
delete_confirm_message: 𓂧𓇋𓋴𓏏𓂋𓍯𓇋 𓏏𓄿𓋴𓎡 𓍯𓎡
show:
title: 𓏏𓄿𓋴𓎡 𓂧𓇋𓏏𓄿𓇋𓃭
index_link: 𓇋𓈖𓂧𓇋𓎡𓋴
edit_link: 𓇋𓂧𓇋𓏏
destroy_link: 𓂧𓇋𓋴𓏏𓂋𓍯𓇋
delete_confirm_message: 𓂧𓇋𓋴𓏏𓂋𓍯𓇋 𓏏𓄿𓋴𓎡 𓍯𓎡
edit:
title: 𓇋𓂧𓇋𓏏 𓏏𓄿𓋴𓎡
index_link: 𓇋𓈖𓂧𓇋𓎡𓋴
update:
success_update_task: 𓅱𓏤𓂧𓄿𓏏𓇋𓂧 𓏏𓄿𓋴𓎡
failure_update_task: 𓆑𓄿𓇋𓃭𓅱𓂋𓇋 𓅱𓏤𓂧𓄿𓏏𓇋 𓏏𓄿𓋴𓎡
destroy:
deleted_task: 𓂧𓇋𓃭𓇋𓏏𓇋𓂧 𓏏𓄿𓋴𓎡
#ここまで>
```
### Tasksコントローラー用のルーティングの設定
- task用のルーティング(index show new create edit update destroy)を追加してください
- rootパス(/)用のルーティングをTasksコントローラーのindexアクションに設定してください
#### 確認
- `localhost:3000/rails/info/routes`にアクセスしてルーティングが正しく設定されているか確認しましょう
### Tasksコントローラーの作成
- コマンドを使ってTasksController用のファイルとTask用のviewのディレクトリを作成してください
### Task一覧表示用のアクションを追加
- TasksControllerに一覧表示用のアクションを追加してください
- TasksControllerの一覧表示用のアクションに対応するviewファイルを用意して下さい(中身は空でも大丈夫です)
#### 確認
- `localhost:3000/`にアクセスしてエラーが出ないか確認しましょう
- `localhost:3000/tasks`にアクセスしてエラーが出ないか確認しましょう
### Task新規作成用のアクションを追加
- TasksControllerに新規作成(from表示用)のアクションを追加してください(下記ビューの表示にはTaskモデルのインスタンスが入ったインスタンス変数(@task)が必要です)
- TasksControllerの新規作成用のアクションに対応するviewファイルを用意して下記を記入してください
```erb
<h1><%= t('.title') %></h1>
<div class="nav justify-content-end">
<%= link_to t('.index_link'), tasks_path, class: 'nav-link' %>
</div>
<%= form_with model: @task, local: true do |f| %>
<div class='form-group'>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class='form-group'>
<%= f.label :description %>
<%= f.text_field :description, class: 'form-control', row: 5 %>
</div>
<%= f.submit nil, class: 'btn btn-primary' %>
<% end %>
```
### Task登録用のアクションを追加
- Task登録用のアクションを追加してください
- Taskの登録に成功したときはタスク一覧画面に遷移するようにしてください
- Taskの登録に成功したときにフラッシュメッセージが表示されるようにflashの情報を渡してください(`notice: t('.success_create_task')`)
- Taskの登録に失敗したときはrenderで`app/views/tasks/new.html.erb`ファイルを表示するようにしてください
- Taskの登録に失敗した時にフラッシュメッセージが表示されるようにflashの情報を渡してください(`flash.now[:alert] = t('.failure_create_task')`)
- paramsで渡ってきたnameとdescriptionの情報はストロングパラメーターを使用してまとめてインスタンスに渡せるように`task_params`メソッドを定義して利用してください
#### flashメッセージの表示場所を作成
- `app/views/layouts/application.html.erb`を下記のように編集してください(日本語のコメントは追加しないでください)
```erb
〜省略〜
<body>
<div class="app-title navbar navbar-expand-md navbar-light bg-light">
<div class="navbar-brand"><%= t('title') %></div>
</div>
<div class="container p-2">
<!-- ここから追加してください -->
<% if flash.notice.present? %>
<div class="alert alert-success">
<%= flash.notice %>
</div>
<% elsif flash.alert.present? %>
<div class="alert alert-danger">
<%= flash.alert %>
</div>
<% end %>
<!-- ここまで追加してください -->
<%= yield %>
</div>
</body>
</html>
```
#### 確認
- 実際にTaksを作成して登録と失敗が正常に動いているか確認してください
### Task一覧表示機能を追加
- Task一覧表示用のアクションを追加してください
- `app/views/tasks/index.html.erb`の記述を全て下記に置き換えてください
```erb
<h1><%= t('.title') %></h1>
<%= link_to t('.new_link'), new_task_path, class: 'btn btn-primary' %>
<div class='mt-3'>
<table class='table table-hover'>
<thead class='thead-default'>
<tr>
<th><%= Task.human_attribute_name(:name) %></th>
<th><%= Task.human_attribute_name(:created_at) %></th>
<th></th>
</tr>
</thead>
<tbody>
<% @tasks.each do |task| %>
<tr>
<td><%= link_to task.name, task_path(task) %></td>
<td><%= l(task.created_at, format: :short) %></td>
<td>
<%= link_to t('.edit_link'), edit_task_path(task), class: 'btn btn-primary mr-3' %>
<%= link_to t('.destroy_link'), task_path(task), method: :delete, data: { confirm: t('.delete_confirm_message') }, class: 'btn btn-danger' %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
```
#### 確認
- `localhost:3000/`にアクセスしてタスク一覧が表示されているか確認してください
### Task詳細表示機能を追加
- Task詳細表示用のアクションを追加してください
- TasksControllerの詳細表示用のアクションに対応するviewファイルを用意して下記を記入してください
```erb
<h1><%= t('.title')%></h1>
<div class='nav justify-content-end'>
<%= link_to t('.index_link') %>
</div>
<table class='table table-hover'>
<tbody>
<tr>
<th><%= Task.human_attribute_name(:id)%></th>
<td><%= @task.id %></td>
</tr>
<tr>
<th><%= Task.human_attribute_name(:name)%></th>
<td><%= @task.name %></td>
</tr>
<tr>
<th><%= Task.human_attribute_name(:description)%></th>
<td><%= simple_format(h(@task.description), {}, sanitize: false, wrapper_tag: "div") %></td>
</tr>
<tr>
<th><%= Task.human_attribute_name(:created_at)%></th>
<td><%= l(@task.created_at, format: :short) %></td>
</tr>
<tr>
<th><%= Task.human_attribute_name(:updated_at)%></th>
<td><%= l(@task.updated_at, format: :short) %></td>
</tr>
</tbody>
</table>
<%= link_to t('.edit_link'), edit_task_path(@task), class: 'btn btn-primary mr-3' %>
<%= link_to t('.destroy_link'), task_path(@task), method: :delete, data: { confirm: t('.delete_confirm_message') }, class: 'btn btn-danger' %>
```
#### 確認
- `localhost:3000/`に表示されているタスク詳細画面へのリンクからタスク詳細画面に遷移できるか確認してください
- 遷移先のタスク詳細画面でタスクの詳細が表示されているか確認してください
### Task編集機能を追加
- Task編集フォーム表示用のアクションを追加してください
- TasksControllerの編集フォーム表示用のアクションに対応するviewファイルを用意して下記を記入してください
```erb
<h1><%= t('.title') %></h1>
<div class="nav justify-content-end">
<%= link_to t('.index_link'), tasks_path, class: 'nav-link' %>
</div>
<%= form_with model: @task, local: true do |f| %>
<div class='form-group'>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class='form-group'>
<%= f.label :description %>
<%= f.text_field :description, class: 'form-control', row: 5 %>
</div>
<%= f.submit nil, class: 'btn btn-primary' %>
<% end %>
```
### Task更新機能を追加
- Task更新用のアクションを追加してください
- Taskの更新に成功したときはタスク詳細画面に遷移するようにしてください
- Taskの更新に成功したときにフラッシュメッセージが表示されるようにflashの情報を渡してください(`notice: t('.success_update_task')`)
- Taskの更新に失敗したときはrenderで`app/views/tasks/edit.html.erb`ファイルを表示するようにしてください
- Taskの更新に失敗した時にフラッシュメッセージが表示されるようにflashの情報を渡してください(`flash.now[:alert] = t('.failure_update_task')`)
- paramsで渡ってきたnameとdescriptionの情報はストロングパラメーターを使用してまとめてインスタンスに渡せるように`task_params`メソッドを利用してください
#### 確認
- `localhost:3000/`に表示されているタスク編集画面へのリンクからタスク編集画面に遷移できるか確認してください
- 遷移先のタスク編集画面でタスクが編集出来るか確認してください
### Task削除機能を追加
- Task削除用のアクションを追加してください
- Taskの削除は失敗することがないことを前提として`task.destroy!`メソッドを使用してください
- 削除後はTaskの一覧画面に遷移するようにしてください
- 削除後にフラッシュメッセージが表示されるようにflashの情報を渡してください(notice: t('.deleted_task'))
### バリデーションのエラーメッセージを表示出来るようにする
- 下記を参考に`app/views/tasks/new.html.erb`でバリデーションエラーが出た時にエラーメッセージが表示されるようにエラーメッセージ表示欄を追加してください
- 下記を参考に`app/views/tasks/edit.html.erb`でバリデーションエラーが出た時にエラーメッセージが表示されるようにエラーメッセージ表示欄を追加してください
```erb
<h1><%= t('.title') %></h1>
<div class="nav justify-content-end">
<%= link_to t('.index_link'), tasks_path, class: 'nav-link' %>
</div>
<% if @task.errors.present? %>
<ul id='error_explanation'>
<% @task.errors.full_messages.each do |message| %>
<li><%= message%></li>
<% end %>
</ul>
<% end %>
<%= form_with model: @task, local: true do |f| %>
<div class='form-group'>
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class='form-group'>
<%= f.label :description %>
<%= f.text_field :description, class: 'form-control', row: 5 %>
</div>
<%= f.submit nil, class: 'btn btn-primary' %>
<% end %>
```