WEBサービス創造記

WEBサービスを作ったり保守したりしてる人のメモブログです。

acts_as_paranoidのインストールと使い方

      2015/06/13

acts_as_paranoidとは

acts_as_paranoidは、データを論理削除するためのプラグイン。
findで自動的に論理削除したものを除いて検索できたり、destroyするとリレーションが設定されているテーブルのデータにも削除フラグを立ててくれたりする。

※物理削除は、delete文でデータそのものをデータベースから削除することで、論理削除とは削除済みかどうかのフラグを持たせるだけでデータそのものは残してある状態。

acts_as_paranoidのインストール

$ gem install rails3_acts_as_paranoid

もしくはGemfileに以下の一行を追加してbundle install

gem 'rails3_acts_as_paranoid'

acts_as_paranoidの設定

動作確認用のデータベース設定

acts_as_paranoidの動作確認を行うために以下のようなテーブルを用意した。

$ rails generate model group name:string deleted_at:datetime
$ rails generate model person group:references name:string age:integer sex:integer deleted_at:datetime
$ rake db:migrate

GroupとPersonは一対多のリレーションをもっている。
acts_as_paranoidにおける論理削除のフラグとして利用するカラムの名称としては”deleted_at”が一般的なようなので、各テーブルではこのカラムを作成した。

以下をseeds.rbに追記して、rake db:seedを実行し、動作確認用のデータをテーブルに挿入する。

Group.create(:name => 'adult_male')
Group.create(:name => 'adult_female')
Group.create(:name => 'boy')
Group.create(:name => 'girl')

Person.create(:group_id => 1, :name => 'Bob', :age => 33, :sex => 1)
Person.create(:group_id => 3, :name => 'Mark', :age => 12, :sex => 1)
Person.create(:group_id => 4, :name => 'Ava', :age => 8, :sex => 2)
Person.create(:group_id => 1, :name => 'George', :age => 24, :sex => 1)
Person.create(:group_id => 2, :name => 'Olivia', :age => 21, :sex => 2)

モデル編集

app/models/group.rbとapp/models/person.rbを以下のように編集。

class Group < ActiveRecord::Base
  acts_as_paranoid
  has_many :people, :dependent => :destroy
end

class Person < ActiveRecord::Base acts_as_paranoid belongs_to :group end [/ruby]

※”acts_as_paranoid”という1行を追加するだけ

acts_as_paranoidの使い方

動作確認用のモデルの準備ができたら、動作確認もかねてacts_as_paranoidの使い方を試してみる。
※動作確認はrails console上で行う

$ rails console

レコードの削除

通常通り、destroyで削除ができるが、acts_as_paranoidによる論理削除が有効となる。

ruby-1.9.2-p290 > george = Person.find(4)
ruby-1.9.2-p290 > george.destroy

上記コマンド実行後にDBを確認すると、

mysql> select * from people;
+----+----------+--------+------+------+---------------------+---------------------+---------------------+
| id | group_id | name   | age  | sex  | deleted_at          | created_at          | updated_at          |
+----+----------+--------+------+------+---------------------+---------------------+---------------------+
|  1 |        1 | Bob    |   33 |    1 | NULL                | 2011-10-19 23:05:23 | 2011-10-19 23:05:23 |
|  2 |        3 | Mark   |   12 |    1 | NULL                | 2011-10-19 23:05:23 | 2011-10-19 23:05:23 |
|  3 |        4 | Ava    |    8 |    2 | NULL                | 2011-10-19 23:05:23 | 2011-10-19 23:05:23 |
|  4 |        1 | George |   24 |    1 | 2011-10-19 23:14:25 | 2011-10-19 23:05:23 | 2011-10-19 23:05:23 |
|  5 |        2 | Olivia |   21 |    2 | NULL                | 2011-10-19 23:05:23 | 2011-10-19 23:05:23 |
+----+----------+--------+------+------+---------------------+---------------------+---------------------+

id4のdeleted_atに日付が入っている。これが論理削除の状態。
なお、destroy!のように!をつけることで物理削除を行うこともできる。

論理削除したレコードは、以下のコマンドで復帰させることができる。

ruby-1.9.2-p290 > Person.only_deleted.find(4).recover

また、今回のようにモデルに親子関係が設定されている場合は、親モデルであるGroupを削除すると、参照している小モデルのレコードも削除することができる。

ruby-1.9.2-p290 > Group.find(1).destroy
  Group Load (0.5ms)  SELECT `groups`.* FROM `groups` WHERE `groups`.`id` = 1 AND (groups.deleted_at IS NULL) LIMIT 1
   (0.5ms)  BEGIN
  Person Load (7.2ms)  SELECT `people`.* FROM `people` WHERE `people`.`group_id` = 1 AND (people.deleted_at IS NULL)
  SQL (0.4ms)  UPDATE `people` SET deleted_at = '2011-10-19 23:38:21' WHERE `people`.`id` = 1 AND (people.deleted_at IS NULL)
  SQL (0.2ms)  UPDATE `people` SET deleted_at = '2011-10-19 23:38:21' WHERE `people`.`id` = 4 AND (people.deleted_at IS NULL)
  SQL (0.2ms)  UPDATE `groups` SET deleted_at = '2011-10-19 23:38:21' WHERE `groups`.`id` = 1 AND (groups.deleted_at IS NULL)
   (345.9ms)  COMMIT
 => #<Group id: 1, name: "adult_male", deleted_at: "2011-10-19 23:38:21", created_at: "2011-10-19 23:05:23", updated_at: "2011-10-19 23:34:01">

下記のようにrecoverすれば、削除された小モデルのレコードも復元することができる。

ruby-1.9.2-p290 > Group.only_deleted.find(1).recover

小モデルのレコードを復元させたくない場合は、下記コマンドを実行。

ruby-1.9.2-p290 > Group.only_deleted.find(1).recover(:recursive => false)

レコードの検索

allで全データを取得するに、自動的に論理削除されているレコードが省かれる。

ruby-1.9.2-p290 > Person.all
  Person Load (0.5ms)  SELECT `people`.* FROM `people` WHERE (people.deleted_at IS NULL)

論理削除されているレコードも含めて取得する場合は下記コマンドを実行。

ruby-1.9.2-p290 > Person.with_deleted
  Person Load (1.0ms)  SELECT `people`.* FROM `people` 

論理削除されたレコードだけを取得する場合は下記コマンドを実行。

ruby-1.9.2-p290 > Person.only_deleted
  Person Load (0.5ms)  SELECT `people`.* FROM `people` WHERE (people.deleted_at IS NOT NULL)

 - Ruby on Rails , , , ,