association_callbacks 0.0.1
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.
- data/.gitignore +5 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +89 -0
- data/MIT-LICENSE +20 -0
- data/README.mdown +93 -0
- data/Rakefile +10 -0
- data/VERSION +1 -0
- data/association_callbacks.gemspec +24 -0
- data/init.rb +1 -0
- data/lib/association_callbacks/active_record.rb +89 -0
- data/lib/association_callbacks.rb +22 -0
- data/spec/association_callbacks/active_record_spec.rb +76 -0
- data/spec/association_callbacks_spec.rb +23 -0
- data/spec/mocks/comment.rb +26 -0
- data/spec/mocks/post.rb +23 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/bootsrap/database.rb +17 -0
- metadata +130 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
association_callbacks (0.0.1)
|
5
|
+
activerecord (~> 3.2.0)
|
6
|
+
activesupport (~> 3.2.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actionpack (3.2.2)
|
12
|
+
activemodel (= 3.2.2)
|
13
|
+
activesupport (= 3.2.2)
|
14
|
+
builder (~> 3.0.0)
|
15
|
+
erubis (~> 2.7.0)
|
16
|
+
journey (~> 1.0.1)
|
17
|
+
rack (~> 1.4.0)
|
18
|
+
rack-cache (~> 1.1)
|
19
|
+
rack-test (~> 0.6.1)
|
20
|
+
sprockets (~> 2.1.2)
|
21
|
+
activemodel (3.2.2)
|
22
|
+
activesupport (= 3.2.2)
|
23
|
+
builder (~> 3.0.0)
|
24
|
+
activerecord (3.2.2)
|
25
|
+
activemodel (= 3.2.2)
|
26
|
+
activesupport (= 3.2.2)
|
27
|
+
arel (~> 3.0.2)
|
28
|
+
tzinfo (~> 0.3.29)
|
29
|
+
activesupport (3.2.2)
|
30
|
+
i18n (~> 0.6)
|
31
|
+
multi_json (~> 1.0)
|
32
|
+
arel (3.0.2)
|
33
|
+
builder (3.0.0)
|
34
|
+
diff-lcs (1.1.3)
|
35
|
+
erubis (2.7.0)
|
36
|
+
hike (1.2.1)
|
37
|
+
i18n (0.6.0)
|
38
|
+
journey (1.0.3)
|
39
|
+
json (1.6.6)
|
40
|
+
multi_json (1.2.0)
|
41
|
+
rack (1.4.1)
|
42
|
+
rack-cache (1.2)
|
43
|
+
rack (>= 0.4)
|
44
|
+
rack-ssl (1.3.2)
|
45
|
+
rack
|
46
|
+
rack-test (0.6.1)
|
47
|
+
rack (>= 1.0)
|
48
|
+
railties (3.2.2)
|
49
|
+
actionpack (= 3.2.2)
|
50
|
+
activesupport (= 3.2.2)
|
51
|
+
rack-ssl (~> 1.3.2)
|
52
|
+
rake (>= 0.8.7)
|
53
|
+
rdoc (~> 3.4)
|
54
|
+
thor (~> 0.14.6)
|
55
|
+
rake (0.9.2.2)
|
56
|
+
rdoc (3.12)
|
57
|
+
json (~> 1.4)
|
58
|
+
rspec (2.9.0)
|
59
|
+
rspec-core (~> 2.9.0)
|
60
|
+
rspec-expectations (~> 2.9.0)
|
61
|
+
rspec-mocks (~> 2.9.0)
|
62
|
+
rspec-core (2.9.0)
|
63
|
+
rspec-expectations (2.9.0)
|
64
|
+
diff-lcs (~> 1.1.3)
|
65
|
+
rspec-mocks (2.9.0)
|
66
|
+
rspec-rails (2.9.0)
|
67
|
+
actionpack (>= 3.0)
|
68
|
+
activesupport (>= 3.0)
|
69
|
+
railties (>= 3.0)
|
70
|
+
rspec (~> 2.9.0)
|
71
|
+
sprockets (2.1.2)
|
72
|
+
hike (~> 1.2)
|
73
|
+
rack (~> 1.0)
|
74
|
+
tilt (~> 1.1, != 1.3.0)
|
75
|
+
sqlite3 (1.3.5)
|
76
|
+
sqlite3-ruby (1.3.3)
|
77
|
+
sqlite3 (>= 1.3.3)
|
78
|
+
thor (0.14.6)
|
79
|
+
tilt (1.3.3)
|
80
|
+
tzinfo (0.3.32)
|
81
|
+
|
82
|
+
PLATFORMS
|
83
|
+
ruby
|
84
|
+
|
85
|
+
DEPENDENCIES
|
86
|
+
association_callbacks!
|
87
|
+
rspec (~> 2.9.0)
|
88
|
+
rspec-rails (~> 2.9.0)
|
89
|
+
sqlite3-ruby
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Alexis Toulotte
|
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.
|
data/README.mdown
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# AssociationCallbacks
|
2
|
+
|
3
|
+
Provides a way to define [callbacks](http://api.rubyonrails.org/classes/ActiveModel/Callbacks.html)
|
4
|
+
of one [ActiveRecord](http://api.rubyonrails.org/classes/ActiveRecord/Base.html)
|
5
|
+
model into an associated one.
|
6
|
+
|
7
|
+
## Example
|
8
|
+
|
9
|
+
First, two simple `Article` and `Comment` models:
|
10
|
+
|
11
|
+
class Article < ActiveRecord::Base
|
12
|
+
has_many :comments
|
13
|
+
end
|
14
|
+
|
15
|
+
class Comment < ActiveRecord::Base
|
16
|
+
belongs_to :article
|
17
|
+
end
|
18
|
+
|
19
|
+
Then, you often need to denormalize `Comment` stuff into `Post` or vice versa.
|
20
|
+
Here is the standard way to denormalize `last_comment_at` on posts:
|
21
|
+
|
22
|
+
class Comment < ActiveRecord::Base
|
23
|
+
belongs_to :article
|
24
|
+
|
25
|
+
after_create :update_post_last_comment_at
|
26
|
+
after_destroy :update_post_last_comment_at
|
27
|
+
|
28
|
+
def update_post_last_comment_at
|
29
|
+
post.update_attributes!(:last_comment_at => post.comments.order('created_at').last.try(:created_at))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
But, there is a problem here: we define `Post` denormalization callbacks into
|
34
|
+
`Comment` model. IMHO, this is the wrong place. `Post` denormalization
|
35
|
+
**should** be in `Post` model in order to have less relationship between
|
36
|
+
models.
|
37
|
+
|
38
|
+
Here is how to do it with `association_callabacks`:
|
39
|
+
|
40
|
+
class Post < ActiveRecord::Base
|
41
|
+
has_many :comments
|
42
|
+
|
43
|
+
after_create :update_last_comment_at, :source => :comments
|
44
|
+
after_destroy :update_last_comment_at, :source => :comments
|
45
|
+
|
46
|
+
def update_last_comment_at
|
47
|
+
update_attributes!(:last_comment_at => comments.order('created_at').last.try(:created_at))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
You just have to specify `:source` option to your callbacks, and that's all!
|
52
|
+
Note that `:source` option must be an existing association name.
|
53
|
+
|
54
|
+
Note that association callbacks methods can take associated record as
|
55
|
+
argument, above code can be:
|
56
|
+
|
57
|
+
class Post < ActiveRecord::Base
|
58
|
+
has_many :comments
|
59
|
+
|
60
|
+
after_create :update_last_comment_at
|
61
|
+
|
62
|
+
def update_last_comment_at(comment)
|
63
|
+
update_attributes!(:last_comment_at => comment.created_at)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Association callbacks can also be defined as block:
|
68
|
+
|
69
|
+
class Post < ActiveRecord::Base
|
70
|
+
has_many :comments
|
71
|
+
|
72
|
+
after_destroy :source => :comments do |post|
|
73
|
+
post.decrement!(:comments_count)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Another solution is to use [ActiveModel Observers](http://api.rubyonrails.org/classes/ActiveModel/Observer.html),
|
78
|
+
but for a better project comprehension, I really prefer placing denormalization
|
79
|
+
directly into model. Observers are more designed for emails notifications,
|
80
|
+
cache sweepers, etc.
|
81
|
+
|
82
|
+
## Installation
|
83
|
+
|
84
|
+
Just add this into your `Gemfile`:
|
85
|
+
|
86
|
+
gem 'association_callabacks'
|
87
|
+
|
88
|
+
Then, just run `bundle install`.
|
89
|
+
|
90
|
+
## Executing test suite
|
91
|
+
|
92
|
+
This project is fully tested with [Rspec 2](http://github.com/rspec/rspec).
|
93
|
+
Just run `bundle exec rake` (after a `bundle install`).
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'association_callbacks'
|
3
|
+
s.version = File.read(File.expand_path(File.dirname(__FILE__) + '/VERSION')).strip
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.author = 'Alexis Toulotte'
|
6
|
+
s.email = 'al@alweb.org'
|
7
|
+
s.homepage = 'https://github.com/alexistoulotte/association_callbacks'
|
8
|
+
s.summary = 'Callbacks for ActiveRecord associations'
|
9
|
+
s.description = 'Provides a way to define callbacks of one ActiveRecord model into an associated one'
|
10
|
+
|
11
|
+
s.rubyforge_project = 'association_callbacks'
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
|
18
|
+
s.add_dependency 'activerecord', '~> 3.2.0'
|
19
|
+
s.add_dependency 'activesupport', '~> 3.2.0'
|
20
|
+
|
21
|
+
s.add_development_dependency 'rspec', '~> 2.9.0'
|
22
|
+
s.add_development_dependency 'rspec-rails', '~> 2.9.0'
|
23
|
+
s.add_development_dependency 'sqlite3-ruby'
|
24
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/lib/association_callbacks')
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module AssociationCallbacks
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
|
5
|
+
CALLBACKS = %w(
|
6
|
+
after_commit
|
7
|
+
after_create
|
8
|
+
after_destroy
|
9
|
+
after_save
|
10
|
+
after_update
|
11
|
+
after_validation
|
12
|
+
before_create
|
13
|
+
before_destroy
|
14
|
+
before_save
|
15
|
+
before_update
|
16
|
+
before_validation
|
17
|
+
).freeze
|
18
|
+
|
19
|
+
extend ActiveSupport::Concern
|
20
|
+
|
21
|
+
included do |base|
|
22
|
+
CALLBACKS.each do |callback|
|
23
|
+
base.class_eval <<-EOS
|
24
|
+
class << self
|
25
|
+
|
26
|
+
def #{callback}_with_association(*args, &block)
|
27
|
+
if args.last.is_a?(Hash) && args.last.key?(:source)
|
28
|
+
options = args.extract_options!
|
29
|
+
define_callback_with_association(:#{callback}, args, options, &block)
|
30
|
+
else
|
31
|
+
#{callback}_without_association(*args, &block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
alias_method_chain :#{callback}, :association
|
35
|
+
|
36
|
+
end
|
37
|
+
EOS
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module ClassMethods
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def define_callback_with_association(callback, methods, options = {}, &block)
|
46
|
+
relation_name = options.delete(:source).try(:to_sym)
|
47
|
+
relation = reflect_on_association(relation_name) || raise(ArgumentError.new("No such association: #{name}.#{relation_name}"))
|
48
|
+
inverse_relation_name = relation.inverse_of.try(:name).presence || raise(ArgumentError.new("You must specify :inverse_of on #{name}.#{relation_name} to use association callbacks"))
|
49
|
+
relation.klass.send(callback, options) do |record|
|
50
|
+
invoke_callback_with_association(record, record.send(inverse_relation_name), methods, &block)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def invoke_callback_block_with_association(record, inverse_record, &block)
|
59
|
+
yield(inverse_record, record) if block_given?
|
60
|
+
end
|
61
|
+
|
62
|
+
def invoke_callback_methods_with_association(record, inverse_record, methods)
|
63
|
+
methods.each do |method|
|
64
|
+
if inverse_record.method(method).arity == 1
|
65
|
+
inverse_record.send(method, record)
|
66
|
+
else
|
67
|
+
inverse_record.send(method)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def invoke_callback_with_association(record, assocation, methods, &block)
|
73
|
+
return if assocation.nil?
|
74
|
+
if assocation.respond_to?(:find_each)
|
75
|
+
assocation.find_each do |inverse_record|
|
76
|
+
invoke_callback_methods_with_association(record, inverse_record, methods)
|
77
|
+
invoke_callback_block_with_association(record, inverse_record, &block)
|
78
|
+
end
|
79
|
+
elsif assocation.is_a?(::ActiveRecord::Base)
|
80
|
+
invoke_callback_methods_with_association(record, assocation, methods)
|
81
|
+
invoke_callback_block_with_association(record, assocation, &block)
|
82
|
+
else
|
83
|
+
raise "Assocation can't be used by callbacks: #{association.inspect}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'active_record'
|
4
|
+
require 'active_support/concern'
|
5
|
+
|
6
|
+
module AssociationCallbacks
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
def version
|
11
|
+
@@version ||= File.read(File.expand_path(File.dirname(__FILE__) + '/../VERSION')).strip.freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
lib_path = File.expand_path(File.dirname(__FILE__) + '/association_callbacks')
|
19
|
+
|
20
|
+
require "#{lib_path}/active_record"
|
21
|
+
|
22
|
+
ActiveRecord::Base.send(:include, AssociationCallbacks::ActiveRecord)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AssociationCallbacks::ActiveRecord do
|
4
|
+
|
5
|
+
context 'with has_many relation' do
|
6
|
+
|
7
|
+
it 'invokes callback defines as method' do
|
8
|
+
post = Post.create!
|
9
|
+
expect {
|
10
|
+
Comment.create!(:post_id => post.id)
|
11
|
+
}.to change { post.reload.comments_count }.by(1)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'invokes callback defines as method (with one argument)' do
|
15
|
+
post = Post.create!
|
16
|
+
expect {
|
17
|
+
Comment.create!(:post => post, :created_at => 2.years.ago)
|
18
|
+
}.to change { post.reload.last_comment_at }.from(nil)
|
19
|
+
post.last_comment_at.to_i.should be_within(5).of(2.years.ago.to_i)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'invokes callback defines as block' do
|
23
|
+
post = Post.create!
|
24
|
+
comment = Comment.create!(:post => post)
|
25
|
+
expect {
|
26
|
+
comment.destroy
|
27
|
+
}.to change { post.reload.comments_count }.by(-1)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'invokes regular callbacks' do
|
31
|
+
post = Post.new(:body => 'this is body', :title => 'foo')
|
32
|
+
expect {
|
33
|
+
post.save!
|
34
|
+
}.to change { post.texts }.from(nil).to('foo,this,is,body')
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with belongs_to relation' do
|
40
|
+
|
41
|
+
it 'invokes callback defines as method' do
|
42
|
+
post = Post.create!
|
43
|
+
comment = post.comments.create!
|
44
|
+
expect {
|
45
|
+
post.update_attributes!(:title => 'foo')
|
46
|
+
}.to change { comment.reload.post_updated_at }
|
47
|
+
comment.post_updated_at.to_i.should be_within(5).of(Time.now.to_i)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'invokes callback defines as method (with one argument)' do
|
51
|
+
post = Post.create!(:title => 'foo')
|
52
|
+
comment = post.comments.create!
|
53
|
+
expect {
|
54
|
+
post.update_attributes!(:title => 'bar')
|
55
|
+
}.to change { comment.reload.post.title }.from('foo').to('bar')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'invokes callback defines as block' do
|
59
|
+
post = Post.create!
|
60
|
+
comment = Comment.create!(:post_id => post.id)
|
61
|
+
expect {
|
62
|
+
post.destroy
|
63
|
+
}.to change { comment.reload.orphan_from_id }.from(nil).to(post.id)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'invokes regular callbacks' do
|
67
|
+
post = Post.create!(:title => 'foo')
|
68
|
+
comment = Comment.new(:post => post)
|
69
|
+
expect {
|
70
|
+
comment.save!
|
71
|
+
}.to change { comment.post_title }.from(nil).to('foo')
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AssociationCallbacks do
|
4
|
+
|
5
|
+
describe '.version' do
|
6
|
+
|
7
|
+
it 'is a string' do
|
8
|
+
AssociationCallbacks.version.should be_a(String)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'is with correct format' do
|
12
|
+
AssociationCallbacks.version.should match(/^\d+\.\d+(\.\d+)?$/)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'is freezed' do
|
16
|
+
expect {
|
17
|
+
AssociationCallbacks.version.gsub!('.', '#')
|
18
|
+
}.to raise_error(/can't modify frozen string/i)
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Comment < ActiveRecord::Base
|
2
|
+
|
3
|
+
belongs_to :post, :inverse_of => :comments
|
4
|
+
|
5
|
+
after_save :update_post_updated_at, :source => :post
|
6
|
+
before_create :set_post_title
|
7
|
+
before_save :update_post_title, :source => :post
|
8
|
+
after_destroy :source => :post do |comment, post|
|
9
|
+
comment.update_attributes!(:orphan_from_id => post.id)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def set_post_title
|
15
|
+
self.post_title = post.title
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_post_title(post)
|
19
|
+
update_attributes!(:post_title => post.title) if post.title_changed?
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_post_updated_at
|
23
|
+
update_attributes!(:post_updated_at => post.updated_at)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/spec/mocks/post.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
class Post < ActiveRecord::Base
|
2
|
+
|
3
|
+
has_many :comments, :inverse_of => :post
|
4
|
+
|
5
|
+
after_create :increment_comments_count, :update_last_comment_at, :source => :comments
|
6
|
+
after_destroy :source => :comments do |post|
|
7
|
+
post.decrement!(:comments_count)
|
8
|
+
end
|
9
|
+
before_save do |post|
|
10
|
+
post.texts = "#{post.title} #{post.body}".strip.split(/\s+/).join(',')
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def increment_comments_count
|
16
|
+
increment!(:comments_count)
|
17
|
+
end
|
18
|
+
|
19
|
+
def update_last_comment_at(comment)
|
20
|
+
update_attributes!(:last_comment_at => comment.created_at)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
ENV["RAILS_ENV"] ||= 'test'
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../lib/association_callbacks'
|
4
|
+
|
5
|
+
# Support
|
6
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
7
|
+
|
8
|
+
# Mocks
|
9
|
+
ActiveSupport::Dependencies.autoload_paths << "#{File.dirname(__FILE__)}/mocks"
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
config.before(:each) do
|
13
|
+
Comment.delete_all
|
14
|
+
Post.delete_all
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => "#{File.dirname(__FILE__)}/../../test.sqlite3", :timeout => 5000)
|
2
|
+
|
3
|
+
ActiveRecord::Base.connection.create_table(:comments, :force => true) do |t|
|
4
|
+
t.integer :orphan_from_id
|
5
|
+
t.datetime :post_updated_at
|
6
|
+
t.integer :post_id
|
7
|
+
t.string :post_title
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
ActiveRecord::Base.connection.create_table(:posts, :force => true) do |t|
|
11
|
+
t.text :body
|
12
|
+
t.integer :comments_count, :default => 0
|
13
|
+
t.datetime :last_comment_at
|
14
|
+
t.text :texts
|
15
|
+
t.string :title
|
16
|
+
t.timestamps
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: association_callbacks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Alexis Toulotte
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: &70294690344260 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70294690344260
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70294690343080 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.2.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70294690343080
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &70294690341960 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.9.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70294690341960
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec-rails
|
49
|
+
requirement: &70294690340660 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.9.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70294690340660
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: sqlite3-ruby
|
60
|
+
requirement: &70294690339420 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70294690339420
|
69
|
+
description: Provides a way to define callbacks of one ActiveRecord model into an
|
70
|
+
associated one
|
71
|
+
email: al@alweb.org
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- .rspec
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- MIT-LICENSE
|
81
|
+
- README.mdown
|
82
|
+
- Rakefile
|
83
|
+
- VERSION
|
84
|
+
- association_callbacks.gemspec
|
85
|
+
- init.rb
|
86
|
+
- lib/association_callbacks.rb
|
87
|
+
- lib/association_callbacks/active_record.rb
|
88
|
+
- spec/association_callbacks/active_record_spec.rb
|
89
|
+
- spec/association_callbacks_spec.rb
|
90
|
+
- spec/mocks/comment.rb
|
91
|
+
- spec/mocks/post.rb
|
92
|
+
- spec/spec_helper.rb
|
93
|
+
- spec/support/bootsrap/database.rb
|
94
|
+
homepage: https://github.com/alexistoulotte/association_callbacks
|
95
|
+
licenses: []
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
hash: -2681495212806614534
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
hash: -2681495212806614534
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project: association_callbacks
|
120
|
+
rubygems_version: 1.8.17
|
121
|
+
signing_key:
|
122
|
+
specification_version: 3
|
123
|
+
summary: Callbacks for ActiveRecord associations
|
124
|
+
test_files:
|
125
|
+
- spec/association_callbacks/active_record_spec.rb
|
126
|
+
- spec/association_callbacks_spec.rb
|
127
|
+
- spec/mocks/comment.rb
|
128
|
+
- spec/mocks/post.rb
|
129
|
+
- spec/spec_helper.rb
|
130
|
+
- spec/support/bootsrap/database.rb
|