acts-as-joinable 0.2 → 0.2.2
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/Rakefile +1 -1
- data/lib/acts-as-joinable.rb +1 -0
- data/lib/acts_as_joinable/core.rb +28 -9
- data/lib/acts_as_joinable/dirty.rb +116 -0
- data/test/test_acts_as_joinable.rb +17 -1
- metadata +5 -3
data/Rakefile
CHANGED
|
@@ -5,7 +5,7 @@ require 'rake/gempackagetask'
|
|
|
5
5
|
spec = Gem::Specification.new do |s|
|
|
6
6
|
s.name = "acts-as-joinable"
|
|
7
7
|
s.authors = ["Lance Pollard"]
|
|
8
|
-
s.version = "0.2"
|
|
8
|
+
s.version = "0.2.2"
|
|
9
9
|
s.summary = "ActsAsJoinable: DRYing up Many-to-Many Relationships in ActiveRecord"
|
|
10
10
|
s.homepage = "http://github.com/viatropos/acts-as-joinable"
|
|
11
11
|
s.email = "lancejpollard@gmail.com"
|
data/lib/acts-as-joinable.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# http://github.com/pluginaweek/preferences/blob/master/lib/preferences.rb
|
|
2
|
+
# add changes so you can track when the join model changes
|
|
1
3
|
module ActsAsJoinable
|
|
2
4
|
module Core
|
|
3
5
|
def self.included(base)
|
|
@@ -8,7 +10,21 @@ module ActsAsJoinable
|
|
|
8
10
|
end
|
|
9
11
|
|
|
10
12
|
module ClassMethods
|
|
11
|
-
|
|
13
|
+
def add_around_filters_for_join(options, attribute, filter, filter_type)
|
|
14
|
+
options[filter_type] = filter if filter
|
|
15
|
+
=begin
|
|
16
|
+
if filter
|
|
17
|
+
options[filter_type] = lambda { |parent, child|
|
|
18
|
+
parent.write_join_attribute(attribute, child.id)
|
|
19
|
+
filter.call(self)
|
|
20
|
+
}
|
|
21
|
+
else
|
|
22
|
+
options[filter_type] = lambda { |parent, child|
|
|
23
|
+
parent.write_join_attribute(attribute, child.id)
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
=end
|
|
27
|
+
end
|
|
12
28
|
# custom parent, self, and child contexts
|
|
13
29
|
# Group...
|
|
14
30
|
# acts_as_joinable_on :groups,
|
|
@@ -59,6 +75,8 @@ module ActsAsJoinable
|
|
|
59
75
|
|
|
60
76
|
scope_name = opts[:named_scope]
|
|
61
77
|
|
|
78
|
+
autosave = opts[:autosave] != false
|
|
79
|
+
|
|
62
80
|
joins.map!(&:to_sym)
|
|
63
81
|
|
|
64
82
|
# class name of the model we're joining to self
|
|
@@ -110,8 +128,8 @@ module ActsAsJoinable
|
|
|
110
128
|
:conditions => sql
|
|
111
129
|
}
|
|
112
130
|
|
|
113
|
-
options
|
|
114
|
-
options
|
|
131
|
+
add_around_filters_for_join(options, "#{singular_type.to_s}_id".to_sym, before_add, :before_add)
|
|
132
|
+
add_around_filters_for_join(options, "#{singular_type.to_s}_id".to_sym, after_add, :after_add)
|
|
115
133
|
|
|
116
134
|
# relationships == [:parent, :child]
|
|
117
135
|
relationships.each do |relationship|
|
|
@@ -275,16 +293,13 @@ module ActsAsJoinable
|
|
|
275
293
|
|
|
276
294
|
def add_has_one(singular_type, plural_type, relationship_with_context, class_name, join_context, join_value, options)
|
|
277
295
|
define_method singular_type do
|
|
278
|
-
send(plural_type)
|
|
296
|
+
send(plural_type)[-1]#.last
|
|
279
297
|
end
|
|
280
298
|
define_method "#{singular_type}=" do |value|
|
|
281
|
-
|
|
299
|
+
return value if send(plural_type).map(&:id).include?(value.id)
|
|
282
300
|
|
|
283
|
-
|
|
301
|
+
send(plural_type) << value unless value.blank?
|
|
284
302
|
|
|
285
|
-
unless value.blank?
|
|
286
|
-
send(plural_type) << value
|
|
287
|
-
end
|
|
288
303
|
if value.blank?
|
|
289
304
|
send(plural_type).delete_all
|
|
290
305
|
else
|
|
@@ -337,6 +352,10 @@ module ActsAsJoinable
|
|
|
337
352
|
end
|
|
338
353
|
|
|
339
354
|
module InstanceMethods
|
|
355
|
+
def write_join_attribute(name, value)
|
|
356
|
+
|
|
357
|
+
end
|
|
358
|
+
|
|
340
359
|
def destroy_relationships
|
|
341
360
|
#conditions = %Q|(`relationships`.parent_type IN ("#{self.class.name}","#{self.class.base_class.name}") AND `relationships`.parent_id = #{self.id}) OR (`relationships`.child_type IN ("#{self.class.name}","#{self.class.base_class.name}") AND `relationships`.child_id = #{self.id})|
|
|
342
361
|
classes = [self.class.name, self.class.base_class.name].compact.uniq
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
module ActsAsJoinable
|
|
2
|
+
module Dirty
|
|
3
|
+
def self.included(base)
|
|
4
|
+
base.extend ClassMethods
|
|
5
|
+
base.send :include, InstanceMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module InstanceMethods
|
|
13
|
+
def write_join_attribute(name, value, context = nil)
|
|
14
|
+
name = name.to_s
|
|
15
|
+
assert_valid_join_attribute(name)
|
|
16
|
+
|
|
17
|
+
join_attributes_changed = join_attributes_changed_context(context)
|
|
18
|
+
|
|
19
|
+
if join_attributes_changed.include?(name)
|
|
20
|
+
old = join_attributes_changed[name]
|
|
21
|
+
join_attributes_changed.delete(name) unless join_attribute_value_changed?(name, old, value)
|
|
22
|
+
else
|
|
23
|
+
old = clone_join_attribute_value(name, context)
|
|
24
|
+
join_attributes_changed[name] = old if join_attribute_value_changed?(name, old, value)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
join_attributes_context(context)[name] = value
|
|
28
|
+
|
|
29
|
+
value
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def join_attributes_changed?(context = nil)
|
|
33
|
+
!join_attributes_changed_context(context).empty?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def join_attributes_changed(context = nil)
|
|
37
|
+
join_attributes_changed_context(context).keys
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def join_attribute_changes(context = nil)
|
|
41
|
+
join_attributes_changed(context).inject({}) do |changes, join_attribute|
|
|
42
|
+
changes[join_attribute] = join_attribute_change(join_attribute, context)
|
|
43
|
+
changes
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def reload(*args) #:nodoc:
|
|
48
|
+
result = super
|
|
49
|
+
|
|
50
|
+
@join_attributes.clear if @join_attributes
|
|
51
|
+
@join_attributes_changed.clear if @join_attributes_changed
|
|
52
|
+
|
|
53
|
+
result
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def assert_valid_join_attribute(name)
|
|
59
|
+
#raise(ArgumentError, "Unknown join_attribute: #{name}") unless join_attribute_definitions.include?(name)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def join_attributes_context(context)
|
|
63
|
+
@join_attributes ||= {}
|
|
64
|
+
@join_attributes[context.is_a?(Symbol) ? context.to_s : context] ||= {}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def join_attributes_context_loaded?(context)
|
|
68
|
+
true #join_attribute_definitions.length == join_attributes_context(context).length
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Generates a clone of the current value stored for the join_attribute with
|
|
72
|
+
# the given name / context
|
|
73
|
+
def clone_join_attribute_value(name, context)
|
|
74
|
+
value = join_attribute(name, context)
|
|
75
|
+
value.duplicable? ? value.clone : value
|
|
76
|
+
rescue TypeError, NoMethodError
|
|
77
|
+
value
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def join_attribute(name, context = nil)
|
|
81
|
+
join_attributes_context(context)[name]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Keeps track of all join_attributes that have been changed so that they can
|
|
85
|
+
# be properly updated in the database. Maps context -> join_attribute -> value.
|
|
86
|
+
def join_attributes_changed_context(context)
|
|
87
|
+
@join_attributes_changed ||= {}
|
|
88
|
+
@join_attributes_changed[context.is_a?(Symbol) ? context.to_s : context] ||= {}
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def join_attribute_changed?(name, context)
|
|
92
|
+
join_attributes_changed_context(context).include?(name)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def join_attribute_change(name, context)
|
|
96
|
+
[join_attributes_changed_context(context)[name], join_attribute(name, context)] if join_attribute_changed?(name, context)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def join_attribute_was(name, context)
|
|
100
|
+
join_attribute_changed?(name, context) ? join_attributes_changed_context(context)[name] : join_attribute(name, context)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def join_attribute_will_change!(name, context)
|
|
104
|
+
join_attributes_changed_context(context)[name] = clone_join_attribute_value(name, context)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def reset_join_attribute!(name, context)
|
|
108
|
+
write_join_attribute(name, join_attributes_changed_context(context)[name], context) if join_attribute_changed?(name, context)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def join_attribute_value_changed?(name, old, value)
|
|
112
|
+
old != value
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -78,7 +78,7 @@ class ActsAsJoinableTest < ActiveRecord::TestCase
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
# parent, child, and self
|
|
81
|
-
assert_queries(
|
|
81
|
+
assert_queries(3) do
|
|
82
82
|
group.destroy
|
|
83
83
|
end
|
|
84
84
|
|
|
@@ -93,6 +93,22 @@ class ActsAsJoinableTest < ActiveRecord::TestCase
|
|
|
93
93
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
|
+
context "dirty join attributes" do
|
|
97
|
+
setup do
|
|
98
|
+
Group.delete_all
|
|
99
|
+
@group = Group.create!
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
should "get dirty attributes" do
|
|
103
|
+
assert !@group.join_attributes_changed?
|
|
104
|
+
|
|
105
|
+
@group.posts << Post.create!
|
|
106
|
+
|
|
107
|
+
assert @group.join_attributes_changed?
|
|
108
|
+
puts @group.join_attribute_changes.inspect
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
96
112
|
teardown do
|
|
97
113
|
destroy_models
|
|
98
114
|
end
|
metadata
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: acts-as-joinable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 19
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
8
|
- 2
|
|
9
|
-
|
|
9
|
+
- 2
|
|
10
|
+
version: 0.2.2
|
|
10
11
|
platform: ruby
|
|
11
12
|
authors:
|
|
12
13
|
- Lance Pollard
|
|
@@ -14,7 +15,7 @@ autorequire:
|
|
|
14
15
|
bindir: bin
|
|
15
16
|
cert_chain: []
|
|
16
17
|
|
|
17
|
-
date: 2010-10-
|
|
18
|
+
date: 2010-10-26 00:00:00 -05:00
|
|
18
19
|
default_executable:
|
|
19
20
|
dependencies: []
|
|
20
21
|
|
|
@@ -34,6 +35,7 @@ files:
|
|
|
34
35
|
- lib/acts-as-joinable.rb
|
|
35
36
|
- lib/acts_as_joinable/active_record_patch.rb
|
|
36
37
|
- lib/acts_as_joinable/core.rb
|
|
38
|
+
- lib/acts_as_joinable/dirty.rb
|
|
37
39
|
- rails/init.rb
|
|
38
40
|
- test/database.rb
|
|
39
41
|
- test/lib/asset.rb
|