acts-as-joinable 0.2 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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"
@@ -41,6 +41,7 @@ module ActsAsJoinable
41
41
  end
42
42
 
43
43
  include ActsAsJoinable::Core
44
+ include ActsAsJoinable::Dirty
44
45
  end
45
46
  end
46
47
  end
@@ -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[:before_add] = before_add if before_add
114
- options[:after_add] = after_add if after_add
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).last
296
+ send(plural_type)[-1]#.last
279
297
  end
280
298
  define_method "#{singular_type}=" do |value|
281
- #send(relationship_with_context).delete_all
299
+ return value if send(plural_type).map(&:id).include?(value.id)
282
300
 
283
- #send(relationship_with_context).delete_all
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(2) do
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: 15
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- version: "0.2"
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-22 00:00:00 -05:00
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