Rails

## 前置
各役割や書き方などをまとめてみました
サンプルコード→解説という形式です
コードはコピペでくっつけたものなので、意味としてはぐちゃぐちゃです
こんな感じで書くんだーって程度に見てください

## コントローラ
```terminal
rails g controller Users new
```
- `rails g controller コントローラ名　アクション名`
- コントローラ名は、頭大文字、複数形
- コントローラファイルとビューフォルダとアクションが生成


```app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :logged_in_user

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      redirect_to users_path
    else
      render 'new'
    end
  end
 private
   def user_params
      params.require(:user).permit(:name,:password,
                                   :password_confirmation)
   end
   
   def logged_in_user
      unless logged_in?
        flash[:danger] = "ログインしてください"
        redirect_to login_url
      end
   end

end
```
- `before_action メソッド名`で、各アクションを行う前に処理を行える
- `before_action メソッド名, only: [:アクション名,:アクション名]`で、指定したアクションのみに適用される
- コントローラは全て`ApplicationController`を継承しているので、全コントローラで行いたいメソッドはApplicationControllerに記述する
- 不正な操作を防ぐため、送られてきたリクエストから必要な値だけを取得するメソッドを定義する

## ルーティング
```config/routes.rb
root 'static_pages#home'
get  '/contact', to: 'static_pages#contact'
get  '/date/:date' to: 'static_pages#date'
resources :users, only[:new, :create, :show]
```
- `root 'コントローラ名#アクション名'`で、ルートパスでどのアクションを行うか指定する
- `httpリクエスト 'パス', to: 'コントローラ名#アクション名'`で、そのパスに送られてきたリクエストに対して、どのアクションを返すのか指定
- パスの中の`:OO`は指定したコントローラで呼び出せる
- `resources :コントローラ名`で、そのコントローラに対して決められたアクションとパスが用意される。一覧は下記
- `only[:アクション名]`で、使用するアクションを制限できる

HTTPリクエスト|URL|アクション|名前付きルート|用途
-|-|-|-|-
GET|/users|index|users_path	すべてのユーザーを一覧するページ
GET|/users/1|show|user_path(user)|特定のユーザーを表示するページ
GET|/users/new|new|new_user_path|ユーザーを新規作成するページ（ユーザー登録）
POST|/users|create|users_path|ユーザーを作成するアクション
GET|/users/1/edit|edit|edit_user_path(user)|id=1のユーザーを編集するページ
PATCH|/users/1|update|user_path(user)|ユーザーを更新するアクション
DELETE|/users/1|destroy|user_path(user)|ユーザーを削除するアクション

## ビュー
```app/views/layouts/application.html.rb
<!DOCTYPE html>
<html lang="ja">
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title><%= yield(:title) %></title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <!--[if lt IE 9]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
      </script>
    <![endif]-->
  </head>
  <body>
    <header class="navbar sticky-top bg-black">
      <div class="container d-flex justify-content-between">
          <div class="h1 text-light">
              MYAPP
          </div>
          <% if logged_in? %>
            <%= link_to "ログアウト", logout_path, 
            method: :delete, class: "btn btn-outline-danger" %>
          <% end %>
        </div>
      </div>
    </header>
    <main>
      <%= yield %>
      <%= debug(params) if Rails.env.development? %>
    </main>
  </body>
</html>
```
- どのページにも適用される要素は`layouts/application.html.rb`に記述
- getリクエストを受けた場合、`app/views/コントローラ名/アクション名.html.rb`が表示される
- if文で、条件に合わせて要素を変更することも可能

```
<% provide(:title, "新規登録") %>

<div class="container">
　　<div class="row justify-content-center py-5">
　　　　<div class="col-md-6 col-md-offset-3 p-4 bg-white">
  　　<h1 class="text-center mb-3">新規登録</h1>
   <%= form_with(model: @user, local: true) do |f| %>
    <%= render 'shared/error_messages', object: f.object %>

    <%= f.label :name, "名前" %>
    <%= f.text_field :name, class: "form-control" %>

    <%= f.label :password, "パスワード" %>
    <%= f.password_field :password, class: "form-control" %>

    <%= f.label :password_confirmation, "パスワードを確認" %>
    <%= f.password_field :password_confirmation, class: "form-control" %>

   　　<%= f.submit "ユーザを作成", class: "btn btn-primary w-100 mt-3" %>
  　　<% end %>
 　　</div>
　　</div>
</div>
```
- `<% provide(:キー, 値) %>`と指定しておけば、`layouts/application.html.rb`で　`<%= yield(:キー) %>`で呼び出せる
- form_withでフォームの作成
- `model: @user` インスタンス変数はコントローラで定義したもの。渡されたオブジェクトによってPOSTかPATCHか自動で判断される

## モデル・マイグレーション
### 新しいモデルの作成
```terminal
rails g model User name:string
```
- `rails g model モデル名 カラム名:カラムの型`で、モデルに必要なファイルが生成される

```db/migrate/[timestamp]_create_users.rb
class CreateArticles < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :name

      t.timestamps
    end
  end
end
```
- create_tableによって新しいテーブルが作られる
- 一意性を持たせたい場合はchangeメソッド内のcreate_tableブロック外に
`add_index :テーブル名, :カラム名,unique: true`

```terminal
rails db:migrate
```
- 変更したものを反映させるために使うコマンド

### 既存モデルにカラムの追加
```terminal
rails g migration add_password_digest_to_users password_digest:string
```
- カラムを追加したい場合のコマンド
- `rails g migration マイグレーションファイル名　カラム名:カラムの型`

```db/migrate/[timestamp]_add_password_digest_to_users.rb
class AddPasswordDigestToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :password_digest, :string
  end
end
```
- `add_column :テーブル名, :カラム名, :データ型`

```terminal
rails db:migrate
```
- 変更したものを反映させるために使うコマンド

### 子モデルの作成
```
rails g model Micropost content:text user:references
```
- 最後に`モデル名:references`をつけることで、関連付けをさせる
```db/migrate/[timestamp]_create_microposts.rb
class CreateMicroposts < ActiveRecord::Migration[6.0]
  def change
    create_table :microposts do |t|
      t.text :content
      t.references :user, foreign_key: true

      t.timestamps
    end
    add_index :microposts, [:user_id, :created_at]
  end
end
```
- `t.references :user, foreign_key: true`によって、user_idを外部キーとして持たせる
- `add_index :microposts, [:user_id, :created_at]`複数のキーを配列として渡すことで、複合キーインデックスを作成


### モデルファイル
```app/models/user.rb
class User < ApplicationRecord
 has_many :microposts, dependent: :destroy
 default_scope -> { order(id: :asc) }
 VALID_NUMBER_REGEX = /\A[0-9][0-9][0-9][0-9]\z/
 validates :number, presence: true, length: { is: 4 },
              format: {with: VALID_NUMBER_REGEX},
              uniqueness: true
 
end
```
- `has_many :子モデル`で　1対多　の関連付け
- 子モデル側には`belongs_to :親モデル`を記述
- `dependent: :destroy`で、親が削除されれば、関連された子データも全て削除される
- default_scopeでデータの並び替え
- validatesで各カラムに対して制限をかける。正規表現も使える