crud処理、deviseを使った製作物について（初心者向け）

#### わたしが今回投稿した理由
オンラインスクールで学んだことを活かしてその備忘録として今回執筆することにいたしました。
素人が書いているものなので、もし違っている内容があった場合はご容赦いただけると幸いです。
早速ですが、初めていきましょう。

# 開発環境
- rails 6
- データベース：postgresql(のちにherokuでデプロイさせたかったため)
- VSCode
- 今回はresourcesで使用
　（これを使用したらshow,destroy,update,edit,index等を一括で定義できます）

### コード
- ターミナルに以下を入力する

```
rails new 自分の作りたいアプリ名 -d postgresql
```

❇︎基本`rails`は`SQLite３`がデフォルトになっているので、`-d`とするとデータベースを指定することができる。

### そのあと実行すること
- 自分が作ったアプリ名のフォルダに戻るような感じにする
  `例）cd my_favorite`

- これが終わったら、ターミナルに以下を入力

```
rails db:create
```
- 自分で作ったアプリのフォルダを`VSCode`にドロップしてあげる。そうすると、`VSCode`で編集できるようになる。

### `gem devise`をインストール
- `gemfile`に以下を記述

```ruby:gemfile

 gem 'devise'
```
- 追記が終了したら、以下をターミナルに入力

```
bundle install
```

### `gem`がインストールできたら、`devise`のログイン機能を実装するために必要なコマンドをターミナルに入力
```
 rails g devise:install *(コロン忘れ注意)*
```
❇︎　なぜ、`rails g devise:install`なのかというと、`devise`は専用のコマンドを使用し、
　 設定ファイルを作成する必要があるため、このようにする必要がある

### `devise専用`モデルを作成するので、ターミナルに以下を入力

```
rails g devise user *(こっちはコロン不要)*
```
#### 終了したあとは、以下のコマンドをターミナルに入力

```
 rails db:migrate
```
### 次にナビゲーションバーを作成
- `application.html.erb`に以下の記述をする

```ruby:application.html.erb

<!-- 略 -->
 <body>
  <!-- ここから書きます -->
  <% if user_signed_in? %>
   <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
   <%= link_to "トップ", products_path %>
   <%= link_to "投稿画面へ", new_product_path %> 
  <% else %>
   <%= link_to "ログイン", new_user_session_path %>
   <%= link_to "新規登録", new_user_registration_path %>
  <% end %>
  <!-- ここまで書きます -->
　<%= yield %>
 </body>
</html>
```  
### ナビゲーションバーを実装したら、次は`product`モデルと`product`コントローラーを作成する
- 以下をターミナルに記述

```
rails g model product
```
- 上記を行なったら、`migrationfile`の項目を以下のように編集する
-　ここで、productsテーブルに`name`, `price`, `user_id`のカラムを作成するため、以下のように編集する。尚、`user_id`カラムは、ログインしたユーザーと紐付けるために必要 

```
class CreateProducts < ActiveRecord::Migration[5.2]
  def change
   create_table :products do |t|
      t.string :name
      t.integer :price
      t.integer :user_id
      # ここまで
      t.timestamps
    end
  end
end
```
####上記を実行したあとは以下をターミナルで実行

```
rails db:migrate
```
- 上記が無事終了したら、`db/seeds.rb`にてデータの編集を行う

```ruby:seeds.rb
Product.create(name: "Ruby入門", price: 2500, user_id: 1)
Product.create(name: "Rails基礎", price: 2900, user_id: 1)
Product.create(name: "PHP基礎", price: 1500, user_id: 1)
```

#### 上記が終了したら、以下のコマンドをターミナルに入力

```
 rails db:seed
```
**これでエラーが発生しない場合は、テーブルに無事登録されている**

### 無事に登録完了したら以下のコマンドをターミナルに入力

```
rails g controller Products *（頭文字大文字と複数にするように）*
```
### コマンド入力後は以下のような処理を行う
- `config/routes.rb`を以下のように編集

```ruby:config/routes.rb
 Rails.application.routes.draw do
 root to: 'products#index'
 resources :products
 end
```
#### 上記が終わったら、`index`アクションを定義する
```ruby:products_controller.rb
 class ProductsController < ApplicationController
  def index
   @products = Product.all
  end
 end
```
#### `index`アクションが定義できたら、次はこれに対応する`view`ファイルを作成
```ruby:index.html.erb
<h1>新規投稿一覧</h1>
   <% if user_signed_in? %>
   <% @products.each do |product| %>
    <p>商品名:<%= product.name %></p>
    <p>金額:<%= product.price %></p>
   <% else %>
   恐れ入りますが、ログインお願いします
   <% end %>
　<% end %>
```
- `devise`でログイン機能を実装すると、ログイン・サインアップ画面は自動的に生成されるが`views`
- の中には該当するファイルが存在しない。そのため、今のままだとログイン画面に変更を加えることができない。

- もし変更を加える場合は、`devise`のコマンドを利用してビューファイルを生成する必要がある。

- ログイン画面用のビューファイルを生成するためには、以下のコマンドをターミナルに入力。

```
rails g devise:views
```
#### 上記ができたら、次は`products_controller`の`new`アクションを定義
```ruby:products_controller.rb
 class ProductsController < ApplicationController
  def new
   @product = Product.new
  end
 end
```
#### `ビューファイル`の作成
- 上記までできたら、`users`ディレクトリの中の`new.html.erb`に新規投稿フォームを作成する

```ruby:new.html.erb
<h1>新規投稿</h1>
<%= form_with model: @product, local: true do |form| %>
<p>商品名:<%= form.text_field :name, required: true %></p>
<p>金額:<%= form.text_field :age, required: true %></p>
<%= form.submit "送信" %>
<% end %>
```
### `createアクション`を定義
```ruby:products_controller.rb
 def create
  Product.create(name: product_params[:name], price: product_params[:price], 
  user_id: current_user.id)
  redirect_to root_path
  end
```
**`create`アクションが定義できたら、`ストロングパラメータ`の登場！**

`products_controller`下部に以下のように記述

```ruby:products_controller.rb
<!-- 略 -->
 private
  def product_params
   params.require(:user).permit(:name, :price)
  end
```

- こちらを解説すると、`user`モデルに紐づいた`（:name, :price）`のみ許可するよということを定義している

#### 上記が終了したら、`products_controller`の一番上に下記コマンドを記述
```ruby:products_controller.rb
class ProductsController < ApplicationController
  before_action :move_to_index, except: :index ←こちらを追加

  def index
    @products = Product.all
  end

  def new
    @product = Product.new
  end

  def create
    Product.create(name: product_params[:name], price: product_params[:price], user_id: current_user.id)
  end

  def move_to_index
    redirect_to action: :index unless user_signed_in? ←こちらを追加
  end
以下省略
```
**これをアクションの前に書くとログインしていない場合には、その他のアクションにはいかず、indexアクションに強制的にいくようにする。**


### ルートを一部変更する
```ruby:routes.rb
 Rails.application.routes.draw do
 root to: 'products#index'
 resources :products
 resources :users, only: :show ←これを追加
 end
```
- 今回は、`users_controller`の中でも`show`アクションしか使わないから、上記のように書く

#### `users`コントローラーを新しく作ってあげるのでターミナルに以下を記述する

```
rails g controller Users
```
#### `users_controller`に以下を記述
```ruby:users_controller.rb
 class UsersController < ApplicationController
 　def show
 　　@products = Product.where(user_id: current_user.id)
　 end
 end
```
#### `show.html.erb`（`userscontroller`のビューファイル）に以下を記述
```ruby:show.html.erb
<% @products.each do |product| %>
  <p>商品名:<%= product.name %></p>
  <p>価格:<%= product.price %></p>
<% end %>
```
#### `application.html.erb`に以下の記述を追加で記入（ナビゲーションバー）
```ruby:application.html.erb
 <!-- 略 --> 
  <% if user_signed_in? %>
   <%= link_to "ログアウト", destroy_user_session_path, method: :delete %>
   <%= link_to "トップ", products_path %>
   <%= link_to "投稿画面へ", new_product_path %> 
   <%= link_to 'マイページへ', user_path(current_user.id) %> ←これを追加
  <% else %>
   <%= link_to "ログイン", new_user_session_path %>
   <%= link_to "新規登録", new_user_registration_path %>
  <% end %>
```
#### 購入商品一覧に購入したユーザーのIDを表示させるため、`/views/products`の`index.html.erb`に次のように書く
```ruby:index.html.erb
<h1>新規投稿一覧</h1>
   <% if user_signed_in? %>
    <% @products.each do |product| %>
    <p>商品名:<%= product.name %></p>
    <p>金額:<%= product.price %></p>
    <p>会員No.:<%= product.user.id %></p>   
   <% else %>
    恐れ入りますが、ログインお願いします
   <% end %>
　<% end %>
```

**しかし、このままだとエラーが発生する。ここからどうしたらいいかというと`アソシエーション`という処理を実行する。**

 イメージとしては`user`と`product`を結合させるようなイメージ

#### まず初めに行うこと
- `app/models`にある`product.rb`を以下のように編集

```ruby:product.rb
 class Product < ApplicationRecord
  belongs_to :user←こちらを記述
 end
```
- 解説を行うとすると、`product`は誰が持っているの？と考えたら、あ、`ユーザー`だという考えになるはずだから、
このように記述する

#### 次に行うこと
- `app/models`にある`user.rb`を以下のように編集

```ruby:user.rb
class User < ApplicationRecord 
#Include default devise modules. Others available are:
 #:confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :validatable
  has_many :products←こちらを記述
 end
```
- 解説をすると、`user`は、何をたくさん持ってるの？と考えたら、`products`いっぱい持っているという考えになると
おもうから、このように記述する

### これでアソシエーションが完了したので、2点改善を行なう。

#### まず1点目は、先ほど、`users_controller`の`show`アクションを記述したが、少し不格好なので、以下のように変更する

- 変更前

```ruby:users_controller.rb
 class UsersController < ApplicationController
  def show
   @products = Product.where(user_id: current_user.id)
  end
 end
```

- 変更後

```ruby:users_controller.rb
def show
 @products = User.find(current_user.id)
end
```
#### 2点目は、`show.html.erb` `（userscontroller）`を以下のように変更

- 変更前

```ruby:show.html.erb
<% @products.each do |product| %>
  <p>商品名:<%= product.name %></p>
  <p>価格:<%= product.price %></p>
<% end %>
```

- 変更後

```ruby:show.html.erb
<% @user.products.each do |product| %>（←@user.productsに変更する）
  <p>商品名:<%= product.name %></p>
  <p>価格:<%= product.price %></p>
<% end %>
```

### 最後に
これでログイン機能の実装、crud処理の大まかなことはできました。
`edit`,`update`アクションの実装、`フラッシュ機能`や、`bootstrap`で装飾等も説明したかった部分はありますが、今回はここまでにしておきます。
今後、ご自身のポートフォリオを作成する際、`ログイン機能`を実装するときは、最初に`devise`を実装してから、`crud処理`等を行なった方が、もしかしたら行き詰まりにくくなると思います。（私がそうでした笑）
ありがとうございました。