railsとreactでtodoアプリを作る！（part1）

# 作成するアプリについて
railsとreactを用いたtodoアプリになります。
https://todo-app-rails-react.herokuapp.com/todoes

https://github.com/taiki-nd/todo-app

（part2）

https://qiita.com/taiki-nd/items/41230829bcedd73bdec4

（part3）

https://qiita.com/taiki-nd/items/14ff0faf685905532e0f

（part4）

https://qiita.com/taiki-nd/items/ccd07c79a2eca0dba716

（part5）

https://qiita.com/taiki-nd/items/b7b9a6a24f0c99458b2a

# 開発環境
* ruby3.0
* rails6.1(rails6以上必須)
* react17.0.2
* vscode

# アプリの作成手順

1. サーバーサイドの実装
    1. アプリの作成
    1. turbolinksの無効化
    1. モデル＆テーブルの作成
    1. 初期データの作成
    1. top#indexの作成
    1. todoes_controllerの作成
    1. ルーティングの設定
    1. application_controllerの設定
    1. application.html.erbに追記
1. フロントサイドの実装
    1. conponentsフォルダの作成
    1. リセットcssと共通cssの設定
    1. index.jsxの記述
    1. App.jsの記述
    1. TodoLists.jsの記述
    1. NewTodo.jsの記述
    1. EditTodo.jsの記述

の手順で進めていきます。早速ですが進めていきましょう！

# アプリ作成
## 1.　サーバーサイドの実装
### 1.1 アプリの作成
ターミナルにて以下を実行してアプリを作成します。
``rails _6.1.4.1_ new todo-app --webpack=react -T -d mysql``
（バージョン、オプション、アプリ名は適宜変更してください。）

```ruby:config/database.yml
default: &default
  adapter: mysql2
  #  encoding: utf8mb4
  encoding: utf8 #このように変更
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password:
  socket: /tmp/mysql.sock
```
``cd todo-app``
としてアプリまで移動し、reactの導入をします。
``yarn add react-router-dom axios styled-components react-toastify``

:::note info
react-router-dom : Reactでのroutingの実現。
axios : サーバとのHTTP通信を行う。
styled-components : CSS in JS のライブラリ。
react-toastify : ポップアップメッセージを容易に作れるライブラリ。
:::

### 1.2 turbolinksの無効化

:::note alert
これを忘れると挙動がおかしくなります
:::

以下のファイルを編集

```html:app/views/layouts/application.html.erb
<!-- <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> -->
<!-- <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> -->
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_pack_tag 'application' %>
```

続いてTurbolinks.start()をコメントアウト

```javascript:app/javascript/packs/application.js
Rails.start()
//Turbolinks.start()
ActiveStorage.start()
```

以上でturbolinksの無効化されました。

### 1.3 モデル＆テーブルの作成
続いてモデルとテーブルの作成をしていきます。
mdoel名はtodoとしましょう。必要カラムは以下の通りです

* content（todoの内容、string型）
* complete（完了しているか否かを判定するためのカラム、boolean型）

では作っていきます。

``rails g model todo``

モデルが作成できたらマイグレーションファイルを編集していきます。

```ruby:db/migrate/12345678_create_todo.rb
class CreateTodos < ActiveRecord::Migration[6.1]
  def change
    create_table :todos do |t|
      t.string :content, null: false
      t.boolean :complete, default: false, null: false

      t.timestamps
    end
  end
end
```

:::note warn
boolean型を指定するときには必ずdefault値を指定する必要があります。
:::

データベースをマイグレーション

``rails db:create``
``rails db:migrate``

これでモデル関係の完成です。
必要に応じて

```ruby:gemfile
gem 'mysql2', '~> 0.5.3'
```
として``bundle update``をしてください。

### 1.4 初期データの作成
あると便利なので初期データを投入していきます

```ruby:db/seed.rb
initial_todoes = [
  {
    content: 'initial todo 1'
  },
  {
    content: 'initial todo 2'
  },
  {
    content: 'initial todo 3'
  }
]

initial_todoes.each do |todo|
  Todo.create(todo)
end
```
seeds.rbに記述できましたら以下を実行してデータベースに投入します。
``rails db:seed``

### 1.5 top#indexの作成
後ほどルーティング処理で記述しますが全てのリクエストをこちらのtop_controllerのindexアクションに飛ばします。
``rails g controller top index``
これで必要なアクションとビューページが作成されます。

```ruby:app/controller/top_controller.rb
class TopController < ApplicationController
  def index
  end
end
```
ビューページは以下のように編集してください。

```html:app/views/top/index.html.erb
<div id="root"></div>
```

### 1.6 todoes_controllerの作成
中核をなすコントローラーの作成をしていきます。こちらのコントローラーはほぼほぼAPIの役割を果たすので以下のような方法でコントローラーを作成します。
**controllerディレクトリ内にapi/v1ディレクトリを作成します。**![スクリーンショット 2021-11-01 10.42.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645779/92e83a1a-4184-c233-d964-15838abcfc33.png)

**v１ディレクトリ内にtodoes_contoroller.rbを作成します。**![スクリーンショット 2021-11-01 10.47.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645779/33dcecfe-6922-34e9-92d8-4659ff94c736.png)

**todoes_contoroller.rbに記述していきます。**

```ruby:app/contoroller/api/v1/todoes_contoroller.rb
class Api::V1::TodoesController < ApplicationController

  def index
    todoes = Todo.order(updated_at: :desc)
    #アップデート順に並べたいため
    render json: todoes
    #todoesをjson形式で返したい
  end

  def show
    todo = Todo.find(params[:id])
    render json: todo
  end

  def create
    todo = Todo.new(todo_params)
    if todo.save
      render json: todo
    else
      render json: todo.errors, status: 422
    end
  end

  def update
    todo = Todo.find(params[:id])
    if todo.update(todo_params)
      render json: todo
    else #今回は特に使用しませんが形式上書いておいきます。
      render json: todo.errors, status: 422
    end
  end

  def destroy
    if Todo.destroy(params[:id])
      head :no_content #特に何かを返すわけではないので
    else 
      render json: { error: "Failed to destroy" }, status: 422
    end
  end

  def destroy_all #全てのtodoを削除するためのアクションです
    if Todo.destroy_all
      head :no_content
    else
      render json: { error: "Failed to destroy" }, status: 422
    end
  end

  private

  def todo_params
    params.require(:todo).permit(:content, :complete)
  end

end
```
これでtodoes_controllerの作成が完了しました。

### 1.7 ルーティングの設定
ここは簡単にいきます。

```ruby:config/routes.rb
Rails.application.routes.draw do

  root to: redirect('/todoes')

  get 'todoes', to: 'top#index'
  get 'todoes/new', to: 'top#index'
  get 'todoes/:id/edit', to: 'top#index'
  #全て'top#index'にルーティングしていく。

  namespace :api do
    namespace :v1 do
      delete '/todoes/destroy_all', to: 'todoes#destroy_all'
      #resources :todoesでは賄えないアクションなので別途記述する。
      resources :todoes, only: %i[index show create update destroy]
    end
  end

end

```
### 1.8 application_controllerの設定

```ruby:app/controller/application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :null_session
  #railsのapiモード使うときのおまじないみたいな記述です。
end
```
### 1.9 application.html.erbに追記
さてこの項目ではサーバーサイドの設定がうまくいているかを確認します。
まずは
``app/javascripts/packs/hello_react.jsx``を
``app/javascripts/packs/index.jsx``に変更します。![スクリーンショット 2021-11-01 11.44.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645779/cdcfbdc6-8f90-61ce-a284-50e6c0f1c9c1.png)

そして以下のファイルの``<head></head>``内に追記します。

:::note warn
上から順に読み込まれるので最後に記述してください。
:::

```html:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>TodoApp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all' %>
    <%= javascript_pack_tag 'application' %>
    <!--以下を追記-->
    <%= javascript_pack_tag 'index' %>
    <!--ここまで-->
  </head>

  <body>
    <%= yield %>
  </body>
</html>
```

``rails s``で``http://localhost:3000/todoes``を確認してください。
![スクリーンショット 2021-11-01 11.47.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1645779/d0078b49-a17d-5d6e-b971-2ccf01c606a2.png)

隠れてますけど``Hello React``が出ていれば完了です！

part1はここまでとしますね！次のpartからはフロントに入ります！