OSDN Git Service

initialize repository
[traxi/context_monitor.git] / lib / context_monitor.rb
1 # -*- coding: utf-8 -*-
2 module ActiveRecord
3
4   # 作成時および更新時の情報を記録するモジュール。
5   module ContextMonitor
6
7     def self.included(base) # :ndoc:
8       base.extend(ClassMethods)
9     end
10
11     module ClassMethods
12       #
13       # モデルクラスで呼び出すことにより指定した対象の状況を記録するようになる。
14       #
15       # <tt>monitor</tt> : 記録する対象のモデルクラスの名前を指定する。
16       #                    デフォルトは <tt>User</tt>
17       #                    ここで使用するモデルクラスには current_id というクラスメソッドが
18       #           定義されている必要がある。
19       #
20       def context_monitor(target_model_name = :user, options = {})
21         model_name  = target_model_name.to_s.capitalize
22         suffix = (options[:suffix] || 'by').to_s
23         created = 'created_' + suffix
24         updated = 'updated_' + suffix
25
26         class_eval do
27           callbacks = Callbacks.new(model_name, created, updated)
28           before_create callbacks
29           before_update callbacks
30           belongs_to created, :class_name => model_name, :foreign_key => "#{created}_id"
31           belongs_to updated, :class_name => model_name, :foreign_key => "#{updated}_id"
32         end
33       end
34       alias monitor context_monitor
35     end
36
37     class Callbacks # :ndoc: all
38       def initialize(model_name, created, updated)
39         @model = model_name.constantize
40         @created_id = "#{created}_id"
41         @updated_id = "#{updated}_id"
42       end
43       def before_create(record)
44         record.write_attribute(@created_id, @model.current_id) if include_column_and_nil?(record, @created_id)
45         before_update record
46       end
47       def before_update(record)
48         record.write_attribute(@updated_id, @model.current_id) if include_column?(record, @updated_id)
49       end
50
51       private
52       def column_names(record)
53         @column_names ||= record.class.column_names
54       end
55
56       def include_column?(record, column)
57         column_names(record).include? column
58       end
59
60       def include_column_and_nil?(record, column)
61         include_column?(record, column) && record.read_attribute(column).nil?
62       end
63     end
64   end
65 end
66
67 ActiveRecord::Base.__send__(:include, ActiveRecord::ContextMonitor)
68