record_with_operator 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .idea/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in record_with_operator.gemspec
4
+ gemspec
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ = RecordWithOperator
2
+
3
+ == Introduction
4
+
5
+ RecordWithOperator is a rails plugin that makes your all active record models to be saved or logically deleted with created_by, updated_by, deleted_by automatically.
6
+ Also it makes creator, updater, deleter association (belongs_to) if the class has created_by, updated_by, deleted_by.
7
+
8
+ You need to set 'operator' (it may be an User object) to the instance of the model you are trying to create/save/update/delete.
9
+ (This cannot happen automatically as the current_user is stored in the session which models cannot access.)
10
+ Once you have set an operator, it will be copied to objects in the association collection, so it might be enough to set an operator per request.
11
+ Operators are also useful for your access control features on model's side.
12
+ To set an operator, simply use operator= or get objects by find method with :for option.
13
+
14
+ The logical deletion function itself is out of this plugin's scope.
15
+ This plugin assumes that the logical deletion is kicked by record.destory.
16
+
17
+ == Installation
18
+
19
+ > ./script/plugin install git://github.com/bbuchalter/record_with_operator.git
20
+
21
+ == Example
22
+
23
+ Create Note table with nessisary attributes:
24
+ class CreateNotes < ActiveRecord::Migration
25
+ def self.up
26
+ create_table :users do |t|
27
+ t.string :body
28
+ t.operator_stamps #creates attributes for created_by, updated_by, deleted_by
29
+ t.timestamps
30
+ end
31
+ end
32
+
33
+
34
+ Create a new note object with current_user:
35
+
36
+ note = Note.create(:body => "This is my first note.", :operator => current_user)
37
+ # note.operator will be current_user
38
+ # note.created_by will be current_user.id
39
+
40
+ Get note objects with current_user:
41
+
42
+ notes = Note.find(:all, :for => current_user)
43
+ # notes.first.operator will be current_user
44
+ # notes.find_by_body("This is my first note.").operator will be current_user
45
+
46
+ Create note's comments:
47
+
48
+ note = Note.find(params[:id], :for => current_user)
49
+ note.comments.create!(:body => params[:comment_body])
50
+ # comment's operator will be automatically set and used as created_by
51
+
52
+ == Configuration
53
+
54
+ You can change the operator's class name by setting RecordWithOperator.config[:user_class_name].
55
+ The default is 'User'.
56
+ Note that it is required to change the value before the model's creator/updater/deleter is firstly called.
57
+ For example, you can write the code under config/initializers.
58
+
59
+ RecordWithOperator.config[:user_class_name] = "AdminUser"
60
+
61
+ It's also possible to modify options for creator/updater/deleter associations.
62
+ For example, in the case you use acts_as_paranoid and want to get creator/updater/deleter even if they are deleted,
63
+ the configuration will be look like this.
64
+
65
+ RecordWithOperator.config[:operator_association_options] = {:with_deleted => true}
66
+
67
+ Copyright (c) 2009-2010 Yasuko Ohba, released under the MIT license
@@ -0,0 +1,70 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/gempackagetask'
7
+
8
+ NAME = "record_with_operator"
9
+ AUTHOR = "Yasuko Ohba"
10
+ EMAIL = "y.ohba@everyleaf.com"
11
+ DESCRIPTION = "Rails plugin to set created_by, updated_by, deleted_by to ActiveRecord objects. Supports associations."
12
+ GITHUB_PROJECT = "record_with_operator"
13
+ HOMEPAGE = "http://github.com/nay/#{GITHUB_PROJECT}/tree"
14
+ BIN_FILES = %w( )
15
+ CLEAN.include ['pkg']
16
+
17
+ desc 'Default: run unit tests.'
18
+ task :default => :test
19
+
20
+ desc 'Test the record_with_operator plugin.'
21
+ Rake::TestTask.new(:test) do |t|
22
+ t.libs << 'lib'
23
+ t.libs << 'test'
24
+ t.pattern = 'test/**/*_test.rb'
25
+ t.verbose = true
26
+ end
27
+
28
+ desc 'Generate documentation for the record_with_operator plugin.'
29
+ Rake::RDocTask.new(:rdoc) do |rdoc|
30
+ rdoc.rdoc_dir = 'rdoc'
31
+ rdoc.title = 'RecordWithOperator'
32
+ rdoc.options << '--line-numbers' << '--inline-source'
33
+ rdoc.rdoc_files.include('README.rdoc')
34
+ rdoc.rdoc_files.include('lib/**/*.rb')
35
+ end
36
+
37
+ spec = Gem::Specification.new do |s|
38
+ s.name = NAME
39
+ s.version = VER
40
+ s.platform = Gem::Platform::RUBY
41
+ s.has_rdoc = true
42
+ s.extra_rdoc_files = ["README.rdoc", "MIT-LICENSE"]
43
+ s.rdoc_options += ['--line-numbers', '--inline-source']
44
+ s.summary = DESCRIPTION
45
+ s.description = DESCRIPTION
46
+ s.author = AUTHOR
47
+ s.email = EMAIL
48
+ s.homepage = HOMEPAGE
49
+ s.executables = BIN_FILES
50
+ s.bindir = "bin"
51
+ s.require_path = "lib"
52
+ s.test_files = Dir["test/*.{rb,yml}"]
53
+
54
+ s.add_dependency('activerecord', '>=2.2.0')
55
+
56
+ s.files = %w(README.rdoc Rakefile MIT-LICENSE) +
57
+ %w(install.rb uninstall.rb) +
58
+ Dir.glob("{bin,doc,lib,tasks,rails}/**/*")
59
+
60
+ end
61
+
62
+ Rake::GemPackageTask.new(spec) do |p|
63
+ p.need_tar = true
64
+ p.gem_spec = spec
65
+ end
66
+
67
+ desc 'Update gem spec'
68
+ task :gemspec do
69
+ open("#{NAME}.gemspec", "w").write spec.to_ruby
70
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ ActiveRecord::Base.instance_eval{include RecordWithOperator} unless ActiveRecord::Base.include?(RecordWithOperator)
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,34 @@
1
+ module AssociationWithOperator
2
+
3
+ def find(*args)
4
+ results = super
5
+ if results.kind_of? Array
6
+ results.each{|r| r.operator = proxy_owner.operator}
7
+ else
8
+ results.operator = proxy_owner.operator if results
9
+ end
10
+ results
11
+ end
12
+
13
+
14
+ def method_missing(method, *args)
15
+ results = super
16
+ unless ActiveRecord::NamedScope::Scope === results
17
+ if results.respond_to?(:operator=)
18
+ results.operator= proxy_owner.operator
19
+ elsif results.kind_of? Array
20
+ results.each{|r| r.operator = proxy_owner.operator if r.respond_to?(:operator=)}
21
+ end
22
+ end
23
+ results
24
+ end
25
+
26
+ def construct_join_attributes(associate)
27
+ join_attributes = super
28
+ if @owner.operator || associate.operator
29
+ join_attributes[:operator] ||= @owner.operator
30
+ join_attributes[:operator] ||= associate.operator
31
+ end
32
+ join_attributes
33
+ end
34
+ end
@@ -0,0 +1,8 @@
1
+ require 'active_record/connection_adapters/abstract/schema_definitions'
2
+ ActiveRecord::ConnectionAdapters::TableDefinition.class_eval do
3
+ def operator_stamps
4
+ column(:created_by, :integer)
5
+ column(:updated_by, :integer)
6
+ column(:deleted_by, :integer)
7
+ end
8
+ end
@@ -0,0 +1,167 @@
1
+ module RecordWithOperator
2
+ require 'helpers/migration_helper.rb'
3
+
4
+ def self.config
5
+ @config ||= {:user_class_name => "User", :operator_association_options => {}}
6
+ @config
7
+ end
8
+
9
+ attr_accessor :operator
10
+
11
+ def self.included(base)
12
+ class << base
13
+ def reflections_with_operator
14
+ create_operator_associations
15
+ reflections_without_operator
16
+ end
17
+ alias_method_chain :reflections, :operator
18
+
19
+ def operator_associations_created?
20
+ @operator_associations_created
21
+ end
22
+
23
+ def create_operator_associations
24
+ return if operator_associations_created?
25
+ @operator_associations_created = true
26
+
27
+ if self.table_exists?
28
+ belongs_to :creator, {:foreign_key => "created_by", :class_name => RecordWithOperator.config[:user_class_name]}.merge(RecordWithOperator.config[:operator_association_options]) if column_names.include?('created_by')
29
+ belongs_to :updater, {:foreign_key => "updated_by", :class_name => RecordWithOperator.config[:user_class_name]}.merge(RecordWithOperator.config[:operator_association_options]) if column_names.include?('updated_by')
30
+ belongs_to :deleter, {:foreign_key => "deleted_by", :class_name => RecordWithOperator.config[:user_class_name]}.merge(RecordWithOperator.config[:operator_association_options]) if column_names.include?('deleted_by')
31
+ end
32
+ end
33
+
34
+ def has_many_with_operator(*args, &extension)
35
+ options = args.extract_options!
36
+ # add AssociationWithOprator to :extend
37
+ if options[:extend]
38
+ options[:extend] = [options[:extend]] unless options[:extend].kind_of? Array
39
+ options[:extend] << AssociationWithOperator
40
+ else
41
+ options[:extend] = AssociationWithOperator
42
+ end
43
+ # add :set_operator to :before_add
44
+ if options[:before_add]
45
+ options[:before_add] = [options[:before_add]] unless options[:before_add].kind_of? Array
46
+ options[:before_add] << :set_operator
47
+ else
48
+ options[:before_add] = :set_operator
49
+ end
50
+ args << options
51
+ has_many_without_operator(*args, &extension)
52
+ end
53
+ alias_method_chain :has_many, :operator
54
+
55
+ def find_with_for(*args)
56
+ options = args.extract_options!
57
+ operator = options.delete(:for)
58
+ args << options
59
+ results = find_without_for(*args)
60
+ if operator
61
+ if results.kind_of? Array
62
+ results.each{|r| r.operator = operator}
63
+ elsif results
64
+ results.operator = operator
65
+ end
66
+ end
67
+ results
68
+ end
69
+
70
+ alias_method_chain :find, :for
71
+
72
+ # No longer valid in Rails 3
73
+ # def validate_find_options_with_for(options)
74
+ # if options
75
+ # options = options.dup
76
+ # options.delete(:for)
77
+ # end
78
+ # validate_find_options_without_for(options)
79
+ # end
80
+ #
81
+ # alias_method :validate_find_options, :validate_find_options_with_for
82
+
83
+ private
84
+ # define_method association, association= ...
85
+ def association_accessor_methods_with_operator(reflection, association_proxy_class)
86
+ association_accessor_methods_without_operator(reflection, association_proxy_class)
87
+ define_method("#{reflection.name}_with_operator") do |*params|
88
+ r = send("#{reflection.name}_without_operator", *params)
89
+ r.operator ||= self.operator if r && r.respond_to?(:operator=)
90
+ r
91
+ end
92
+ alias_method_chain "#{reflection.name}".to_sym, :operator
93
+
94
+ define_method("#{reflection.name}_with_operator=") do |new_value|
95
+ new_value.operator ||= self.operator if new_value.respond_to?(:operator=)
96
+ send("#{reflection.name}_without_operator=", new_value)
97
+ end
98
+ alias_method_chain "#{reflection.name}=".to_sym, :operator
99
+ end
100
+ alias_method_chain :association_accessor_methods, :operator
101
+
102
+ # define_method build_association, create_association ...
103
+ def association_constructor_method_with_operator(constructor, reflection, association_proxy_class)
104
+ association_constructor_method_without_operator(constructor, reflection, association_proxy_class)
105
+ define_method("#{constructor}_#{reflection.name}_with_operator") do |*params|
106
+ options = { :operator => self.operator }
107
+ params.empty? ? params[0] = options : params.first.merge!(options)
108
+ self.send("#{constructor}_#{reflection.name}_without_operator", *params)
109
+ end
110
+ alias_method_chain "#{constructor}_#{reflection.name}".to_sym, :operator
111
+ end
112
+ alias_method_chain :association_constructor_method, :operator
113
+ end
114
+
115
+ base.before_create :set_created_by
116
+ base.before_save :set_updated_by
117
+ base.before_destroy :set_deleted_by
118
+
119
+ end
120
+
121
+ def respond_to?(name, priv=false)
122
+ case name.to_sym
123
+ when :creator
124
+ respond_to? :created_by
125
+ when :updater
126
+ respond_to? :updated_by
127
+ when :deleter
128
+ respond_to? :deleted_by
129
+ else
130
+ super
131
+ end
132
+ end
133
+
134
+ private
135
+ def set_operator(child)
136
+ child.operator ||= self.operator
137
+ end
138
+
139
+ def method_missing(method, *args)
140
+ return super unless respond_to?(method)
141
+ case method.to_sym
142
+ when :creator, :updater, :deleter
143
+ self.class.create_operator_associations
144
+ send(method, *args)
145
+ else
146
+ super
147
+ end
148
+ end
149
+
150
+ def set_created_by
151
+ return unless respond_to?(:created_by=) && operator
152
+ self.created_by = operator.id
153
+ end
154
+
155
+ def set_updated_by
156
+ return unless respond_to?(:updated_by=) && operator && changed? # no use setting updating_by when it's not changed
157
+ self.updated_by = operator.id
158
+ end
159
+
160
+ def set_deleted_by
161
+ return unless self.class.column_names.include?("deleted_by") && operator
162
+ return if frozen?
163
+ self.class.update_all("deleted_by = #{operator.id}", ["#{self.class.primary_key} = ?", id])
164
+ self.deleted_by = operator.id
165
+ end
166
+
167
+ end
@@ -0,0 +1,3 @@
1
+ module RecordWithOperator
2
+ VERSION = "0.0.22"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :record_with_operator do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "record_with_operator/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "record_with_operator"
7
+ s.version = RecordWithOperator::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Yasuko Ohba"]
10
+ s.email = ["y.ohba@everyleaf.com"]
11
+ s.homepage = ""
12
+ s.summary = %q{Rails plugin to set created_by, updated_by, deleted_by to ActiveRecord objects. Supports associations.}
13
+ s.description = %q{Rails plugin to set created_by, updated_by, deleted_by to ActiveRecord objects. Supports associations.}
14
+
15
+ s.rubyforge_project = "record_with_operator"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in record_with_operator.gemspec
4
+ gemspec
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,3 @@
1
+ module RecordWithOperator
2
+ # Your code goes here...
3
+ end
@@ -0,0 +1,3 @@
1
+ module RecordWithOperator
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "record_with_operator/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "record_with_operator"
7
+ s.version = RecordWithOperator::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["TODO: Write your name"]
10
+ s.email = ["TODO: Write your email address"]
11
+ s.homepage = ""
12
+ s.summary = %q{TODO: Write a gem summary}
13
+ s.description = %q{TODO: Write a gem description}
14
+
15
+ s.rubyforge_project = "record_with_operator"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+ end
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: record_with_operator_plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: record_with_operator_plugin.sqlite3.db
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: record_with_operator_plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username:
17
+ :password:
18
+ :database: record_with_operator_plugin_test
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ class User < ActiveRecord::Base
4
+ end
5
+
6
+ class NoteBelongsToMemo < ActiveRecord::Base
7
+ set_table_name "notes"
8
+ belongs_to :memo
9
+ end
10
+
11
+ class Memo < ActiveRecord::Base
12
+ set_table_name "memos"
13
+ end
14
+
15
+ class RecordWithOperatorBelongsTo < ActiveSupport::TestCase
16
+ def setup
17
+ RecordWithOperator.config[:user_class_name] = "User"
18
+ @user1 = User.create!(:name => "user1")
19
+ @user2 = User.create!(:name => "user2")
20
+ @note_created_by_user1 = NoteBelongsToMemo.create!(:body => "test", :operator => @user1)
21
+ end
22
+
23
+ # belongs_to Association Test
24
+ # build_association
25
+ def test_build_memo_should_have_operator
26
+ note = NoteBelongsToMemo.find(@note_created_by_user1.id, :for => @user2)
27
+ memo = note.build_memo(:body => "memo")
28
+ assert_equal @user2, memo.operator
29
+ end
30
+
31
+ # create_association
32
+ def test_create_memo_should_have_operator_and_created_by
33
+ note = NoteBelongsToMemo.find(@note_created_by_user1.id, :for => @user2)
34
+ memo = note.create_memo(:body => "memo")
35
+ assert_equal false, memo.new_record?
36
+ assert_equal @user2, memo.operator
37
+ assert_equal @user2.id, memo.created_by
38
+ end
39
+
40
+ # association=
41
+ def test_memo_eql_should_have_operator_and_created_by
42
+ note = NoteBelongsToMemo.find(@note_created_by_user1.id, :for => @user2)
43
+ memo = Memo.new(:body => "memo")
44
+ note.memo = memo # not save
45
+ assert_equal @user2, memo.operator
46
+ end
47
+
48
+ # association
49
+ def test_auto_found_memo_should_have_operator
50
+ note = NoteBelongsToMemo.find(@note_created_by_user1.id, :for => @user2)
51
+ note.create_memo(:body => "memo")
52
+ assert_equal @user2, note.memo(true).operator
53
+ end
54
+
55
+ # association.nil?
56
+ def test_memo_nil_should_be_false_if_note_belongs_to_memo
57
+ note = NoteBelongsToMemo.find(@note_created_by_user1.id)
58
+ note.create_memo(:body => "memo")
59
+ assert !note.memo.nil?
60
+ end
61
+
62
+ # association.nil?
63
+ def test_memo_nil_should_be_true_if_note_is_independent
64
+ note = NoteBelongsToMemo.find(@note_created_by_user1.id)
65
+ assert note.memo.nil?
66
+ end
67
+ end
@@ -0,0 +1,45 @@
1
+ require 'test_helper'
2
+
3
+ class User < ActiveRecord::Base
4
+ end
5
+
6
+ class NoteWithUserWithDependency < ActiveRecord::Base
7
+ set_table_name "notes"
8
+ has_many :memos, :class_name => "MemoWithUser", :foreign_key => "note_id", :dependent => :destroy
9
+
10
+ protected
11
+ def before_destroy
12
+ raise "can't destroy without operator" unless operator
13
+ end
14
+ end
15
+
16
+ class MemoWithUserWithDependency < ActiveRecord::Base
17
+ set_table_name "memos"
18
+
19
+ protected
20
+ def before_destroy
21
+ raise "can't destroy without operator" unless operator
22
+ end
23
+ end
24
+
25
+
26
+ class RecordWithOperatorHasManyDependentTest < ActiveSupport::TestCase
27
+ def setup
28
+ RecordWithOperator.config[:user_class_name] = "User"
29
+ @user1 = User.create!(:name => "user1")
30
+ raise "@user1.id is nil" unless @user1.id
31
+ @user2 = User.create!(:name => "user2")
32
+ raise "@user2.id is nil" unless @user2.id
33
+ @note_created_by_user1 = NoteWithUserWithDependency.create!(:body => "test", :operator => @user1)
34
+ @note_created_by_user1.memos.create!
35
+ @note_created_by_user1.memos.create!
36
+ @note_created_by_user1.reload
37
+ end
38
+
39
+ def test_memos_should_be_destroyed_when_note_is_destroyed
40
+ @note_created_by_user1.destroy
41
+ assert_nil NoteWithUserWithDependency.find_by_id(@note_created_by_user1.id)
42
+ assert MemoWithUserWithDependency.find_all_by_note_id(@note_created_by_user1.id).empty?
43
+ end
44
+
45
+ end
@@ -0,0 +1,69 @@
1
+ require 'test_helper'
2
+
3
+ class User < ActiveRecord::Base
4
+ end
5
+
6
+ class NoteHasOneMemo < ActiveRecord::Base
7
+ set_table_name "notes"
8
+ has_one :memo, :class_name => "Memo", :foreign_key => "note_id"
9
+ end
10
+
11
+ class Memo < ActiveRecord::Base
12
+ set_table_name "memos"
13
+ end
14
+
15
+ class RecordWithOperatorHasOneAssociationTest < ActiveSupport::TestCase
16
+ def setup
17
+ RecordWithOperator.config[:user_class_name] = "User"
18
+ @user1 = User.create!(:name => "user1")
19
+ @user2 = User.create!(:name => "user2")
20
+ @note_created_by_user1 = NoteHasOneMemo.create!(:body => "test", :operator => @user1)
21
+ end
22
+
23
+ # has_one Association Test
24
+ # build_association
25
+ def test_build_memo_should_have_operator
26
+ note = NoteHasOneMemo.find(@note_created_by_user1.id, :for => @user2)
27
+ memo = note.build_memo(:body => "memo")
28
+ assert_equal @user2, memo.operator
29
+ end
30
+
31
+ # create_association
32
+ def test_create_memo_should_have_operator_and_created_by
33
+ note = NoteHasOneMemo.find(@note_created_by_user1.id, :for => @user2)
34
+ memo = note.create_memo(:body => "memo")
35
+ assert_equal false, memo.new_record?
36
+ assert_equal @user2, memo.operator
37
+ assert_equal @user2.id, memo.created_by
38
+ end
39
+
40
+ # association=
41
+ def test_memo_eql_should_have_operator_and_created_by
42
+ note = NoteHasOneMemo.find(@note_created_by_user1.id, :for => @user2)
43
+ memo = Memo.new(:body => "memo")
44
+ note.memo = memo
45
+ assert_equal false, memo.new_record?
46
+ assert_equal @user2, memo.operator
47
+ assert_equal @user2.id, memo.created_by
48
+ end
49
+
50
+ # association
51
+ def test_auto_found_memo_should_have_operator
52
+ note = NoteHasOneMemo.find(@note_created_by_user1.id, :for => @user2)
53
+ note.create_memo(:body => "memo")
54
+ assert_equal @user2, note.memo(true).operator
55
+ end
56
+
57
+ # association.nil?
58
+ def test_memo_nil_should_be_false_if_note_has_memo
59
+ note = NoteHasOneMemo.find(@note_created_by_user1.id)
60
+ note.create_memo(:body => "memo")
61
+ assert !note.memo.nil?
62
+ end
63
+
64
+ # association.nil?
65
+ def test_memo_nil_should_be_true_if_note_has_no_memo
66
+ note = NoteHasOneMemo.find(@note_created_by_user1.id)
67
+ assert note.memo.nil?
68
+ end
69
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ class User < ActiveRecord::Base
4
+ end
5
+
6
+ class NoteForReflectionTest < ActiveRecord::Base
7
+ set_table_name "notes"
8
+ end
9
+
10
+ class CreatorNoteForReflectionTest < ActiveRecord::Base
11
+ set_table_name "creator_notes"
12
+ end
13
+
14
+ class RecordWithOperatorReflectionTest < ActiveSupport::TestCase
15
+ def setup
16
+ RecordWithOperator.config[:user_class_name] = "User"
17
+ @user1 = User.create!(:name => "user1")
18
+ raise "@user1.id is nil" unless @user1.id
19
+ @note = NoteForReflectionTest.create!(:body => "test", :operator => @user1)
20
+
21
+ @creator_note = CreatorNoteForReflectionTest.create!(:body => "test", :operator => @user1)
22
+ end
23
+
24
+ def test_include
25
+ assert NoteForReflectionTest.find(:all, :include => [:creator, :updater])
26
+ end
27
+
28
+ def test_joins
29
+ assert NoteForReflectionTest.find(:all, :joins => [:creator, :updater])
30
+ end
31
+
32
+ def test_include_missing_association
33
+ assert_raise(ActiveRecord::ConfigurationError) { CreatorNoteForReflectionTest.find(:all, :include => [:updater]) }
34
+ end
35
+
36
+ def test_joins_missing_association
37
+ assert_raise(ActiveRecord::ConfigurationError) { CreatorNoteForReflectionTest.find(:all, :joins => [:updater]) }
38
+ end
39
+ end
@@ -0,0 +1,251 @@
1
+ require 'test_helper'
2
+
3
+ class User < ActiveRecord::Base
4
+ end
5
+
6
+ class NoteWithUser < ActiveRecord::Base
7
+ set_table_name "notes"
8
+ has_many :memos, :class_name => "MemoWithUser", :foreign_key => "note_id"
9
+
10
+ named_scope :new_arrivals, {:order => "updated_at desc"}
11
+
12
+ def destroy_without_callbacks
13
+ unless new_record?
14
+ self.class.update_all self.class.send(:sanitize_sql, ["deleted_at = ?", (self.deleted_at = default_timezone == :utc ? Time.now.utc : Time.now)]), ["#{self.class.primary_key} = ?", id]
15
+ end
16
+ freeze
17
+ end
18
+
19
+ def destroy_with_callbacks!
20
+ return false if callback(:before_destroy) == false
21
+ result = destroy_without_callbacks!
22
+ callback(:after_destroy)
23
+ result
24
+ end
25
+ def destroy!
26
+ transaction { destroy_with_callbacks! }
27
+ end
28
+
29
+ def deleted?
30
+ self.deleted_at.to_time <= Time.now
31
+ end
32
+ end
33
+
34
+ class SimpleNoteWithUser < ActiveRecord::Base
35
+ set_table_name "simple_notes"
36
+ end
37
+
38
+ class MemoWithUser < ActiveRecord::Base
39
+ set_table_name "memos"
40
+
41
+ named_scope :new_arrivals, {:order => "updated_at desc"}
42
+ end
43
+
44
+ class UpdaterNoteWithUser < ActiveRecord::Base
45
+ set_table_name "updater_notes"
46
+
47
+ end
48
+
49
+ class DeleterNoteWithUser < ActiveRecord::Base
50
+ set_table_name "deleter_notes"
51
+
52
+ end
53
+
54
+ class RecordWithOperatorTest < ActiveSupport::TestCase
55
+ def setup
56
+ RecordWithOperator.config[:user_class_name] = "User"
57
+ @user1 = User.create!(:name => "user1")
58
+ raise "@user1.id is nil" unless @user1.id
59
+ @user2 = User.create!(:name => "user2")
60
+ raise "@user2.id is nil" unless @user2.id
61
+ @note_created_by_user1 = NoteWithUser.create!(:body => "test", :operator => @user1)
62
+ end
63
+
64
+ # creator/updater/deleter association operation
65
+ def test_note_should_be_respond_to_creator
66
+ assert NoteWithUser.new.respond_to? :creator
67
+ end
68
+
69
+ def test_simple_note_should_not_be_respond_to_creator
70
+ assert_equal false, SimpleNoteWithUser.new.respond_to?(:creator)
71
+ end
72
+
73
+ def test_note_should_be_respond_to_updater
74
+ assert NoteWithUser.new.respond_to? :updater
75
+ end
76
+
77
+ def test_simple_note_should_not_be_respond_to_updater
78
+ assert_equal false, SimpleNoteWithUser.new.respond_to?(:updater)
79
+ end
80
+
81
+ def test_note_should_be_respond_to_deleter
82
+ assert NoteWithUser.new.respond_to? :deleter
83
+ end
84
+
85
+ def test_simple_note_should_not_be_respond_to_deleter
86
+ assert_equal false, SimpleNoteWithUser.new.respond_to?(:deleter)
87
+ end
88
+
89
+ # test updater without creater, deleter
90
+ def test_updater_note_should_not_be_respond_to_creater
91
+ assert_equal false, UpdaterNoteWithUser.new.respond_to?(:creater)
92
+ end
93
+ def test_updater_note_should_be_respond_to_updater
94
+ assert UpdaterNoteWithUser.new.respond_to? :updater
95
+ end
96
+ def test_updater_note_should_not_be_respond_to_deleter
97
+ assert_equal false, UpdaterNoteWithUser.new.respond_to?(:deleter)
98
+ end
99
+
100
+ # test deleter without create, updater
101
+ def test_deleter_note_should_not_be_respond_to_creater
102
+ assert_equal false, DeleterNoteWithUser.new.respond_to?(:creater)
103
+ end
104
+ def test_deleter_note_should_not_be_respond_to_updater
105
+ assert_equal false, DeleterNoteWithUser.new.respond_to?(:updater)
106
+ end
107
+ def test_deleter_note_should_be_respond_to_deleter
108
+ assert DeleterNoteWithUser.new.respond_to?(:deleter)
109
+ end
110
+
111
+ # find with :for
112
+ def test_note_should_be_found_with_for
113
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
114
+ assert_equal(@user2, note.operator)
115
+ end
116
+
117
+ def test_note_should_be_found_with_for_through_named_scope
118
+ note = NoteWithUser.new_arrivals.find(@note_created_by_user1.id, :for => @user2)
119
+ assert_equal(@user2, note.operator)
120
+ end
121
+
122
+ # save or destory with xxxx_by and can get as a creator/updator/deleter
123
+
124
+ def test_note_should_be_created_with_operator
125
+ assert_equal @user1, @note_created_by_user1.operator
126
+ end
127
+
128
+ def test_note_should_be_created_with_created_by_and_updated_by
129
+ assert_equal @user1.id, @note_created_by_user1.created_by
130
+ assert_equal @user1.id, @note_created_by_user1.updated_by
131
+ @note_created_by_user1.reload
132
+ assert_equal @user1.id, @note_created_by_user1.created_by
133
+ assert_equal @user1.id, @note_created_by_user1.updated_by
134
+ assert_equal @user1, @note_created_by_user1.creator
135
+ assert_equal @user1, @note_created_by_user1.updater
136
+ end
137
+
138
+ def test_note_should_be_updated_with_updated_by
139
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
140
+ note.body = "changed"
141
+ note.save!
142
+ assert_equal(@user2.id, note.updated_by)
143
+ note.reload
144
+ assert_equal(@user2.id, note.updated_by)
145
+ end
146
+
147
+ def test_note_should_be_destroyed_with_deleted_by
148
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
149
+ note.destroy # logically
150
+ note = NoteWithUser.find(@note_created_by_user1.id)
151
+ raise "not deleted" unless note.deleted?
152
+ assert_equal @user2.id, note.deleted_by
153
+ end
154
+
155
+ # reload
156
+ def test_reload_should_not_change_operator
157
+ @note_created_by_user1.reload
158
+ assert_equal @user1, @note_created_by_user1.operator
159
+ end
160
+
161
+
162
+ # has_many Association Test
163
+ def test_builded_memo_should_have_operator
164
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
165
+ memo = note.memos.build(:body => "memo")
166
+ assert_equal @user2, memo.operator
167
+ end
168
+
169
+ def test_builded_memo_should_have_own_set_operator
170
+ note = NoteWithUser.find(@note_created_by_user1.id)
171
+ memo = note.memos.build(:body => "memo", :operator => @user2)
172
+ assert_equal @user2, memo.operator
173
+ end
174
+
175
+
176
+ def test_created_memo_should_have_operator_and_created_by
177
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
178
+ memo = note.memos.create(:body => "memo")
179
+ assert_equal false, memo.new_record?
180
+ assert_equal @user2, memo.operator
181
+ assert_equal @user2.id, memo.created_by
182
+ end
183
+
184
+ def test_auto_found_memo_should_have_operator
185
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
186
+ note.memos.create!(:body => "memo")
187
+ assert_equal @user2, note.memos(true).first.operator
188
+ end
189
+
190
+ def test_manualy_found_memo_should_have_operator
191
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
192
+ note.memos.create!(:body => "memo")
193
+ assert_equal @user2, note.memos.find(:first).operator
194
+ end
195
+
196
+ def test_dynamically_found_memo_should_have_operator
197
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
198
+ note.memos.create!(:body => "memo")
199
+ assert_equal @user2, note.memos.find_by_body("memo").operator
200
+ end
201
+
202
+ def test_dynamically_found_memos_should_have_operator
203
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
204
+ note.memos.create!(:body => "memo")
205
+ assert note.memos.find_all_by_body("memo").all?{|m| m.operator == @user2}
206
+ end
207
+
208
+ def test_found_memo_through_named_scope_should_have_operator
209
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
210
+ note.memos.create!(:body => "memo")
211
+ assert_equal @user2, note.memos.new_arrivals.first.operator
212
+ end
213
+
214
+ def test_dynamically_found_memo_through_named_scope_should_have_operator
215
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
216
+ note.memos.create!(:body => "memo")
217
+ assert_equal @user2, note.memos.new_arrivals.find_by_body("memo").operator
218
+ end
219
+
220
+ def test_auto_found_memo_first_should_be_nil_if_note_has_no_memo
221
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
222
+ assert_equal nil, note.memos.first
223
+ assert_equal nil, note.memos(true).first
224
+ end
225
+
226
+ def test_auto_found_memo_last_should_be_nil_if_note_has_no_memo
227
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
228
+ assert_equal nil, note.memos.last
229
+ assert_equal nil, note.memos(true).last
230
+ end
231
+
232
+ def test_manualy_found_memo_first_should_be_nil_if_note_has_no_memo
233
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
234
+ assert_equal nil, note.memos.find(:first)
235
+ end
236
+
237
+ def test_manualy_found_memo_last_should_be_nil_if_note_has_no_memo
238
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
239
+ assert_equal nil, note.memos.find(:last)
240
+ end
241
+
242
+ def test_dynamically_found_memos_first_should_be_nil_if_note_has_no_memo
243
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
244
+ assert_equal nil, note.memos.find_all_by_body("memo").first
245
+ end
246
+
247
+ def test_found_memo_through_named_scope_last_should_be_nil_if_note_has_no_memo
248
+ note = NoteWithUser.find(@note_created_by_user1.id, :for => @user2)
249
+ assert_equal nil, note.memos.new_arrivals.last
250
+ end
251
+ end
@@ -0,0 +1,59 @@
1
+
2
+ require 'test_helper'
3
+
4
+ class NoteWithAdminUser < ActiveRecord::Base
5
+ set_table_name "notes"
6
+
7
+ def destroy_with_deleted_at
8
+ NoteWithAdminUser.update_all("deleted_at = '#{Time.now.to_s(:db)}'", "id = #{self.id}")
9
+ end
10
+ alias_method_chain :destroy, :deleted_at
11
+ def destory!
12
+ destory_without_deleted_at
13
+ end
14
+
15
+ def deleted?
16
+ self.deleted_at <= Time.now
17
+ end
18
+ end
19
+
20
+ class AdminUser < ActiveRecord::Base
21
+ set_table_name "users"
22
+ end
23
+
24
+ class RecordWithOperatorUserClassNameTest < ActiveSupport::TestCase
25
+ def setup
26
+ RecordWithOperator.config[:user_class_name] = "AdminUser"
27
+ @user1 = AdminUser.create!(:name => "user1")
28
+ @user2 = AdminUser.create!(:name => "user2")
29
+ @note_created_by_user1 = NoteWithAdminUser.create!(:body => "test", :operator => @user1)
30
+ end
31
+
32
+ def test_note_should_be_created_with_operator
33
+ assert_equal @user1, @note_created_by_user1.operator
34
+ end
35
+
36
+ def test_note_should_be_created_with_created_by_and_updated_by
37
+ assert_equal @user1.id, @note_created_by_user1.created_by
38
+ assert_equal @user1.id, @note_created_by_user1.updated_by
39
+ @note_created_by_user1.reload
40
+ assert_equal @user1.id, @note_created_by_user1.created_by
41
+ assert_equal @user1.id, @note_created_by_user1.updated_by
42
+ assert @note_created_by_user1.creator.kind_of?(AdminUser)
43
+ end
44
+
45
+ def test_note_should_be_found_with_for
46
+ note = NoteWithAdminUser.find(@note_created_by_user1.id, :for => @user2)
47
+ assert_equal(@user2, note.operator)
48
+ end
49
+
50
+ def test_note_should_be_updated_with_updated_by
51
+ note = NoteWithAdminUser.find(@note_created_by_user1.id, :for => @user2)
52
+ note.body = "changed"
53
+ note.save!
54
+ assert_equal(@user2.id, note.updated_by)
55
+ note.reload
56
+ assert_equal(@user2.id, note.updated_by)
57
+ end
58
+
59
+ end
@@ -0,0 +1,50 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+
3
+ create_table :simple_notes, :force => true do |t|
4
+ t.column :body, :text
5
+ end
6
+
7
+ create_table :creator_notes, :force => true do |t|
8
+ t.column :body, :text
9
+ t.column :created_by, :integer
10
+ t.column :created_at, :datetime
11
+ end
12
+
13
+ create_table :updater_notes, :force => true do |t|
14
+ t.column :body, :text
15
+ t.column :updated_by, :integer
16
+ t.column :updated_at, :datetime
17
+ end
18
+
19
+ create_table :deleter_notes, :force => true do |t|
20
+ t.column :body, :text
21
+ t.column :deleted_by, :integer
22
+ t.column :deleted_at, :datetime
23
+ end
24
+
25
+ create_table :notes, :force => true do |t|
26
+ t.column :memo_id, :integer
27
+ t.column :body, :text
28
+ t.column :created_by, :integer
29
+ t.column :created_at, :datetime
30
+ t.column :updated_by, :integer
31
+ t.column :updated_at, :datetime
32
+ t.column :deleted_by, :integer
33
+ t.column :deleted_at, :datetime
34
+ end
35
+
36
+ create_table :memos, :force => true do |t|
37
+ t.column :note_id, :integer
38
+ t.column :body, :text
39
+ t.column :created_by, :integer
40
+ t.column :created_at, :datetime
41
+ t.column :updated_by, :integer
42
+ t.column :updated_at, :datetime
43
+ t.column :deleted_by, :integer
44
+ t.column :deleted_at, :datetime
45
+ end
46
+
47
+ create_table :users, :force => true do |t|
48
+ t.column :name, :string
49
+ end
50
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygems'
2
+ require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
3
+ require 'test/unit'
4
+ require 'active_support'
5
+ require 'active_support/test_case'
6
+
7
+ require 'lib/association_with_operator'
8
+ require 'lib/record_with_operator'
9
+ require 'init'
10
+
11
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
12
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
13
+ ActiveRecord::Base.establish_connection(config['mysql'])
14
+
15
+ load(File.dirname(__FILE__) + "/schema.rb")
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: record_with_operator
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.22
6
+ platform: ruby
7
+ authors:
8
+ - Yasuko Ohba
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-13 00:00:00 Z
14
+ dependencies: []
15
+
16
+ description: Rails plugin to set created_by, updated_by, deleted_by to ActiveRecord objects. Supports associations.
17
+ email:
18
+ - y.ohba@everyleaf.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - .gitignore
27
+ - .idea/inspectionProfiles/Project_Default.xml
28
+ - .idea/inspectionProfiles/profiles_settings.xml
29
+ - .idea/workspace.xml
30
+ - Gemfile
31
+ - MIT-LICENSE
32
+ - README.rdoc
33
+ - Rakefile
34
+ - init.rb
35
+ - install.rb
36
+ - lib/association_with_operator.rb
37
+ - lib/helpers/migration_helper.rb
38
+ - lib/record_with_operator.rb
39
+ - lib/record_with_operator/version.rb
40
+ - lib/tasks/record_with_operator_tasks.rake
41
+ - record_with_operator.gemspec
42
+ - record_with_operator/.gitignore
43
+ - record_with_operator/Gemfile
44
+ - record_with_operator/Rakefile
45
+ - record_with_operator/lib/record_with_operator.rb
46
+ - record_with_operator/lib/record_with_operator/version.rb
47
+ - record_with_operator/record_with_operator.gemspec
48
+ - test/database.yml
49
+ - test/record_with_operator_belongs_to_association_test.rb
50
+ - test/record_with_operator_has_many_dependent_test.rb
51
+ - test/record_with_operator_has_one_association_test.rb
52
+ - test/record_with_operator_reflection_test.rb
53
+ - test/record_with_operator_test.rb
54
+ - test/record_with_operator_user_class_name_test.rb
55
+ - test/schema.rb
56
+ - test/test_helper.rb
57
+ - uninstall.rb
58
+ homepage: ""
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project: record_with_operator
81
+ rubygems_version: 1.7.2
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Rails plugin to set created_by, updated_by, deleted_by to ActiveRecord objects. Supports associations.
85
+ test_files: []
86
+