【Rails】Ruby on Railsについて

# 記事概要
フレームワークRuby on Railsについて、まとめる

# 基本理念
基本理念を遵守することで、フレームワークの能力を最大限に活かすことができる

## DRY(Don't Repeat Yourself)
「同じ情報を繰り返し定義しない」という考え方
情報：メソッドや配列など、データの集合体など
→同じコードを繰り返し記述しないという捉え方で問題ない

- メリット
    - 可読性が向上する
    - コード量を減らすことによって、アプリケーションの動作が早くなる

```ruby
# Not DRY
orange_price = 100 * 1.1
peach_price = 200 * 1.1
apple_price = 300 * 1.1

# DRY
tax = 1.1
orange_price = 100 * tax
peach_price = 200 * tax
apple_price = 300 * tax
```

## CoC(Convention Over Configuration)
「設定よりも規約を優先する」という考え方

- メリット
    - 開発スピードが上がる
    - 質を担保できる
    - 規約は開発者同士の共通認識であるため、可読性が向上する

```ruby
# Not CoC
class TestsController < ApplicationController
 def render_top_page
  render template: "tests/index"
 end
end

# CoC
class TestsController < ApplicationController
 def index
 end
end
```

### ディレクトリ
Ruby on Railsのアプリケーションのディレクトリ階層は、規約に則って整理されている

- アプリ名
    - app
        ※ MVCに関するファイルなどを格納している、アプリケーションの主要ディレクトリ
    - bin
        ※ Binary Codeの略。コマンドなどで実行するファイルが格納されている
    - config
        ※ アプリケーションの設定関係のファイルが格納されている
    - db
        ※ データベースに関するファイルが格納されている
    - lib
        ※ libraryの略で、基本的なライブラリが格納されている
    - log
        ※ アプリケーションが動いている間の記録などのファイルが格納されている
    - node_modules
        ※ nodeのパッケージが格納されている
    - public
        ※ デフォルトで表示される画面の情報などが格納されている
    - storage
        ※ 画像などをアプリケーション自体に保存する際に使用するディレクトリ
    - test
        ※ アプリケーションのテストを行う際に使用するファイルを格納するディレクトリ
    - tmp
        ※ アプリケーションが起動している際の一時的な情報を格納するディレクトリ
    - vendor
        ※ ライブラリ(Gem)などをアプリケーション自体にインストールする際に使用するディレクトリ
    - .browserslistrc
    - .ruby-version
    - babel.config.js
    - config.ru
    - Gemfile
    - Gemfile.lock
    - package.json
    - postcss.config.js
    - Rakefile
    - README.md
    - yarn.lock

# オブジェクト指向
オブジェクト指向言語であるRubyで作られているため、Ruby on Railsもオブジェクト指向の考えに則って作られている

# 命名規則
|種類|命名規則|
|-|-|
|クラス名|頭文字大文字のキャメルケース|
|メソッド名|小文字のスネークケース|
|変数名|小文字のスネークケース|

# Viewの構造を意識
## Action View
Ruby on Railsのアプリケーションにおいて、ビューの機能を実現するために必要な処理のオブジェクトのこと

## ヘルパーメソッド
ビューでHTMLタグを出現させたりテキストを加工するために使用するメソッドの総称
あらかじめ用意されているヘルパーメソッドは、[こちら](https://api.rubyonrails.org/classes/ActionView/Helpers.html)を参照

すでに用意されているヘルパーメソッド以外に、ヘルパーメソッドを自作することもできる

## モジュール
Rubyにおける「インスタンスを生成できないクラス」のようなもののこと

```ruby
module モジュール名

end
```

```ruby
module Sample1
 class Test
 end
end

module Sample2
 class Test
 end
end

# Testクラスの呼び出し
Sample1::Test
Sample2::Test
```

## Helper
ヘルパーメソッドを作成できるモジュール

`app/helpers`配下に用意されており、`application_helper.rb`や各コントローラーに対応したhelperのファイルに処理を記述することでヘルパーメソッドとして使用できる

作成方法は、[こちら](https://qiita.com/likapantrip/items/1ca058c6ddd0e1be305f)を参照

```application_helper.rb
module ApplicationHelper
  def sample
    # sampleというヘルパーメソッド
  end
end
```

```erb
<!-- application_helper.rbで定義したsampleのヘルパーメソッドを、ビューファイルで使用できる -->
<%= sample %>
```

# コントローラーの構造を意識
## Action Controller
Ruby on Railsのアプリケーションにおいて、コントローラーの機能を実現するために必要なオブジェクトのこと

## レンダリング
指定したHTMLなどのビューファイルを画面に描画すること
フォーマットは、JSONを使用する場合が多い

## サービスクラス
コントローラー内のコードの可読性を高めるために用いる概念

[![Image from Gyazo](https://i.gyazo.com/8b6c3a84537709a2887c1714fd3a7cfb.png)](https://gyazo.com/8b6c3a84537709a2887c1714fd3a7cfb)

作成方法は、[こちら](https://qiita.com/likapantrip/items/e983791b295e04d963d9)を参照

# モデルの構造を意識
## Active Model
Ruby on Railsのアプリケーションにおいて、モデルの機能を実現するために必要なオブジェクトのこと

## Callbacksモジュール
データ保存時などの任意のタイミングで実行する処理を設定できるモジュール

```ruby
class Tweet < ApplicationRecord
 validates :text, presence: true

 # バリデーションの後で「puts_done」を実行
 after_validation :puts_done

 private
 # 「puts_done」という、任意のタイミングで実行する処理を登録
   def puts_done
     puts 'validation completed'
   end
end
```

## Validationsモジュール
データの保存時に検証するような役割がある

[![Image from Gyazo](https://i.gyazo.com/bd6b406141e3f7c9a62218ba2ba9c4f6.png)](https://gyazo.com/bd6b406141e3f7c9a62218ba2ba9c4f6)

## Serializationモジュール
JSONなどで返却される値を整えることができるモジュール

[![Image from Gyazo](https://i.gyazo.com/cad3163af1f60d88098ae89a24ec1307.png)](https://gyazo.com/cad3163af1f60d88098ae89a24ec1307)

- Serializationモジュールを使用しないケース
    ```tweet.rb
    class Tweet < ApplicationRecord
      validates :text, presence: true
    end
    ```
    ```tweets_controller.rb
    class TweetsController < ApplicationController
      def index
        @tweets = Tweet.includes(:user).order("created_at DESC")
        render json: @tweets
      end
    end
    
    # JSONで返却されている内容は「id, text, image, created_at, updated_at, user_id」
    # [
    #   {"id":2,"text":"太陽の写真","image":"data:image/sample","created_at":"2020-04-22T06:11:44.134Z","updated_at":"2020-04-22T06:11:44.134Z","user_id":1},
    #   {"id":1,"text":"綺麗な景色","image":"data:image/jpeg;base64,/9j","created_at":"2020-04-22T06:11:25.425Z","updated_at":"2020-04-22T06:11:25.425Z","user_id":1},
    # ]
    ```
- Serializationモジュールを使用するケース
    ```tweet.rb
    class Tweet < ApplicationRecord
      # JSONで返却する値を指定するために追加
      def attributes
        {'text' => nil, 'image' => nil}
      end
      validates :text, presence: true
    end
    ```
    ```tweets_controller.rb
    class TweetsController < ApplicationController
      def index
        @tweets = Tweet.includes(:user).order("created_at DESC")
        render json: @tweets
      end
    end
    
    # JSONで返却されている内容は「text, image」
    # [
    #   {"text":"太陽の写真","image":"data:image/sample"},
    #   {"text":"綺麗な景色","image":"data:image/jpeg;base64,/9j"}
    # ]
    ```

## Formオブジェクト
フォームに関する処理を切り出す仕組みのことであり、大きく分けて下記2つの場合に使用する

- フォームから入力された値が複数のモデルに関連するデータであり、一度に複数モデルを操作して、それぞれのデータを更新したい場合
    [![Image from Gyazo](https://i.gyazo.com/c40275f86676dea5af3c418fa91ba5fb.png)](https://gyazo.com/c40275f86676dea5af3c418fa91ba5fb)
    実装方法の説明
    1. モデルを生成する
        ```item.rb
        class Item < ApplicationRecord
        end
        ```
        ```genre.rb
        class Genre < ApplicationRecord
        end
        ```
    1. `app/models`ディレクトリ配下に、`item_form.rb`を手動生成する
    1. itemモデルとgenreモデルの情報を検証・保存する処理を記述する
        ```item_form.rb
        class ItemForm
         include ActiveModel::Model
        
         attr_accessor :text, :genre
         validates :text, presence: true
         validates :genre, presence: true
        
         def save
           Item.create(text: text)
           Genre.create(genre: genre)
         end
        end
        ```
    1. コントローラーで、ItemFormというクラス名を呼び出す
        ```items_controller.rb
        class ItemsController < ApplicationController
         def index
         end
        
         def create
           @item = ItemForm.new(set_params)
           if @item.valid?
             @item.save
           end
         end
        
         private
         def set_params
           params.permit(:text, :genre)
         end
        end
        ```
- フォームから入力された値に対応するモデルは無いものの、バリデーションをかけたい場合
    [![Image from Gyazo](https://i.gyazo.com/c9629f995ff0fa6b1f9478607ab58da0.png)](https://gyazo.com/c9629f995ff0fa6b1f9478607ab58da0)

# モデルによるデータベースの操作
## ActiveRecord
モデルによるデータベースの操作を実現する仕組み



# Ruby on Railsまとめ
https://qiita.com/likapantrip/items/46b43c9d1309b6633f0a