一からはじめるRoRoBoW（後編）

# Ruby on Railsとは
## 設計思想
* 編集中

# Ruby on Railsリファレンス
## ガイド

### モデル
#### Active Record の基礎
* [Active Record の基礎](https://railsguides.jp/active_record_basics.html)

#### Active Record マイグレーション
* [Active Record マイグレーション](https://railsguides.jp/active_record_migrations.html)
* [Rails で信頼性の高い Migration を書くには](https://qiita.com/shuhei/items/c0a6c3e29c87de6dff63)

##### マイグレーション確認
```bash
rails db:migrate:status

 up     20181001000000 Create Hogehoge Tables
 up     20181001000010 Add Columns to Hages
 down   20181001000020 Add Columns to Fugas

# up      コミットが完了したもの
# down　　　　　　　　コミットしていないもの 
```

##### マイグレーションロールバック
```bash
# 直前のマイグレーションコミットをロールバックする
rails db:rollback

# %n%つ前のマイグレーションバージョンにロールバックする
rails db:rollback STEP=%n%
```

##### マイグレーションロールバック＋コミット
```bash
# %n%つ前のマイグレーションバージョンにロールバックし、再度マイグレーションコミットする
rails db:migrate:redo STEP=%n%
# 内部処理についてはマイグレーションコミットの項を参照
```

##### マイグレーションコミット
```bash
# %yyyyMMddHHmmss%接頭辞を持つマイグレーションバージョンのスクリプトをコミットする
rails db:migrate VERSION=%yyyyMMddHHmmss%

# 実行していないマイグレーションバージョンのスクリプトをコミットする
rails db:migrate
```
db:migrate（マイグレーションコミット）が実行されると、内部処理でdb:schema:dumpタスクも実行される
db:schema:dumpタスクはdb/schema.rbスキーマファイルを更新し、スキーマがデータベースの構造に一致する

##### マイグレーションスクリプト
* クラス・マイグレーションファイル名の命名規則

```sh
# カラム追加
Add%Column_Camel_Case%To%Table_Name_Camel_Case%

# 例
rails g migration AddMailAddressToUsers #=>メールアドレスをユーザー情報に追加

# カラム削除
Remove%Column_Camel_Case%From%Table_Name_Camel_Case%

# 例
rails g migration RemoveHogeNameFromUsers #=>hoge_nameというカラムをユーザー情報からドロップする
```

カラム名と種類を続けて記載する
上記の命名規則でマイグレーションスクリプト内に適切なadd_column文/remove_column文が自動生成される

```sh
# 例
rails g migration AddMailAddressToUsers mail_address:string
```

上記で自動生成されるソース

```ruby:YYYYMMDDHHMMSS_add_mail_address_to_users.rb
class AddMailAddressToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :mail_address, :string
  end
end
```

マイグレーションスクリプトの生成

```sh
# index    インデックスを追加する
rails g[enerate] migration Add%Column_Camel_Case%To%Table_Name_Camel_Case% %column_snake_case%:%type%[:index]
```

上記で自動生成されるソース

```ruby:YYYYMMDDHHMMSS_add_mail_address_to_users.rb
class AddMailAddressToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :mail_address, :string
    add_index :users, :mail_address
  end
end
```


##### 自作マイグレーションの為のメソッド

```sh
# upメソッド
class AddDeliveryTypesToOrders < ActiveRecord::Migration[5.1]
  def up
    add_reference :orders, :user_delivery, foreign_key: true, optional: true
  end
end

# changeの代用メソッド

# downメソッド
class AddDeliveryTypesToOrders < ActiveRecord::Migration[5.1]
  def down
    remove_foreign_key :orders, column: :user_delivery_id
    remove_index :orders, column: :user_delivery_id
    remove_reference :orders, :user_delivery
    remove_column :orders, :delivery_type
  end
end

# changeの代用メソッド。downメソッドにはupメソッドによって行われた変換を逆転する方法を記述する
# upの後にdownを実行した場合、スキーマが変更されないようにする必要がある

# changeメソッド
class AddMailAddressToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :mail_address, :string
  end
end
```

##### 自作マイグレーションのメソッド内で定義可能なメソッド
* [Ruby on Rails: How do I add a not null constraint to an existing column using a migration?](https://stackoverflow.com/questions/9286176/ruby-on-rails-how-do-i-add-a-not-null-constraint-to-an-existing-column-using-a)

```sh
# add_column
# add_foreign_key
# add_index
# add_reference
# add_timestamps

# change_column_default (:fromと:toの指定は省略できない)
# change_column_null

# create_join_table
# create_table

# change_table
change_table :products do |t|
  t.remove :description, :name
  t.string :part_number
  t.index :part_number
  t.rename :upccode, :upc_code
end
# change、change_default、removeメソッドが内部実行されなければロールバック可能

# disable_extension

# drop_join_table
# drop_table （ブロックを渡さなければならない）

# enable_extension

# remove_column（型を指定しなければならない）
# remove_foreign_key（2番目のテーブルを指定しなければならない）
# remove_index
# remove_reference
# remove_timestamps

# rename_column
# rename_index
# rename_table
```

##### フィールド
* ActiveRecordインスタンスで使用されるカラム名
  * created_at
  * updated_at
  * lock_version
  * type
  * 関連付け名_type
  * テーブル名_count

```sh
# 文字列型
string
text

# 数値型
integer
decimal
boolean

# バイト型
binary

# 日付型
timestamps

# 関連付け
reference

# 制約・インデックス
index

# limit         string/text/binary/integerフィールドの最大サイズを指定
# precision     
# scale         decimalフィールド
# polymorphic   
# null          
# default       
# index         
# comment       
# * nullとdefaultはコマンドラインで指定不可
```

##### 複雑な処理の為のメソッド
* reversibleメソッド
  * up/downメソッド以外のメソッドを使用したり、マイグレーションが複雑化したことによってup/downメソッドで逆転させられない場合
  * up/downメソッドの直後に何かしらの作業をしたい場合

  * upブロック
    * 正方向のマイグレーションスクリプトがコミットされたタイミングで実行される（upメソッド）
  * downブロック
    * 逆方向のマイグレーションスクリプトがコミット（＝ロールバック）されたタイミングで実行される（downメソッド）

  * DBのデータ遡及にも応用可能

```ruby:YYYYMMDDHHMISS_add_site_url_to_users.rb
# テーブルの制約を付ける
class AddSiteUrlToUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :distributors do |t|
      t.string :zipcode
    end
 
    reversible do |dir|
      dir.up do
        # CHECK制約を追加
        execute <<-SQL
          ALTER TABLE distributors
            ADD CONSTRAINT zipchk
              CHECK (char_length(zipcode) = 5) NO INHERIT;
        SQL
      end
      dir.down do
        execute <<-SQL
          ALTER TABLE distributors
            DROP CONSTRAINT zipchk
        SQL
      end
    end
 
    add_column :users, :home_page_url, :string
    rename_column :users, :email, :email_address
  end
end
```

```ruby:YYYYMMDDHHMISS_add_delivery_types_to_orders.rb
# 遡及
# frozen_string_literal: true
class AddDeliveryTypesToOrders < ActiveRecord::Migration[5.1]

  class AddDeliveryTypes < ActiveRecord::Base
    self.table_name = :orders
    belongs_to :user_delivery, class_name: 'UserDelivery'
  end

  def up
    # remove_reference :orders, :user_delivery
    add_reference :orders, :user_delivery, foreign_key: true, optional: true

    # データ遡及
    reversible do |dir|
      dir.up do
        AddDeliveryTypes.reset_column_information
        AddDeliveryTypes.find_each do |delivery_type|
          fail 'Illegal argument user_delivery' unless order.user_delivery.present?
          delivery_type.update!(delivery_type: order.user_delivery.delivery_type)
        end
      end
      # downでは列削除なので遡及不要
    end
  end

  def down
    remove_foreign_key :orders, column: :user_delivery_id
    remove_index :orders, column: :user_delivery_id
    remove_reference :orders, :user_delivery
    remove_column :orders, :delivery_type
  end
end
```
  * Migration毎に専用のModelを用意する
    * 「マイグレーションファイルは後で手を入れない」のでマイグレーションスクリプト内ではマイグレーション外のコードを利用しない
    * マイグレーションスクリプト内ではそのファイル内でMigrationを完結させる
    * 特にModelを使ってデータの移行を行う場合は注意が必要
  * Modelを使う前には必ずreset_column_informationメソッドを呼ぶ
    * ActiveRecordはテーブルのカラム情報をキャッシュしている
    * キャッシュはModel毎ではなく、テーブル毎のようであるので、Migration内で完結するModelを用意していてもキャッシュしている可能性が高い
  * レコード数の多いテーブルに対してはall.each do |hoge| %block statement% endではなく、find_each do |hoge| %block statement% endを使用する
    * all.eachは全レコードを一回でSELECTしてくる
    * find_eachはデフォルトでは１０００件ずつSELECTする
  * 登録・更新・削除メソッドでは!を使用する
    * save / create / update / removeなどではエラーを握りつぶすので注意
  * Migrationのassertionでデータ妥当性を担保する
    * fail 'Illegal argument user_delivery' unless order.user_delivery.present?
  * up / downコマンドのテストは欠かさず実行する
  * [Rails で信頼性の高い Migration を書くには](https://qiita.com/shuhei/items/c0a6c3e29c87de6dff63)


##### トラブルシューティング
* ActiveRecord::IrreversibleMigration
  * マイグレーションが逆転不可能な場合に発生する

* マイグレーションのステータス確認で********** NO FILE **********が出た場合
  * [railsのrakeのmigrationファイルを削除しNO FILEとstatusに出た時の対処](https://joppot.info/2014/10/16/2104)
  * [rake db:migrate:statusのコードを追いかける](https://qiita.com/tkm_kj/items/328da73479a0e348a01e)

* マイグレーションに失敗した場合
  * migrateはup/downで制御するかreset(db resetされるのであまり好ましくない)

```ruby:db/migrate/20181001000001_add_user_id_to_deliveries.rb
class AddUserIdToDeliveries < ActiveRecord::Migration[5.1]

  class AddUserId < ActiveRecord::Base
    self.table_name = :deliveries
    belongs_to :order, class_name: 'Order'
  end

  def up
    # remove_reference :deliveries, :user
    add_reference :deliveries, :user, foreign_key: true, optional: true

    # データ遡及
    reversible do |dir|
      dir.up do
        AddUserId.reset_column_information
        AddUserId.find_each do |delivery|
          delivery.update(user_id: delivery.order.user_id)
        end
      end
    end
  end

  def down
    remove_foreign_key :deliveries, column: :user_id
    remove_index :deliveries, column: :user_id
    remove_reference :deliveries, :user
  end

  # 失敗した時用
  # def up
  #   remove_foreign_key :deliveries, column: :user_id
  #   remove_index :deliveries, column: :user_id
  #   remove_reference :deliveries, :user
  # end

  # def down
  # end
end
```

downしている場合

```sh
#失敗した時用のup/downをアンコメントしてupを実行する
rails db:migrate # ここから
rails db:migrate:down VERSION=20181001000001
# イグレーションスクリプトを修正する
# 失敗した時用のup/downをコメントアウト ここまで
# 成功するまでここからここまでを繰り返す
```

upしている場合
> 恐らく失敗しているのでupしている事はないかと思われる



#### Active Record バリデーション
##### ビルトイン関数

```ruby
presence: true
length: { maximum: 255 }
```

#### Active Record コールバック
* インスタンス化
  * after_initialize
    * Active Recordのinitializeメソッドを直接オーバーライドしないで済む

* 検索
  * after_find
    * Active Recordがデータベースからレコードを1つ読み込むたび(findメソッド実行時ではない)

* 新規作成
  * before_validation
  * after_validation
  * before_save
  * around_save
  * before_create
  * around_create
  * after_create
  * after_save

* 更新
  * before_validation
  * after_validation
  * before_save
  * around_save
  * before_update
  * around_update
  * after_update
  * after_save
  * after_touch
    * touchメソッド(update_atを更新)実行後
    * [ActiveRecord.touch (:column_symbol)](http://railsdoc.com/references/touch)
    * belongs_toとの併用可能（アソシエーション側のafter_touchコールバックも実行される）

```active_record_after_touch.rb
class Employee < ApplicationRecord
  belongs_to :company, touch: true
  after_touch do
    puts 'Employeeモデルにタッチされました'
  end
end
 
class Company < ApplicationRecord
  has_many :employees
  after_touch :log_when_employees_or_company_touched
 
  private
  def log_when_employees_or_company_touched
    puts 'Employee/Companyにタッチされました'
  end
end
 
>> @employee = Employee.last
=> #<Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05">
 
# @employee.company.touchをトリガーする
>> @employee.touch
Employeeにタッチされました
Employee/Companyにタッチされました
=> true
```  

* 削除
  * before_destroy
    * dependent: :destroyよりも前に配置
    * dependent: :destroyによって削除されるよりも前にbefore_destroyコールバックが実行される必要がある
  * around_destroy
  * after_destroy
    * dependent: :destroyのオプションされたアソシーエションでコールバックが実行される

```active_record_after_destroy.rb
class User < ApplicationRecord
  has_many :posts, dependent: :destroy
end
 
class Post < ApplicationRecord
  after_destroy :log_destroy_action
 
  def log_destroy_action
    puts 'Post destroyed'
  end
end
 
>> user = User.first
=> #<User id: 1>
>> user.posts.create!
=> #<Post id: 1, user_id: 1>
>> user.destroy
Post destroyed
=> #<User id: 1>
```

* コールバックしない更新
  * decrement
  * decrement_counter
  * increment
  * increment_counter
  * update_column
  * update_columns
  * update_all
  * update_counters

* コールバックしない削除
  * delete
  * delete_all


toggle


#### Active Record の関連付け
#### Active Record クエリインターフェイス
#### Active Record と PostgreSQL
#### Active Model の基礎


### ビュー
#### Action View の概要
#### レイアウトとレンダリング
#### Action View フォームヘルパー


### コントローラ
#### Action Controller の概要
##### スコープ変数・定数
[flash[:notice]のワナ？](http://d.hatena.ne.jp/gac777/20090209/1234187881)
[Railsのflashをクリアする](http://blog.digital-squad.net/article/140573529.html)

```ruby
flash
```

##### ビルトイン関数
* [Rails 5 アップデートへの道](https://qiita.com/kenchan0130/items/f5ae55a6e23268238a44#xxx_filter-%E3%81%AE%E9%9D%9E%E6%8E%A8%E5%A5%A8)

* レンダリング
[redirect_to の引数とかのメモ](https://qiita.com/kanpe777/items/c5154b58c852855deefc)

```ruby
redirect_to
```

```ruby
render [%render_template_name:string%|%action_controller_method:symbol%] [template: %render_template_name:string%|%action_controller_method:symbol%]? [file: %file_path:string%]? [inline: %inline_text:string%]?

# render_template_name 同一コントローラのテンプレート名('index'や'update')、他コントローラのテンプレート名("products/show")など
# action_controller_method コントローラの返却するContent-type（text xml json nothingなど)
# template: 上記を明示的にするオプション（付けなくても良い）
# file: ファイルであることを明示的にするオプション
# inline: テンプレートを使用せず、HTMLパーツなどを出力する場合に使用する
# type: ビルダー(ERBビルダなど）を指定。指定しなければerb形式
# plain: "OK"

```
* [renderメソッド リファレンス](https://qiita.com/A-Like/items/4d448fae2a2da33d9df2)

```ruby
header
```

* フィルタ

```ruby
# 実行順序ごと
prepend_around_action
prepend_before_action
before_action
around_action
append_before_action
append_around_action
append_after_action
after_action
prepend_after_action
after_filter # ※Rails 5から非推奨
before_filter # ※Rails 5から非推奨
```


#### Rails ルーティング

#### ノウハウ
* Rails4 でxx_filterはxx_actionに移行
  * [Rails4でアクションの前後にフィルタ/処理を挟み込む](https://ruby-rails.hatenadiary.com/entry/20141129/1417223453)



### ActiveRecord

### ポリモーフィック
* [Rails4でポリモフィックのリレーションを実装する](https://ruby-rails.hatenadiary.com/entry/20141207/1417926599)

#### ポリモフィックリレーションとは
* ポリモフィックリレーションがどのようなものであるかを以下の図.textを用いて説明する
  * コメントはどのようなページでも同じような項目となるため、コメントテーブルとして切り出す
  * コメントは複数投稿することができる
  * コメントテーブルは参照先となるテーブルをArticleかCaseのどちらかをもつようにする
  * このような関連をポリモフィック関連という

```図.text
[記事(Article)]
id
string title
string context
string image_url

            [コメント(Comment)]
            	id
            	string title
            	string context
            	integer good
            	integer bad
            	integer reply_id
            	string comment_type

[事例(Case)]
	id
	string title
	string context
	string image_url

```

#### ActiveModelでの実装方法
* Generator
  * rails g model case title:string context:text image_url:string
  * rails g model article title:string context:text image_url:string
  * rails g model comment title:string context:text good:integer bad:integer reply_id:integer commentable_id:integer commentable_type:string
* Migration File
```yyyymmddhhMMss_create_comments.rb
class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.string :title
      t.text :context
      t.integer :good
      t.integer :bad
      t.integer :reply_id
      t.integer :commentable_id
      t.string :commentable_type

      t.timestamps
    end

    add_index :comments, [:commentable_id, :commentable_type]
  end
end
```
* マイグレーション
  * rake db:migrate

* アソシエーション設定
  * has_manyとbelongs_toを追加		
```app/models/comment.rb

class Comment < ActiveRecord::Base
  belongs_to :commentable, polymorphic: true
end

```

```app/models/event.rb
class Event < ActiveRecord::Base
  has_many :comments, as: :commentable
end
```

```app/models/article.rb
class Article < ActiveRecord::Base
  has_many :comments, as: :commentable
end
```

### Features
#### RSpec
* [RSpecチートシート](https://qiita.com/morrr/items/6ed889d17abbfd352649)
* [Rails：Rspecのテスト実行コマンドについて](https://tyoshikawa1106.hatenablog.com/entry/2015/07/21/233433)

#### Factory_bot
* インストール
  * Gemインストール
  * rspec導入
  * [RailsアプリへのRspecとFactory_botの導入手順](https://qiita.com/Ushinji/items/522ed01c9c14b680222c)

```ruby:Gemfile
group :development, :test do
  gem 'rspec-rails'
  gem "factory_bot_rails"
end
```

```bash
bundle exec rails generate rspec:install
```

* リファレンス

**データ定義**

| シグネチャ | 仕組みなど | サンプル |
|:-------|:---------|:--------|
| FactoryBot.define do %block% end | Factory botのデータ定義を宣言 |
| factory :%model_name% do %block% end | データ定義を宣言した内部でどのモデルのデータを作成するか宣言する部分（実質ここで実装） |



成する | factory_bot_create_list.rb |
| create_list(:%model_name%, %create_count%) | 指定のcount分、レコードを作成する | factory_bot_create_list.rb |

**レシーブ**

| シグネチャ | 仕組みなど | サンプル |
|:-------|:---------|:--------|
| create(:%model_name%) | DBレコード作成 | factory_bot_create.rb |
| build(:%model_name%) | モデルのオブジェクト作成(DB未登録) | factory_bot_build.rb |
| create_list(:%model_name%, %create_count%) | 指定のcount分、レコードを作成する | factory_bot_create_list.rb |

**spec内での呼び出し**

```ruby
before do 
    @user = build(:user)
end
```

当該スペックコードを実行すると自動でオブジェクトが生成される

```bash:terminal
rspec spec/acceptance/api/v1/alerts_spec.rb:22
```

### リファレンス
#### テーブル
| 機能 | 仕組み・固有機能 | 名称 | シグネチャ | 仕組みなど | サンプル |
|:-----|:---------------|:----|:-------|:---------|:--------|
| ActionController | フィルタ | skip_before_action | - | 特定のアクションでフィルタを止めることができる<br>before_actionフィルタに対する停止 | action_controller_skip_before_action.rb |
| ActionController | フィルタ | skip_after_action | - | 特定のアクションでフィルタを止めることができる<br>after_actionフィルタに対する停止 | action_controller_skip_after_action.rb |
| ActionController | フィルタ | prepend_around_action | - | フィルタ<br>フィルタ起動順：１ | action_controller_prepend_around_action.rb |
| ActionController | フィルタ | prepend_before_action | - | フィルタ<br>フィルタ起動順：２ | action_controller_prepend_before_action.rb |
| ActionController | フィルタ | before_action | - | アクション実行前のフィルタ<br>フィルタ起動順：３ | action_controller_before_action.rb |
| ActionController | フィルタ | around_action | - | アクション実行時のフィルタ<br>フィルタ起動順：４ | action_controller_around_action.rb |
| ActionController | フィルタ | append_before_action | - | フィルタ<br>フィルタ起動順：５ | action_controller_append_before_action.rb |
| ActionController | フィルタ | append_around_action | - | フィルタ<br>フィルタ起動順：６ | action_controller_append_around_action.rb |
| ActionController | フィルタ | append_after_action | - | フィルタ<br>フィルタ起動順：７ | action_controller_append_after_action.rb |
| ActionController | フィルタ | after_action | - | アクション実行後のフィルタ<br>フィルタ起動順：８ | action_controller_after_action.rb |
| ActionController | フィルタ | prepend_after_action | - | フィルタ<br>フィルタ起動順：９ | action_controller_prepend_after_action.rb |
| ActiveModel | 検索 | none | - | 空のモデルオブジェクトを取得 | active_model_none.rb |
| ActiveModel | 変換 | pluck | ActiveRecord_Relation.pluck(symbol, [symbol]... | 指定のカラムのみの配列を取得<br>*但し、戻り値がActiveRecord_Relationクラスを継承したオブジェクトかArrayクラスのオブジェクト | active_model_pluck.rb |
| ActiveModel | 検索 | without_soft_destroyed | - | kakurenbo-putiによる論理削除 | active_model_without_soft_destroyed.rb |
| ActiveSupport | 変換 | classify | - | テーブル名からモデルクラス名へ変換 | active_support_classify.rb |


#### サンプルコード

```action_controller_skip_before_action.rb
class LoginsController < ApplicationController
  skip_before_action :require_login, only: [:new, :create]
end
# LoginsControllerのnewアクションとcreateアクションをこれまでどおり認証不要にすることができる
```
* [Rails controller内でのcallbackの順番](https://qiita.com/fortissimo1997/items/6d15f26a1f468952d103)

```action_controller_skip_after_action.rb
class LoginsController < ApplicationController
  skip_after_action :verify_authorized, if: proc { ("Api::V1::" + "#{controller_name}_loyalty".camelize).safe_constantize.present? }, only: [:new, :create]
end
# LoginsControllerのnewアクションとcreateアクションであるファイルが存在する場合のみ認証不要にすることができる
```
* [skip_after_action](https://apidock.com/rails/v4.2.7/AbstractController/Callbacks/ClassMethods/skip_after_action)


```active_model_none.rb
User.none # => []
```


```active_model_pluck.rb
User.all
[#<User:0x000000000785f5c8
  id: 3,
  prefecture_id: nil,
  name: "ホゲホゲ",
  address: nil,
  email: "hogehoge+1@hoge.com",
  password_digest: "$2a$10$ArMoILf5lSLh28C/aLJYtOLYtIbK6GGrbCUF9oxkGLeazBnakVDoe",
  firebase_cloud_messaging_token: "your_devise_token",
  gender: nil,
  birthday: nil,
  created_at: Tue, 09 Oct 2018 04:10:45 UTC +00:00,
  updated_at: Tue, 09 Oct 2018 04:11:09 UTC +00:00,
  agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36",
]
User.all.pluck(:email) #=> ["hogehoge+1@hoge.com"]

# allメソッドは対応
Shop.all.class
=> Shop::ActiveRecord_Relation
Shop.all.pluck(:id)
   (2.1ms)  SELECT `shops`.`id` FROM `shops`
=> [3]
# find_by_sqlは対応
Shop.find_by_sql("select * from shops where name= 'コマドリぃむ'").class
  Shop Load (1.3ms)  select * from shops where name= 'コマドリぃむ'
=> Array
Shop.find_by_sql("select * from shops where name= 'コマドリぃむ'").pluck(:name)
  Shop Load (3.1ms)  select * from shops where name= 'コマドリぃむ'
=> ["コマドリぃむ"]
# whereは対応
Shop.where(name: 'コマドリぃむ').class
=> Shop::ActiveRecord_Relation
Shop.where(name: 'コマドリぃむ').pluck(:name)
   (0.8ms)  SELECT `shops`.`name` FROM `shops` WHERE `shops`.`name` = 'コマドリぃむ'
=> ["コマドリぃむ"]
# find_by_columnは非対応
Shop.find_by_name('コマドリぃむ').class
  Shop Load (1.2ms)  SELECT  `shops`.* FROM `shops` WHERE `shops`.`name` = 'コマドリぃむ' LIMIT 1
=> Shop(id: integer, prefecture_id: integer, payday_type: string, payday_id: integer, started_at: datetime, remind_day: integer, shift_cutoff_date_type: string, shift_cutoff_date_id: integer, work_cutoff_date_type: string, work_cutoff_date_id: integer, name: string, address: string, cast_code: string, extra_wage_pay_rate: decimal, deadline_to_submit_shift: integer, minimum_shift_registered_days: integer, minimum_working_minutes: integer, dummy_flag: boolean, latitude: decimal, longitude: decimal, created_at: datetime, updated_at: datetime, status: integer, closed: boolean, pay_in_month: integer, calc_extra: boolean, extra_rate: decimal, calc_midnight: boolean, midnight_rate: decimal, auto_rest_flag: boolean, write_rest_permission: integer)
Shop.find_by_name('コマドリぃむ').pluck(:name)
  Shop Load (1.0ms)  SELECT  `shops`.* FROM `shops` WHERE `shops`.`name` = 'コマドリぃむ' LIMIT 1
NoMethodError: undefined method `pluck' for #<Shop:0x0000000008d94038>
from /usr/local/bundle/gems/activemodel-5.1.4/lib/active_model/attribute_methods.rb:432:in `method_missing'
# find_byは非対応
[37] pry(main)> res = Shop.find_by name: 'コマドリぃむ'; res.class
  Shop Load (0.9ms)  SELECT  `shops`.* FROM `shops` WHERE `shops`.`name` = 'コマドリぃむ' LIMIT 1
=> Shop(id: integer, prefecture_id: integer, payday_type: string, payday_id: integer, started_at: datetime, remind_day: integer, shift_cutoff_date_type: string, shift_cutoff_date_id: integer, work_cutoff_date_type: string, work_cutoff_date_id: integer, name: string, address: string, cast_code: string, extra_wage_pay_rate: decimal, deadline_to_submit_shift: integer, minimum_shift_registered_days: integer, minimum_working_minutes: integer, dummy_flag: boolean, latitude: decimal, longitude: decimal, created_at: datetime, updated_at: datetime, status: integer, closed: boolean, pay_in_month: integer, calc_extra: boolean, extra_rate: decimal, calc_midnight: boolean, midnight_rate: decimal, auto_rest_flag: boolean, write_rest_permission: integer)
res.pluck(:name)
NoMethodError: undefined method `pluck' for #<Shop:0x0000000008dfc7c8>
from /usr/local/bundle/gems/activemodel-5.1.4/lib/active_model/attribute_methods.rb:432:in `method_missing'

```

```active_model_without_soft_destroyed.rb
class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable, :confirmable, :timeoutable
  soft_deletable

  def self.hoge(hoge_conditions)
    without_soft_destroyed.where(email: hoge_conditions[:email]).first
  end
end

```
マイグレーション時に```rails g migration AddSoftDestroyedAtToUser soft_destroyed_at:datetime:index```のようにsoft_destroyed_atを指定
ActiveModelクラスにsoft_deletableメソッドを実装しておきます
論理削除対象を取得しないようにwithout_soft_destroyedメソッドをコールする


```active_support_classify.rb
```

### コードハック

#### ActiveRecordの絞り込み

* Object.send + ActiveRecord scope

```ruby:app/models/hogehoge.rb
Hogehoge < ApplicationRecord
    belongs_to :hage

  scope :since, -> since_at { where('started_at >= ?', since_at) }
  scope :till, -> till_at { where('ended_at <= ?', till_at) }
end
```
```ruby:app/contlloers/baka/hogehoges_controller.rb
module Baka
  class HogehogesController < ApplicationController

  def resource_collection
    scope = Hogehoge
    scope = scope.send(:since, params[:since]) if params[:since].present? # Object.sendでレシーバーのメソッドを実行する（シンボル指定）
    scope = scope.send(:till, params[:till]) if params[:till].present?    # Object.sendでレシーバーのメソッドを実行する（シンボル指定）
    scope = scope.order(:user_id)
    scope = scope.group(:user_id)
    scope
  end

  def index
    render json: current_resources, each_serializer: HogehogeSerializer, include: include_resources, root: root_elements_name, status: :ok
  end

  private(*delegate(:model_class_name, :include_resources, :resource_collection, to: :class))
end
```

```ruby:app/serializers/hogehoge_serializer.rb
class HogehogeSerializer < ApplicationSerializer
  attributes :user_id,
             :detail

  def detail
    return unless object.user_groups
    ActiveModel::Serializer::CollectionSerializer.new(object.user_groups, serializer: HogehogeUserGroupSerializer)
  end

  class HogehogeUserGroupSerializer < ApplicationSerializer
    attributes :post_address,
               :post_date,
               :tax,
               :send_amount,
               :amount
  end
end
```

```ruby:app/models/hogehoge.rb
class Hogehoge < ApplicationRecord
  def user_groups
    Hogehoge.select(:post_address, :post_date, :tax, :send_amount :amount).where('user_id = ?', user_id)
    # Alert.where('employee_id = ?', employee_id)
    # Alert.find_by(employee_id: employee_id)
  end
end
```

```ruby:spec/factories/hogehoge.rb
FactoryBot.define do
  factory :hogehoge do
    zip_code { %w[100-0011 100-0001 140-0001 ...略... 999-9999].sample }
    prefecture { %w[Hokkaido Aomori Iwate ...略... Okinawa].sample }
    city { %w[Mito Ichinohe Sinagawa].sample }
    address { %w[Hogehoge Hagehage Fugafuga].sample }
    delivery_at 6.days.ago.iso8601(3)

    after :build do |hogehoge|
      hogehoge.order ||= build(:order)
    end
  end
end
```

```ruby:spec/acceptance/hogehoge_spec.rb
require 'rails_helper'
require 'rspec_api_documentation/dsl'

resource 'Hogehoges (何か)' do
  include_context 'Common factories'

  header 'Content-Type', 'application/json'

  before(:each) do
    FactoryBot.create(:user, email: 'test@example.com', name: 'テストユーザー', password: 'testtest')
    FactoryBot.create(:shop, name: '何か確認用店舗', closed_type: false) do |s|
      FactoryBot.create(:item, name: '何か商品', category: Category.hage, size: 'width:100,height:20,color:cyan', unit_price: 15_000)
    end
    FactoryBot.create_list(:hogehoge, 2, user: User.first)
  end
  get '/api/hogehoges' do
    header 'Authorization', :token

    let(:token) { jwt_token(user: employee) }

    parameter :since, '検索開始期間'
    parameter :till, '検索終了期間'

    let(:since) { 7.days.ago.iso8601(3) }
    let(:till) { 7.days.from_now.iso8601(3) }

    before(:each) do
      do_request
    end

    example '01. 何かの一覧' do
      puts response_body
      expect(status).to eq 200
    end
  end
end
```