simply_stored 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Changelog
2
2
  =============
3
3
 
4
+ - Add support for associations not named after the class [akm]
5
+
4
6
  0.3.3
5
7
 
6
8
  - Fix association counting bug
data/README.md CHANGED
@@ -136,6 +136,19 @@ The supported associations are: belongs_to, has_one, has_many, and has_many :thr
136
136
  post.user_count
137
137
  # => 2
138
138
 
139
+
140
+ CouchDB - Custom Associations
141
+
142
+ class Document
143
+ include SimplyStored::Couch
144
+
145
+ belongs_to :creator, :class_name => "User"
146
+ belongs_to :updater, :class_name => "User"
147
+ end
148
+
149
+ d = Document.new
150
+ d.creator = User.first
151
+
139
152
 
140
153
  CouchDB - Validations
141
154
  =============
@@ -2,7 +2,7 @@ module SimplyStored
2
2
  module ClassMethods
3
3
  module Base
4
4
  def get_class_from_name(klass_name)
5
- klass_name.to_s.gsub('__','/').gsub('__','::').classify.constantize
5
+ klass_name.to_s.gsub('__','/').classify.constantize
6
6
  end
7
7
 
8
8
  def foreign_key
@@ -28,4 +28,4 @@ module SimplyStored
28
28
  end
29
29
  end
30
30
  end
31
- end
31
+ end
@@ -3,7 +3,7 @@ module SimplyStored
3
3
  module Couch
4
4
  module BelongsTo
5
5
 
6
- def belongs_to(name)
6
+ def belongs_to(name, options = {})
7
7
  map_definition_without_deleted = <<-eos
8
8
  function(doc) {
9
9
  if (doc['ruby_class'] == '#{self.to_s}' && doc['#{name.to_s}_id'] != null) {
@@ -43,32 +43,37 @@ module SimplyStored
43
43
  :type => "custom",
44
44
  :include_docs => true
45
45
 
46
- properties << SimplyStored::Couch::BelongsTo::Property.new(self, name)
46
+ properties << SimplyStored::Couch::BelongsTo::Property.new(self, name, options)
47
47
  end
48
48
 
49
49
  class Property #:nodoc:
50
50
  attr_accessor :name, :options
51
51
 
52
52
  def initialize(owner_clazz, name, options = {})
53
- @name, @options = name, options
54
- item_class_name = self.item_class_name
53
+ @name = name
54
+ @options = {
55
+ :class_name => name.to_s.singularize.camelize
56
+ }.update(options)
57
+
58
+ @options.assert_valid_keys(:class_name)
59
+
55
60
  owner_clazz.class_eval do
56
61
  attr_reader "#{name}_id"
57
62
  attr_accessor "#{name}_id_was"
58
63
  property "#{name}_id"
59
64
 
60
65
  define_method name do |*args|
61
- options = args.last.is_a?(Hash) ? args.last : {}
62
- options.assert_valid_keys(:force_reload, :with_deleted)
63
- forced_reload = options[:force_reload] || false
64
- with_deleted = options[:with_deleted] || false
66
+ local_options = args.last.is_a?(Hash) ? args.last : {}
67
+ local_options.assert_valid_keys(:force_reload, :with_deleted)
68
+ forced_reload = local_options[:force_reload] || false
69
+ with_deleted = local_options[:with_deleted] || false
65
70
 
66
71
  return instance_variable_get("@#{name}") unless instance_variable_get("@#{name}").nil? or forced_reload
67
- instance_variable_set("@#{name}", send("#{name}_id").present? ? Object.const_get(item_class_name).find(send("#{name}_id"), :with_deleted => with_deleted) : nil)
72
+ instance_variable_set("@#{name}", send("#{name}_id").present? ? Object.const_get(self.class._find_property(name).options[:class_name]).find(send("#{name}_id"), :with_deleted => with_deleted) : nil)
68
73
  end
69
74
 
70
75
  define_method "#{name}=" do |value|
71
- klass = self.class.get_class_from_name(name)
76
+ klass = self.class.get_class_from_name(self.class._find_property(name).options[:class_name])
72
77
  raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
73
78
 
74
79
  instance_variable_set("@#{name}", value)
@@ -107,11 +112,7 @@ module SimplyStored
107
112
  json["#{name}_id"] = object.send("#{name}_id") if object.send("#{name}_id")
108
113
  end
109
114
  alias :value :serialize
110
-
111
- def item_class_name
112
- @name.to_s.camelize
113
- end
114
-
115
+
115
116
  def association?
116
117
  true
117
118
  end
@@ -5,15 +5,15 @@ module SimplyStored
5
5
  properties << SimplyStored::Couch::HasMany::Property.new(self, name, options)
6
6
  end
7
7
 
8
- def define_has_many_getter(name)
8
+ def define_has_many_getter(name, options)
9
9
  define_method(name) do |*args|
10
- options = args.first && args.first.is_a?(Hash) && args.first
11
- if options
12
- options.assert_valid_keys(:force_reload, :with_deleted, :limit, :order)
13
- forced_reload = options.delete(:force_reload)
14
- with_deleted = options[:with_deleted]
15
- limit = options[:limit]
16
- descending = (options[:order] == :desc) ? true : false
10
+ local_options = args.first && args.first.is_a?(Hash) && args.first
11
+ if local_options
12
+ local_options.assert_valid_keys(:force_reload, :with_deleted, :limit, :order)
13
+ forced_reload = local_options.delete(:force_reload)
14
+ with_deleted = local_options[:with_deleted]
15
+ limit = local_options[:limit]
16
+ descending = (local_options[:order] == :desc) ? true : false
17
17
  else
18
18
  forced_reload = false
19
19
  with_deleted = false
@@ -22,25 +22,25 @@ module SimplyStored
22
22
  end
23
23
 
24
24
  cached_results = cached_results = send("_get_cached_#{name}")
25
- cache_key = _cache_key_for(options)
25
+ cache_key = _cache_key_for(local_options)
26
26
  if forced_reload || cached_results[cache_key].nil?
27
- cached_results[cache_key] = find_associated(name, self.class, :with_deleted => with_deleted, :limit => limit, :descending => descending)
27
+ cached_results[cache_key] = find_associated(options[:class_name], self.class, :with_deleted => with_deleted, :limit => limit, :descending => descending, :foreign_key => options[:foreign_key])
28
28
  instance_variable_set("@#{name}", cached_results)
29
29
  end
30
30
  cached_results[cache_key]
31
31
  end
32
32
  end
33
33
 
34
- def define_has_many_through_getter(name, through)
34
+ def define_has_many_through_getter(name, options, through)
35
35
  raise ArgumentError, "no such relation: #{self} - #{through}" unless instance_methods.map(&:to_sym).include?(through.to_sym)
36
36
 
37
37
  define_method(name) do |*args|
38
- options = args.first && args.first.is_a?(Hash) && args.first
39
- if options
40
- options.assert_valid_keys(:force_reload, :with_deleted, :limit)
41
- forced_reload = options[:force_reload]
42
- with_deleted = options[:with_deleted]
43
- limit = options[:limit]
38
+ local_options = args.first && args.first.is_a?(Hash) && args.first
39
+ if local_options
40
+ local_options.assert_valid_keys(:force_reload, :with_deleted, :limit)
41
+ forced_reload = local_options[:force_reload]
42
+ with_deleted = local_options[:with_deleted]
43
+ limit = local_options[:limit]
44
44
  else
45
45
  forced_reload = false
46
46
  with_deleted = false
@@ -48,12 +48,12 @@ module SimplyStored
48
48
  end
49
49
 
50
50
  cached_results = send("_get_cached_#{name}")
51
- cache_key = _cache_key_for(options)
51
+ cache_key = _cache_key_for(local_options)
52
52
 
53
53
  if forced_reload || cached_results[cache_key].nil?
54
54
 
55
55
  # there is probably a faster way to query this
56
- intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted, :limit => limit)
56
+ intermediate_objects = find_associated(through, self.class, :with_deleted => with_deleted, :limit => limit, :foreign_key => options[:foreign_key])
57
57
 
58
58
  through_objects = intermediate_objects.map do |intermediate_object|
59
59
  intermediate_object.send(name.to_s.singularize.underscore, :with_deleted => with_deleted)
@@ -65,7 +65,7 @@ module SimplyStored
65
65
  end
66
66
  end
67
67
 
68
- def define_has_many_setter_add(name)
68
+ def define_has_many_setter_add(name, options)
69
69
  define_method("add_#{name.to_s.singularize}") do |value|
70
70
  klass = self.class.get_class_from_name(name)
71
71
  raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
@@ -79,15 +79,15 @@ module SimplyStored
79
79
  end
80
80
  end
81
81
 
82
- def define_has_many_setter_remove(name)
82
+ def define_has_many_setter_remove(name, options)
83
83
  define_method "remove_#{name.to_s.singularize}" do |value|
84
84
  klass = self.class.get_class_from_name(name)
85
85
  raise ArgumentError, "expected #{klass} got #{value.class}" unless value.is_a?(klass)
86
86
  raise ArgumentError, "cannot remove not mine" unless value.send(self.class.foreign_key.to_sym) == id
87
87
 
88
- if self.class._find_property(name).options[:dependent] == :destroy
88
+ if options[:dependent] == :destroy
89
89
  value.destroy
90
- elsif self.class._find_property(name).options[:dependent] == :ignore
90
+ elsif options[:dependent] == :ignore
91
91
  # skip
92
92
  else # nullify
93
93
  value.send("#{self.class.foreign_key}=", nil)
@@ -100,7 +100,7 @@ module SimplyStored
100
100
  end
101
101
  end
102
102
 
103
- def define_has_many_setter_remove_all(name)
103
+ def define_has_many_setter_remove_all(name, options)
104
104
  define_method "remove_all_#{name}" do
105
105
  all = send("#{name}", :force_reload => true)
106
106
 
@@ -110,27 +110,27 @@ module SimplyStored
110
110
  end
111
111
  end
112
112
 
113
- def define_has_many_count(name, through = nil)
113
+ def define_has_many_count(name, options, through = nil)
114
114
  method_name = name.to_s.singularize.underscore + "_count"
115
115
  define_method(method_name) do |*args|
116
- options = args.first && args.first.is_a?(Hash) && args.first
117
- if options
118
- options.assert_valid_keys(:force_reload, :with_deleted)
119
- forced_reload = options[:force_reload]
120
- with_deleted = options[:with_deleted]
116
+ local_options = args.first && args.first.is_a?(Hash) && args.first
117
+ if local_options
118
+ local_options.assert_valid_keys(:force_reload, :with_deleted)
119
+ forced_reload = local_options[:force_reload]
120
+ with_deleted = local_options[:with_deleted]
121
121
  else
122
122
  forced_reload = false
123
123
  with_deleted = false
124
124
  end
125
125
 
126
126
  if forced_reload || instance_variable_get("@#{method_name}").nil?
127
- instance_variable_set("@#{method_name}", count_associated(through || name, self.class, :with_deleted => with_deleted))
127
+ instance_variable_set("@#{method_name}", count_associated(through || options[:class_name], self.class, :with_deleted => with_deleted, :foreign_key => options[:foreign_key]))
128
128
  end
129
129
  instance_variable_get("@#{method_name}")
130
130
  end
131
131
  end
132
132
 
133
- def define_cache_accessors(name)
133
+ def define_cache_accessors(name, options)
134
134
  define_method "_get_cached_#{name}" do
135
135
  instance_variable_get("@#{name}") || {}
136
136
  end
@@ -141,8 +141,8 @@ module SimplyStored
141
141
  instance_variable_set("@#{name}", cached)
142
142
  end
143
143
 
144
- define_method "_cache_key_for" do |options|
145
- options.blank? ? :all : options.to_s
144
+ define_method "_cache_key_for" do |opt|
145
+ opt.blank? ? :all : opt.to_s
146
146
  end
147
147
  end
148
148
 
@@ -152,26 +152,28 @@ module SimplyStored
152
152
  def initialize(owner_clazz, name, options = {})
153
153
  options = {
154
154
  :dependent => :nullify,
155
- :through => nil
155
+ :through => nil,
156
+ :class_name => name.to_s.singularize.camelize,
157
+ :foreign_key => owner_clazz.name.singularize.underscore.foreign_key
156
158
  }.update(options)
157
159
  @name, @options = name, options
158
160
 
159
- options.assert_valid_keys(:dependent, :through)
161
+ options.assert_valid_keys(:dependent, :through, :class_name, :foreign_key)
160
162
 
161
163
  if options[:through]
162
164
  owner_clazz.class_eval do
163
- define_cache_accessors(name)
164
- define_has_many_through_getter(name, options[:through])
165
- define_has_many_count(name, options[:through])
165
+ define_cache_accessors(name, options)
166
+ define_has_many_through_getter(name, options, options[:through])
167
+ define_has_many_count(name, options, options[:through])
166
168
  end
167
169
  else
168
170
  owner_clazz.class_eval do
169
- define_cache_accessors(name)
170
- define_has_many_getter(name)
171
- define_has_many_setter_add(name)
172
- define_has_many_setter_remove(name)
173
- define_has_many_setter_remove_all(name)
174
- define_has_many_count(name)
171
+ define_cache_accessors(name, options)
172
+ define_has_many_getter(name, options)
173
+ define_has_many_setter_add(name, options)
174
+ define_has_many_setter_remove(name, options)
175
+ define_has_many_setter_remove_all(name, options)
176
+ define_has_many_count(name, options)
175
177
  end
176
178
  end
177
179
  end
@@ -5,9 +5,9 @@ module SimplyStored
5
5
  properties << SimplyStored::Couch::HasOne::Property.new(self, name, options)
6
6
  end
7
7
 
8
- def define_has_one_setter(name)
8
+ def define_has_one_setter(name, options)
9
9
  define_method("#{name}=") do |value|
10
- klass = self.class.get_class_from_name(name)
10
+ klass = self.class.get_class_from_name(self.class._find_property(name).options[:class_name])
11
11
  raise ArgumentError, "expected #{klass} got #{value.class}" unless value.nil? || value.is_a?(klass)
12
12
  old_value = send("#{name}", :force_reload => true)
13
13
  if value.nil?
@@ -19,7 +19,7 @@ module SimplyStored
19
19
  end
20
20
 
21
21
  if old_value
22
- if self.class._find_property(name).options[:dependent] == :destroy
22
+ if options[:dependent] == :destroy
23
23
  old_value.destroy
24
24
  else
25
25
  old_value.send("#{self.class.foreign_property}=", nil)
@@ -30,20 +30,20 @@ module SimplyStored
30
30
  end
31
31
  end
32
32
 
33
- def define_has_one_getter(name)
33
+ def define_has_one_getter(name, options)
34
34
  define_method(name) do |*args|
35
- options = args.first && args.first.is_a?(Hash) && args.first
36
- if options
37
- options.assert_valid_keys(:force_reload, :with_deleted)
38
- forced_reload = options[:force_reload]
39
- with_deleted = options[:with_deleted]
35
+ local_options = args.first && args.first.is_a?(Hash) && args.first
36
+ if local_options
37
+ local_options.assert_valid_keys(:force_reload, :with_deleted)
38
+ forced_reload = local_options[:force_reload]
39
+ with_deleted = local_options[:with_deleted]
40
40
  else
41
41
  forced_reload = false
42
42
  with_deleted = false
43
43
  end
44
44
 
45
45
  if forced_reload || instance_variable_get("@#{name}").nil?
46
- instance_variable_set("@#{name}", find_one_associated(name, self.class, :with_deleted => with_deleted))
46
+ instance_variable_set("@#{name}", find_one_associated(options[:class_name], self.class, :with_deleted => with_deleted, :foreign_key => options[:foreign_key]))
47
47
  end
48
48
  instance_variable_get("@#{name}")
49
49
  end
@@ -53,14 +53,18 @@ module SimplyStored
53
53
  attr_reader :name, :options
54
54
 
55
55
  def initialize(owner_clazz, name, options = {})
56
- options = {:dependent => :nullify}.update(options)
56
+ options = {
57
+ :dependent => :nullify,
58
+ :class_name => name.to_s.singularize.camelize,
59
+ :foreign_key => owner_clazz.name.singularize.underscore.foreign_key
60
+ }.update(options)
57
61
  @name, @options = name, options
58
62
 
59
- options.assert_valid_keys(:dependent)
63
+ options.assert_valid_keys(:dependent, :class_name, :foreign_key)
60
64
 
61
65
  owner_clazz.class_eval do
62
- define_has_one_getter(name)
63
- define_has_one_setter(name)
66
+ define_has_one_getter(name, options)
67
+ define_has_one_setter(name, options)
64
68
  end
65
69
  end
66
70
 
@@ -72,8 +72,8 @@ module SimplyStored
72
72
  retry_count = 0
73
73
  begin
74
74
  blk.call
75
- rescue RestClient::Conflict => e
76
- if self.class.auto_conflict_resolution_on_save && retry_count < max_retries && try_to_merge_conflict
75
+ rescue RestClient::Exception, RestClient::Conflict => e
76
+ if (e.http_code == 409 || e.is_a?(RestClient::Conflict)) && self.class.auto_conflict_resolution_on_save && retry_count < max_retries && try_to_merge_conflict
77
77
  retry_count += 1
78
78
  retry
79
79
  else
@@ -175,6 +175,7 @@ module SimplyStored
175
175
  end
176
176
 
177
177
  def find_associated(from, to, options = {})
178
+ foreign_key = options.delete(:foreign_key).gsub(/_id$/, '')
178
179
  view_options = {}
179
180
  view_options[:reduce] = false
180
181
  view_options[:descending] = options[:descending] if options[:descending]
@@ -189,11 +190,11 @@ module SimplyStored
189
190
  if options[:with_deleted]
190
191
  CouchPotato.database.view(
191
192
  self.class.get_class_from_name(from).send(
192
- "association_#{from.to_s.singularize.underscore}_belongs_to_#{to.name.singularize.underscore}_with_deleted", view_options))
193
+ "association_#{from.to_s.singularize.underscore}_belongs_to_#{foreign_key}_with_deleted", view_options))
193
194
  else
194
195
  CouchPotato.database.view(
195
196
  self.class.get_class_from_name(from).send(
196
- "association_#{from.to_s.singularize.underscore}_belongs_to_#{to.name.singularize.underscore}", view_options))
197
+ "association_#{from.to_s.singularize.underscore}_belongs_to_#{foreign_key}", view_options))
197
198
  end
198
199
  end
199
200
 
@@ -6,98 +6,112 @@ module SimplyStored
6
6
  end
7
7
 
8
8
  module ClassMethods
9
- def belongs_to(klass_name)
10
- define_belongs_to_getter(klass_name)
11
- define_belongs_to_setter(klass_name)
9
+ def belongs_to(name, options = nil)
10
+ options = {
11
+ :class_name => self.formalize_class_name(name),
12
+ :foreign_key => "#{name}_id"
13
+ }.update(options || {})
14
+ define_belongs_to_getter(name, options)
15
+ define_belongs_to_setter(name, options)
12
16
  end
13
17
 
14
- def has_one(klass_name, options = {})
18
+ def has_one(name, options = {})
15
19
  options = {
16
20
  :clear => :nullify, # or :destroy
17
- :dependent => :nullify # or :destroy
21
+ :dependent => :nullify, # or :destroy
22
+ :class_name => self.formalize_class_name(name),
23
+ :foreign_key => self.foreign_key
18
24
  }.update(options)
19
25
 
20
- define_has_one_getter(klass_name, options)
21
- define_has_one_setter(klass_name, options)
22
- define_has_one_dependent_clearing(klass_name, options)
26
+ define_has_one_getter(name, options)
27
+ define_has_one_setter(name, options)
28
+ define_has_one_dependent_clearing(name, options)
23
29
  end
24
30
 
25
- def has_many(klass_name, options = {})
31
+ def has_many(name, options = {})
26
32
  options = {
27
33
  :clear => :nullify, # or :destroy
28
- :dependent => :nullify # or :destroy
34
+ :dependent => :nullify, # or :destroy
35
+ :class_name => self.formalize_class_name(name.to_s.singularize),
36
+ :foreign_key => self.foreign_key
29
37
  }.update(options)
30
38
 
31
- define_has_many_getter(klass_name, options)
32
- define_has_many_setter_add(klass_name, options)
33
- define_has_many_setter_remove(klass_name, options)
34
- define_has_many_setter_remove_all(klass_name, options)
35
- define_has_many_dependent_clearing(klass_name, options)
39
+ define_has_many_getter(name, options)
40
+ define_has_many_setter_add(name, options)
41
+ define_has_many_setter_remove(name, options)
42
+ define_has_many_setter_remove_all(name, options)
43
+ define_has_many_dependent_clearing(name, options)
36
44
  end
37
45
 
38
- def define_belongs_to_getter(klass_name)
39
- define_method klass_name.to_s do
40
- klass = self.class.get_class_from_name(klass_name)
41
- cached_version = instance_variable_get("@_cached_belongs_to_#{klass_name}")
42
- if cached_version.nil? and self["#{klass_name}_id"].present?
43
- cached_version = klass.find(self.send("#{klass_name}_id"), :auto_load => true)
44
- instance_variable_set("@_cached_belongs_to_#{klass_name}", cached_version)
46
+ def define_belongs_to_getter(name, options)
47
+ foreign_key_column = options[:foreign_key]
48
+ define_method(name.to_s) do
49
+ klass = options[:class_name].constantize
50
+ cached_version = instance_variable_get("@_cached_belongs_to_#{name}")
51
+ if cached_version.nil? and self[foreign_key_column].present?
52
+ cached_version = klass.find(self.send(foreign_key_column), :auto_load => true)
53
+ instance_variable_set("@_cached_belongs_to_#{name}", cached_version)
45
54
  end
46
55
  cached_version
47
56
  end
48
57
  end
49
58
 
50
- def define_belongs_to_setter(klass_name)
51
- define_method "#{klass_name}=" do |val|
52
- klass = self.class.get_class_from_name(klass_name)
59
+ def define_belongs_to_setter(name, options)
60
+ foreign_key_column = options[:foreign_key]
61
+ define_method("#{name}=") do |val|
62
+ klass = options[:class_name].constantize
53
63
  raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
54
- self.send("#{klass_name}_id=", val.id)
55
- instance_variable_set("@_cached_belongs_to_#{klass_name}", val)
64
+ self.send("#{foreign_key_column}=", val.id)
65
+ instance_variable_set("@_cached_belongs_to_#{name}", val)
56
66
  end
57
67
  end
58
68
 
59
- def define_has_one_getter(klass_name, options)
60
- define_method klass_name.to_s do
61
- klass = self.class.get_class_from_name(klass_name)
62
- cached_version = instance_variable_get("@_cached_has_one_#{klass_name}")
69
+ def define_has_one_getter(name, options)
70
+ foreign_key_column = options[:foreign_key]
71
+ define_method(name.to_s) do
72
+ klass = options[:class_name].constantize
73
+ cached_version = instance_variable_get("@_cached_has_one_#{name}")
63
74
  if cached_version
64
- return cached_version
75
+ cached_version
65
76
  else
66
- cached_version = klass.send("find_by_#{self.class.foreign_key}".to_sym, self.id, {:auto_load => true})
67
- instance_variable_set("@_cached_has_one_#{klass_name}", cached_version)
68
- return cached_version
77
+ cached_version = klass.send("find_by_#{foreign_key_column}".to_sym, self.id, {:auto_load => true})
78
+ instance_variable_set("@_cached_has_one_#{name}", cached_version)
79
+ cached_version
69
80
  end
70
81
  end
71
82
  end
72
83
 
73
- def define_has_one_setter(klass_name, options)
74
- define_method "#{klass_name}=" do |val|
75
- klass = self.class.get_class_from_name(klass_name)
84
+ def define_has_one_setter(name, options)
85
+ foreign_key_column = options[:foreign_key]
86
+ define_method("#{name}=") do |val|
87
+ klass = options[:class_name].constantize
76
88
  raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
77
89
 
78
90
  # clear old
79
- old = self.send("#{klass_name}")
80
- old.send("#{self.class.foreign_key}=", nil) if old && options[:clear] == :nullify
91
+ old = self.send("#{name}")
92
+ old.send("#{foreign_key_column}=", nil) if old && options[:clear] == :nullify
81
93
  old.delete if old && options[:clear] == :destroy
82
94
 
83
95
  # store new
84
- val.send("#{self.class.foreign_key}=", self.id)
85
- instance_variable_set("@_cached_has_one_#{klass_name}", val)
96
+ val.send("#{foreign_key_column}=", self.id)
97
+ instance_variable_set("@_cached_has_one_#{name}", val)
86
98
  end
87
99
  end
88
100
 
89
- def define_has_one_dependent_clearing(klass_name, options)
101
+ def define_has_one_dependent_clearing(name, options)
90
102
  # add method to list of methods to run when deleted
91
103
  @_clear_dependents_after_delete_methods ||= []
92
- @_clear_dependents_after_delete_methods << "has_one_clear_#{klass_name}_after_destroy"
104
+ @_clear_dependents_after_delete_methods << "has_one_clear_#{name}_after_destroy"
93
105
 
94
106
  # define actual clearing/deleting
95
- define_method "has_one_clear_#{klass_name}_after_destroy" do
96
- klass = self.class.get_class_from_name(klass_name)
97
- dependent = klass.send("find_by_#{self.class.foreign_key}".to_sym, self.id)
98
- if options[:dependent] == :nullify
99
- dependent.send("#{self.class.foreign_key}=", nil) if dependent
100
- elsif options[:dependent] == :destroy
107
+ foreign_key_column = options[:foreign_key]
108
+ define_method("has_one_clear_#{name}_after_destroy") do
109
+ klass = options[:class_name].constantize
110
+ dependent = klass.send("find_by_#{foreign_key_column}".to_sym, self.id)
111
+ case options[:dependent]
112
+ when :nullify then
113
+ dependent.send("#{foreign_key_column}=", nil) if dependent
114
+ when :destroy then
101
115
  dependent.delete if dependent
102
116
  else
103
117
  raise ArgumentError, "unknown dependent method: #{options[:dependent].inspect}"
@@ -105,76 +119,81 @@ module SimplyStored
105
119
  end
106
120
  end
107
121
 
108
- def define_has_many_getter(klass_name, options)
109
- define_method klass_name.to_s do
110
- klass = self.class.get_class_from_name(klass_name)
111
- cached_version = instance_variable_get("@_cached_has_many_#{klass_name}")
122
+ def define_has_many_getter(name, options)
123
+ foreign_key_column = options[:foreign_key]
124
+ define_method(name.to_s) do
125
+ klass = options[:class_name].constantize
126
+ cached_version = instance_variable_get("@_cached_has_many_#{name}")
112
127
  if cached_version
113
- return cached_version
128
+ cached_version
114
129
  else
115
- cached_version = klass.send("find_all_by_#{self.class.foreign_key}".to_sym, self.id, {:auto_load => true})
116
- instance_variable_set("@_cached_has_many_#{klass_name}", cached_version)
117
- return cached_version
130
+ cached_version = klass.send("find_all_by_#{foreign_key_column}".to_sym, self.id, {:auto_load => true})
131
+ instance_variable_set("@_cached_has_many_#{name}", cached_version)
132
+ cached_version
118
133
  end
119
134
  end
120
135
  end
121
136
 
122
- def define_has_many_setter_add(klass_name, options)
123
- define_method "add_#{klass_name.to_s.singularize}" do |val|
124
- klass = self.class.get_class_from_name(klass_name)
137
+ def define_has_many_setter_add(name, options)
138
+ foreign_key_column = options[:foreign_key]
139
+ define_method("add_#{name.to_s.singularize}") do |val|
140
+ klass = options[:class_name].constantize
125
141
  raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
126
- val.send("#{self.class.foreign_key}=", self.id)
142
+ val.send("#{foreign_key_column}=", self.id)
127
143
  val.save(false)
128
- cached_version = instance_variable_get("@_cached_has_many_#{klass_name}") || []
129
- instance_variable_set("@_cached_has_many_#{klass_name}", cached_version << val)
144
+ cached_version = instance_variable_get("@_cached_has_many_#{name}") || []
145
+ instance_variable_set("@_cached_has_many_#{name}", cached_version << val)
130
146
  end
131
147
  end
132
148
 
133
- def define_has_many_setter_remove(klass_name, options)
134
- define_method "remove_#{klass_name.to_s.singularize}" do |val|
135
- klass = self.class.get_class_from_name(klass_name)
149
+ def define_has_many_setter_remove(name, options)
150
+ foreign_key_column = options[:foreign_key]
151
+ define_method("remove_#{name.to_s.singularize}") do |val|
152
+ klass = options[:class_name].constantize
136
153
  raise ArgumentError, "expected #{klass} got #{val.class}" unless val.is_a?(klass)
137
- raise ArgumentError, "cannot remove not mine" unless val.send(self.class.foreign_key.to_sym) == self.id
138
- if options[:clear] == :nullify
139
- val.send("#{self.class.foreign_key}=", nil)
154
+ raise ArgumentError, "cannot remove not mine" unless val.send(foreign_key_column) == self.id
155
+ case options[:clear]
156
+ when :nullify then
157
+ val.send("#{foreign_key_column}=", nil)
140
158
  val.save(false)
141
- elsif options[:clear] == :destroy
159
+ when :destroy then
142
160
  val.delete
143
161
  else
144
162
  raise "Unknown option for clear: #{option[:clear]}"
145
163
  end
146
- cached_version = instance_variable_get("@_cached_has_many_#{klass_name}") || []
147
- instance_variable_set("@_cached_has_many_#{klass_name}", cached_version.delete_if{|x| x.id == val.id})
164
+ cached_version = instance_variable_get("@_cached_has_many_#{name}") || []
165
+ instance_variable_set("@_cached_has_many_#{name}", cached_version.delete_if{|x| x.id == val.id})
148
166
  end
149
167
  end
150
168
 
151
- def define_has_many_setter_remove_all(klass_name, options)
152
- define_method "remove_all_#{klass_name}" do
153
- klass = self.class.get_class_from_name(klass_name)
154
-
155
- all = klass.send("find_all_by_#{self.class.foreign_key}".to_sym, self.id)
156
-
169
+ def define_has_many_setter_remove_all(name, options)
170
+ foreign_key_column = options[:foreign_key]
171
+ define_method("remove_all_#{name}") do
172
+ klass = options[:class_name].constantize
173
+ all = klass.send("find_all_by_#{foreign_key_column}".to_sym, self.id)
157
174
  all.each do |item|
158
- self.send("remove_#{klass_name.to_s.singularize}", item)
175
+ self.send("remove_#{name.to_s.singularize}", item)
159
176
  end
160
- instance_variable_set("@_cached_has_many_#{klass_name}", [])
177
+ instance_variable_set("@_cached_has_many_#{name}", [])
161
178
  end
162
179
  end
163
180
 
164
- def define_has_many_dependent_clearing(klass_name, options)
181
+ def define_has_many_dependent_clearing(name, options)
165
182
  # add method to list of methods to run when deleted
166
183
  @_clear_dependents_after_delete_methods ||= []
167
- @_clear_dependents_after_delete_methods << "has_many_clear_#{klass_name}_after_destroy"
184
+ @_clear_dependents_after_delete_methods << "has_many_clear_#{name}_after_destroy"
168
185
 
169
186
  # define actual clearing/deleting
170
- define_method "has_many_clear_#{klass_name}_after_destroy" do
171
- klass = self.class.get_class_from_name(klass_name)
172
- dependents = klass.send("find_all_by_#{self.class.foreign_key}".to_sym, self.id)
173
- if options[:dependent] == :nullify
187
+ foreign_key_column = options[:foreign_key]
188
+ define_method("has_many_clear_#{name}_after_destroy") do
189
+ klass = options[:class_name].constantize
190
+ dependents = klass.send("find_all_by_#{foreign_key_column}".to_sym, self.id)
191
+ case options[:dependent]
192
+ when :nullify then
174
193
  dependents.each do |dependent|
175
- dependent.send("#{self.class.foreign_key}=", nil)
194
+ dependent.send("#{foreign_key_column}=", nil)
176
195
  end
177
- elsif options[:dependent] == :destroy
196
+ when :destroy then
178
197
  dependents.each do |dependent|
179
198
  dependent.delete
180
199
  end
@@ -193,4 +212,4 @@ module SimplyStored
193
212
  end
194
213
  end
195
214
  end
196
- end
215
+ end
@@ -206,7 +206,11 @@ module SimplyStored
206
206
  end
207
207
 
208
208
  def self.get_class_from_name(klass_name)
209
- klass_name.to_s.gsub('__','/').gsub('__','::').classify.constantize
209
+ klass_name.to_s.gsub('__','/').classify.constantize
210
+ end
211
+
212
+ def self.formalize_class_name(name)
213
+ name.to_s.gsub('__','/').gsub('__','::').classify
210
214
  end
211
215
  end
212
- end
216
+ end
data/lib/simply_stored.rb CHANGED
@@ -4,7 +4,7 @@ require File.expand_path(File.dirname(__FILE__) + '/simply_stored/storage')
4
4
  require File.expand_path(File.dirname(__FILE__) + '/simply_stored/class_methods_base')
5
5
 
6
6
  module SimplyStored
7
- VERSION = '0.3.3'
7
+ VERSION = '0.3.4'
8
8
  class Error < RuntimeError; end
9
9
  class RecordNotFound < RuntimeError; end
10
10
  end
@@ -10,6 +10,7 @@ class User
10
10
  has_many :strict_posts
11
11
  has_many :hemorrhoids
12
12
  has_many :pains, :through => :hemorrhoids
13
+ has_many :docs, :class_name => "Document", :foreign_key => "editor_id"
13
14
 
14
15
  view :by_name_and_created_at, :key => [:name, :created_at]
15
16
  end
@@ -44,6 +45,13 @@ class Category
44
45
  validates_inclusion_of :name, :in => ["food", "drinks", "party"], :allow_blank => true
45
46
  end
46
47
 
48
+ class Document
49
+ include SimplyStored::Couch
50
+
51
+ belongs_to :author, :class_name => "User"
52
+ belongs_to :editor, :class_name => "User"
53
+ end
54
+
47
55
  class Tag
48
56
  include SimplyStored::Couch
49
57
 
@@ -474,6 +474,25 @@ class CouchTest < Test::Unit::TestCase
474
474
  assert_nil post.user
475
475
  end
476
476
  end
477
+
478
+ context "with aliased associations" do
479
+ should "allow different names for the same class" do
480
+ editor = User.create(:name => 'Editor', :title => 'Dr.')
481
+ author = User.create(:name => 'author', :title => 'Dr.')
482
+ assert_not_nil editor.id, editor.errors.inspect
483
+ assert_not_nil author.id, author.errors.inspect
484
+
485
+ doc = Document.create(:editor => editor, :author => author)
486
+ doc.save!
487
+ assert_equal editor.id, doc.editor_id
488
+ assert_equal author.id, doc.author_id
489
+ doc = Document.find(doc.id)
490
+ assert_not_nil doc.editor, doc.inspect
491
+ assert_not_nil doc.author
492
+ assert_equal editor.id, doc.editor.id
493
+ assert_equal author.id, doc.author.id
494
+ end
495
+ end
477
496
  end
478
497
 
479
498
  context "with has_many" do
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 3
9
- version: 0.3.3
8
+ - 4
9
+ version: 0.3.4
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mathias Meyer, Jonathan Weiss
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-19 00:00:00 +02:00
17
+ date: 2010-06-17 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency