record_with_operator 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+