Ruby on Railsとは
設計思想
- 編集中
Ruby on Railsリファレンス
ガイド
モデル
Active Record の基礎
Active Record マイグレーション
マイグレーション確認
rails db:migrate:status
up 20181001000000 Create Hogehoge Tables
up 20181001000010 Add Columns to Hages
down 20181001000020 Add Columns to Fugas
# up コミットが完了したもの
# down コミットしていないもの
マイグレーションロールバック
# 直前のマイグレーションコミットをロールバックする
rails db:rollback
# %n%つ前のマイグレーションバージョンにロールバックする
rails db:rollback STEP=%n%
マイグレーションロールバック+コミット
# %n%つ前のマイグレーションバージョンにロールバックし、再度マイグレーションコミットする
rails db:migrate:redo STEP=%n%
# 内部処理についてはマイグレーションコミットの項を参照
マイグレーションコミット
# %yyyyMMddHHmmss%接頭辞を持つマイグレーションバージョンのスクリプトをコミットする
rails db:migrate VERSION=%yyyyMMddHHmmss%
# 実行していないマイグレーションバージョンのスクリプトをコミットする
rails db:migrate
db:migrate(マイグレーションコミット)が実行されると、内部処理でdb:schema:dumpタスクも実行される
db:schema:dumpタスクはdb/schema.rbスキーマファイルを更新し、スキーマがデータベースの構造に一致する
マイグレーションスクリプト
- クラス・マイグレーションファイル名の命名規則
# カラム追加
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文が自動生成される
# 例
rails g migration AddMailAddressToUsers mail_address:string
上記で自動生成されるソース
class AddMailAddressToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :mail_address, :string
end
end
マイグレーションスクリプトの生成
# index インデックスを追加する
rails g[enerate] migration Add%Column_Camel_Case%To%Table_Name_Camel_Case% %column_snake_case%:%type%[:index]
上記で自動生成されるソース
class AddMailAddressToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :mail_address, :string
add_index :users, :mail_address
end
end
自作マイグレーションの為のメソッド
# 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
自作マイグレーションのメソッド内で定義可能なメソッド
# 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
# 文字列型
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のデータ遡及にも応用可能
# テーブルの制約を付ける
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
# 遡及
# 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はデフォルトでは1000件ずつSELECTする
- 登録・更新・削除メソッドでは!を使用する
- save / create / update / removeなどではエラーを握りつぶすので注意
- Migrationのassertionでデータ妥当性を担保する
- fail 'Illegal argument user_delivery' unless order.user_delivery.present?
- up / downコマンドのテストは欠かさず実行する
- Rails で信頼性の高い Migration を書くには
トラブルシューティング
-
ActiveRecord::IrreversibleMigration
- マイグレーションが逆転不可能な場合に発生する
-
マイグレーションのステータス確認で********** NO FILE **********が出た場合
-
マイグレーションに失敗した場合
- migrateはup/downで制御するかreset(db resetされるのであまり好ましくない)
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している場合
#失敗した時用のup/downをアンコメントしてupを実行する
rails db:migrate # ここから
rails db:migrate:down VERSION=20181001000001
# イグレーションスクリプトを修正する
# 失敗した時用のup/downをコメントアウト ここまで
# 成功するまでここからここまでを繰り返す
upしている場合
恐らく失敗しているのでupしている事はないかと思われる
Active Record バリデーション
ビルトイン関数
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)
- belongs_toとの併用可能(アソシエーション側のafter_touchコールバックも実行される)
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のオプションされたアソシーエションでコールバックが実行される
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]のワナ?
Railsのflashをクリアする
flash
ビルトイン関数
redirect_to
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"
header
- フィルタ
# 実行順序ごと
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に移行
ActiveRecord
ポリモーフィック
ポリモフィックリレーションとは
- ポリモフィックリレーションがどのようなものであるかを以下の図.textを用いて説明する
- コメントはどのようなページでも同じような項目となるため、コメントテーブルとして切り出す
- コメントは複数投稿することができる
- コメントテーブルは参照先となるテーブルをArticleかCaseのどちらかをもつようにする
- このような関連をポリモフィック関連という
[記事(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_typet.timestamps
endadd_index :comments, [:commentable_id, :commentable_type]
end
end
``` -
マイグレーション
- rake db:migrate
-
アソシエーション設定
- has_manyとbelongs_toを追加
```app/models/comment.rb
- has_manyとbelongs_toを追加
class Comment < ActiveRecord::Base
belongs_to :commentable, polymorphic: true
end
```app/models/event.rb
class Event < ActiveRecord::Base
has_many :comments, as: :commentable
end
class Article < ActiveRecord::Base
has_many :comments, as: :commentable
end
Features
RSpec
Factory_bot
- インストール
- Gemインストール
- rspec導入
- RailsアプリへのRspecとFactory_botの導入手順
group :development, :test do
gem 'rspec-rails'
gem "factory_bot_rails"
end
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内での呼び出し
before do
@user = build(:user)
end
当該スペックコードを実行すると自動でオブジェクトが生成される
rspec spec/acceptance/api/v1/alerts_spec.rb:22
リファレンス
テーブル
機能 | 仕組み・固有機能 | 名称 | シグネチャ | 仕組みなど | サンプル |
---|---|---|---|---|---|
ActionController | フィルタ | skip_before_action | - | 特定のアクションでフィルタを止めることができる before_actionフィルタに対する停止 |
action_controller_skip_before_action.rb |
ActionController | フィルタ | skip_after_action | - | 特定のアクションでフィルタを止めることができる after_actionフィルタに対する停止 |
action_controller_skip_after_action.rb |
ActionController | フィルタ | prepend_around_action | - | フィルタ フィルタ起動順:1 |
action_controller_prepend_around_action.rb |
ActionController | フィルタ | prepend_before_action | - | フィルタ フィルタ起動順:2 |
action_controller_prepend_before_action.rb |
ActionController | フィルタ | before_action | - | アクション実行前のフィルタ フィルタ起動順:3 |
action_controller_before_action.rb |
ActionController | フィルタ | around_action | - | アクション実行時のフィルタ フィルタ起動順:4 |
action_controller_around_action.rb |
ActionController | フィルタ | append_before_action | - | フィルタ フィルタ起動順:5 |
action_controller_append_before_action.rb |
ActionController | フィルタ | append_around_action | - | フィルタ フィルタ起動順:6 |
action_controller_append_around_action.rb |
ActionController | フィルタ | append_after_action | - | フィルタ フィルタ起動順:7 |
action_controller_append_after_action.rb |
ActionController | フィルタ | after_action | - | アクション実行後のフィルタ フィルタ起動順:8 |
action_controller_after_action.rb |
ActionController | フィルタ | prepend_after_action | - | フィルタ フィルタ起動順:9 |
action_controller_prepend_after_action.rb |
ActiveModel | 検索 | none | - | 空のモデルオブジェクトを取得 | active_model_none.rb |
ActiveModel | 変換 | pluck | ActiveRecord_Relation.pluck(symbol, [symbol]... | 指定のカラムのみの配列を取得 *但し、戻り値が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 |
サンプルコード
class LoginsController < ApplicationController
skip_before_action :require_login, only: [:new, :create]
end
# LoginsControllerのnewアクションとcreateアクションをこれまでどおり認証不要にすることができる
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アクションであるファイルが存在する場合のみ認証不要にすることができる
User.none # => []
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'
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メソッドをコールする
コードハック
ActiveRecordの絞り込み
- Object.send + ActiveRecord scope
Hogehoge < ApplicationRecord
belongs_to :hage
scope :since, -> since_at { where('started_at >= ?', since_at) }
scope :till, -> till_at { where('ended_at <= ?', till_at) }
end
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
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
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
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
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