rails - ActiveRecord の コールバック
基本
- オブジェクトの生成・更新・削除のタイミングで呼び出されるメソッド
- トリガとなるイベント(validation,saveなど)の前(before)と後(after)に登録可能
- コールバックはメソッドチェーンに追加される。
- before_xxx で false を返すか例外を発生させると、それ以降の処理を停止させることができる (トランザクション中の場合は ROLLBACK を発生させる)
使い方
- before_xxxx/after_xxxx メソッドでコールバックとするメソッド名を登録
- メソッドを定義する
例
class Blog < ActiveRecord::Base after_save :saved_title protected after_validation :saved_title puts "Saved!!" end end
利用可能なコールバックの種類と実行順序
Create
- before_validation
- after_validation
- before_save
- around_save
- before_create
- around_create
- after_create
- after_save
Update
- before_validation
- after_validation
- before_save
- around_save
- before_update
- around_update
- after_update
- after_save
Destroy
- before_destroy
- around_destroy
- after_destroy
Find
- after_initialize
- after_find
条件付きのコールバック
:if/:unless を使うことで特定の条件のときのみコールバックを
実行させる/させないことができる
例
class SomeModel < ActiveRecord::Base before_save :some_action, if: :action_condition? protected def action_condition? end end
:if/:unless には、シンボル、文字列、手続きオブジェクトが指定できる
モデルから再利用する
クラスにコールバック名と同名のメソッドを定義し、コールバックメソッド
にオブジェクトを渡す。
class SomeCallback def before_save # ... end end class SomeModel < ActiveRecord::Base before_save SomeCallback.new end
rails - has_many through:
他対他 の関連を参照する
元々は他対他を直接参照できるようにするもの。
+-------+ +-----------+ +-----+ |Product| 1---n |OrderDetail| n---1 |Order| +-------+ +-----------+ +-----+
例えば、特定の Order中の Productを調べたい場合など。
class Product < ActiveRecord::Base has_many :order_details has_many :orders, through: :order_details end class Order < ActiveRecord::Base has_many :order_details has_many :products, through: :order_details end class OrderDetail < ActiveRecord::Base belongs_to :product belongs_to :order end
こうすると、
@orders = @product.orders
として参照できる
カスケードした関連を直接参照する
+----+ +----+ +-----+ |User| 1---n |Blog| 1---n |Entry| +----+ +----+ +-----+
User から Entry のアイテムを直接参照できるようにする。
class User < ActiveRecord::Base has_many :blogs has_many :entries, through: :blogs end class Blog < ActiveRecord::Base has_many :entries belongs_to :user end class Entry < ActiveRecord::Base belongs_to :blog end
次のように参照できる。
@user.entries
ただし、次のように作成することはできない。
@user.entries.create title: "ほげ"
1対多のカスケードとなっているため Blog が特定できない。
Blog の id を指定し追加する。
@blog = Blog.find @blog_id @blog.entries.create title: "ほげ"
rails - ActiveRecord Migration のまとめ
基本
- db/migration 以下に YYYYMMDDhhmmdd_XXX_YYY.rb のファイルを作成する
- Migrationのファイル名とクラス名は一致していないとダメ
-
- ファイル名: YYYYMMDDhhmmdd_create_users.rb
- クラス名: CreateUsers
- 自分で設定ファイルを作成可能だが 基本的には rails generate migrationコマンドを使用する。
- DBに反映するには、
rake db:migrate
を実行する
- ロールバックは、
rake db:rollback
を実行する
-
- reversible なコマンド(create_table/add_columnなど)については追加不要
- カラム名の変更などは手動で定義する必要がある
CreateXXX - テーブルを作成する
$ rails generate migration CreateUsers
自動的に create_table が追加される。
テーブル名は複数形になる。
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| end end end
同時にカラムの定義も可能。
引数に カラム名:型[:オプション(省略可)] (複数可) を指定する。
型省略時は string になる。
$ rails generate migration CreateUsers name:string email:string
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :email end end end
AddYYYToXXX - カラムの追加する
カラムの追加。To以下にテーブル名を指定する。
$ rails generate migration AddNameAndEmailToUsers name:string email:string
db/migrate/20140218112618_add_name_and_email_to_users.rb
class AddNameAndEmailToUsers < ActiveRecord::Migration def change add_column :users, :name, :string add_column :users, :email, :string end end
RemoveYYYToXXX - カラムを削除する
カラムの削除。追加時と同じく To以下にテーブル名を指定する。
$ rails generate migration RemoveEmailToUsers email:string
db/migrate/20140218112720_remove_email_to_users.rb
class RemoveEmailToUsers < ActiveRecord::Migration def change remove_column :users, :email, :string end end
AddYYYRefToXXX - 外部テーブルへの参照を作成する
名前が user_id のカラムが追加され、インデックスが貼られる。
外部キー制約は設定されない(DBではなくモデル側でチェックを
するポリシーのため)。
$ rails generate migration AddUserRefToBlogs user:references
db/migrate/20140218114718_add_user_ref_to_blogs.rb
class AddUserRefToBlogs < ActiveRecord::Migration def change add_reference :blogs, :user, index: true end end
migration の状態を調べる
$ rake db:migrate:status database: /home/babiy/work/testapp/db/development.sqlite3 Status Migration ID Migration Name -------------------------------------------------- up 20140218082310 Create users up 20140218082651 Add name and email to users ||<