acts_has_many 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -33,13 +33,13 @@ end
33
33
  # OR
34
34
 
35
35
  class Company < ActiveRecord::Base
36
- acts_has_many relations: [:users] # array necessary relations
36
+ acts_has_many :users # list necessary relations
37
37
 
38
38
  has_many :users
39
39
  end
40
40
 
41
41
  # acts_has_many options:
42
- # :relations( array; default: has many relation which are written above) - necessary relations
42
+ # list relations(it maybe missed if you use has many relation which are written above)
43
43
  # :compare( string or symbol; default: :title) - name column with unique elements in table
44
44
  # :through( boolean; default: false) - if you use has_many :through
45
45
 
@@ -60,9 +60,7 @@ company.actuale? :users # => false ( exclude 1 record of current relation)
60
60
 
61
61
  company # => <Company id: 1, title: "Microsoft">
62
62
 
63
- update_id, delete_id = company.has_many_update(data: { title: 'Google'}, relation: :users)
64
- # or
65
- # update_id, delete_id = company.has_many_update({ title: 'Google'}, :users)
63
+ update_id, delete_id = company.has_many_update({ title: 'Google'}, :users)
66
64
  # or
67
65
  # update_id, delete_id = company.update_with_users({ title: 'Google'})
68
66
 
@@ -213,4 +211,4 @@ features. Before submitting a bug report or feature request, check to make sure
213
211
  been submitted. You can indicate support for an existing issuse by voting it up. When submitting a
214
212
  bug report, please include a [Gist](http://gist.github.com/) that includes a stack trace and any
215
213
  details that may be necessary to reproduce the bug, including your gem version, Ruby version, and
216
- operating system. Ideally, a bug report should include a pull request with failing specs.
214
+ operating system. Ideally, a bug report should include a pull request with failing specs.
@@ -1,10 +1,10 @@
1
1
  module ActiveRecord
2
2
  module Acts #:nodoc:
3
3
  module HasMany
4
-
4
+
5
5
  # class methods for use in model
6
6
  # +acts_has_many_for+
7
- # +acts_has_many+
7
+ # +acts_has_many+
8
8
  #
9
9
  # the last method added:
10
10
  #
@@ -12,54 +12,54 @@ module ActiveRecord
12
12
  # +has_many_through_update+
13
13
  # +dependent_relations+
14
14
  # +compare+
15
- #
15
+ #
16
16
  # Instance methods:
17
17
  # +model+
18
- # +has_many_update+
18
+ # +has_many_update+
19
19
  # +has_many_update!+
20
20
  # +update_with_<relation>+
21
21
  # +actuale?+
22
22
  #
23
23
  # set +before_destroy+ callback;
24
24
 
25
- def self.included(base)
26
- base.extend(ClassMethods)
25
+ def self.included base
26
+ base.extend ClassMethods
27
27
  end
28
-
28
+
29
29
  #
30
- # Acts Has Many gem is for added functional to work
30
+ # Acts Has Many gem is for added functional to work
31
31
  # with +has_many+ relation (additional is has_many :trhough)
32
- #
32
+ #
33
33
  # +acts_has_many+ and +acts_has_many_for+ are class methods for all model,
34
34
  # and you can use them for connection acts_has_many functional to necessary model
35
- # acts_has_many set in model where is has_many relation and
35
+ # acts_has_many set in model where is has_many relation and
36
36
  # acts_has_many_for in model where use model with acts_has_many
37
37
  #
38
38
  # class Education < ActiveRecord::Base
39
39
  # belongs_to :location
40
- # ...
40
+ #
41
41
  # acts_has_many_for :location
42
42
  # end
43
- #
43
+ #
44
44
  # class Location < ActiveRecord::Base
45
45
  # has_many :educaitons
46
46
  # acts_has_many
47
47
  # end
48
- #
48
+ #
49
49
  # You can use +acts_has_many+ methods without +acts_has_many_for+
50
50
  #
51
51
  # class Education < ActiveRecord::Base
52
52
  # belongs_to :location
53
- # ...
53
+ #
54
54
  # end
55
- #
55
+ #
56
56
  # class Location < ActiveRecord::Base
57
57
  # has_many :education
58
58
  # acts_has_many
59
59
  # end
60
- #
60
+ #
61
61
  # in this case you can use nex function:
62
- #
62
+ #
63
63
  # education = Education.first
64
64
  # location = education.location # get location from education
65
65
  #
@@ -68,7 +68,7 @@ module ActiveRecord
68
68
  # new_id, del_id = location.has_many_update({title:"Kyiv"}, :educations)
69
69
  # # or with dinamic methods helper
70
70
  # new_id, del_id = location.update_with_educations {title:"Kyiv"}
71
- #
71
+ #
72
72
  # # you can also use has_many_update! which updated relation with parent row without you
73
73
  # location.has_many_update!({title: "Kyiv"}, education)
74
74
  #
@@ -80,7 +80,7 @@ module ActiveRecord
80
80
  # # and
81
81
  # location.has_many_update! {title:"Kyiv"}
82
82
  #
83
-
83
+
84
84
  module ClassMethods
85
85
 
86
86
  #
@@ -88,23 +88,29 @@ module ActiveRecord
88
88
  # use for set link between parent row and child
89
89
  # options: list relations (symbol)
90
90
  #
91
-
92
- def acts_has_many_for(*relations)
91
+
92
+ def acts_has_many_for *relations
93
93
  relations.each do |relation|
94
94
  relation = relation.to_s
95
95
  class_eval <<-EOV
96
96
  def #{relation}
97
- row = #{relation.classify}.find #{relation.foreign_key}
98
- row.tmp_parrent_id = id
99
- row.tmp_current_relation = '#{self.name.tableize}'
100
- row
97
+ if #{relation.foreign_key}
98
+ row = #{relation.classify}.find #{relation.foreign_key}
99
+ if row.is_a? #{relation.classify}
100
+ row.tmp_parrent_id = id
101
+ row.tmp_current_relation = '#{self.name.tableize}'
102
+ end
103
+ row
104
+ else
105
+ super
106
+ end
101
107
  end
102
108
  EOV
103
109
  end
104
110
  end
105
111
 
106
112
  #
107
- # +acts_has_many+ - available method in all model and switch on
113
+ # +acts_has_many+ - available method in all model and switch on
108
114
  # extension functional in concrete model (need located this method
109
115
  # after relation which include in dependence, or anywhere but set depend relation)
110
116
  # options
@@ -112,23 +118,31 @@ module ActiveRecord
112
118
  # :relations( array) - concrete name of depended relation
113
119
  # :through( boolean) - off or on has_many_through_update method
114
120
  #
115
-
116
- def acts_has_many(options = {})
117
- dependent_relations = []
118
- options_default = { compare: :title, through: false }
119
121
 
120
- options = options_default.merge options
121
-
122
+ def acts_has_many *opt
123
+ options = { compare: :title, through: false }
124
+ options.update opt.extract_options!
125
+ options.assert_valid_keys :compare, :through, :relations
126
+ if options[:relations]
127
+ ActiveSupport::Deprecation.warn "Use simple list relations insted 'relation: Array'! Parameter 'relation: []' will be romoved in v1.0!"
128
+ end
129
+ options[:relations] ||= opt
130
+
122
131
  options[:relations] = self.reflect_on_all_associations(:has_many)
123
- .map{|o| o.name} if options[:relations].nil?
124
-
132
+ .map(&:name) if options[:relations].blank?
133
+
134
+ dependent_relations = []
125
135
  options[:relations].each do |relation|
126
- dependent_relations << relation.to_s.tableize
136
+ if reflect_on_association relation.to_sym
137
+ dependent_relations << relation.to_s.tableize
138
+ else
139
+ raise ArgumentError, "No association found for name `#{relation}'. Has it been defined yet?"
140
+ end
127
141
  end
128
-
142
+
129
143
  #
130
- # +has_many_through_update+ (return array) [ 1 - array objects records, 2 - array delete ids ]
131
- # options
144
+ # +has_many_through_update+ (return array) [ 1 - array objects records, 2 - array delete ids ]
145
+ # options
132
146
  # :update( array) - data for update (id and data)
133
147
  # :new( array) - data for create record (data)
134
148
  #
@@ -136,20 +150,19 @@ module ActiveRecord
136
150
  #
137
151
 
138
152
  has_many_through = ''
139
- if(options[:through])
153
+ if options[:through]
140
154
  has_many_through = """
141
155
  def self.has_many_through_update(options)
142
156
  record_add = []
143
157
  record_del = []
144
-
158
+
145
159
  # update
146
160
  options[:update].each do |id, data|
147
- add, del = #{self}.find(id)
148
- .has_many_update(:data => data, :relation => options[:relation])
161
+ add, del = #{self}.find(id).has_many_update data, options[:relation]
149
162
  record_add << add unless add.nil?
150
163
  record_del << del unless del.nil?
151
164
  end unless options[:update].nil?
152
-
165
+
153
166
  # new
154
167
  unless options[:new].nil?
155
168
  options[:new].uniq!
@@ -159,25 +172,25 @@ module ActiveRecord
159
172
  .where('#{options[:compare]}' => data['#{options[:compare]}'.to_sym])
160
173
  .first_or_create(data)
161
174
  record_del.delete record_add.last.id
162
- end
175
+ end
163
176
  end
164
-
165
- record_add = #{self}.where('id IN (?)', record_add) unless record_add.empty?
177
+
178
+ record_add = #{self}.where('id IN (?)', record_add) unless record_add.empty?
166
179
  [record_add, record_del]
167
180
  end """
168
181
  end
169
-
182
+
170
183
  # add dinamic methods for example
171
184
  # update_with_<relation>(data) equal has_many_update(data, relation)
172
185
  extend_methods = ''
173
186
  dependent_relations.each do |relation|
174
187
  extend_methods += """
175
188
  def update_with_#{relation}(data)
176
- has_many_update data: data, relation: :#{relation}
189
+ has_many_update data, :#{relation}
177
190
  end
178
191
  """
179
192
  end
180
-
193
+
181
194
  class_eval <<-EOV
182
195
  include ActiveRecord::Acts::HasMany::InstanceMethods
183
196
  class << self
@@ -191,96 +204,97 @@ module ActiveRecord
191
204
 
192
205
  def model
193
206
  #{self}
194
- end
195
-
207
+ end
208
+
196
209
  #{extend_methods}
197
210
  #{has_many_through}
198
-
211
+
199
212
  attr_accessor :tmp_current_relation, :tmp_parrent_id
213
+ validates :#{options[:compare]}, uniqueness: true, presence: true
200
214
  before_destroy :destroy_filter
201
215
  EOV
202
216
  end
203
217
  end
204
-
218
+
205
219
  module InstanceMethods
206
-
220
+
207
221
  #
208
- # +has_many_update!+ identicaly to has_many_update but
222
+ # +has_many_update!+ identicaly to has_many_update but
209
223
  # You can use this method when you use +acts_has_many_for+
210
224
  # and get object for update with help of +relation+ or give parent row
211
225
  # option
212
- # data for update
213
- # parrent row (maybe miss)
226
+ # data - date for update
227
+ # obj - parrent row (maybe miss)
214
228
  #
215
229
 
216
- def has_many_update!(*data)
230
+ def has_many_update! *data
217
231
  if data.size == 2
218
232
  self.tmp_current_relation = data[1].class.name.tableize
219
233
  self.tmp_parrent_id = data[1].id
220
234
  end
221
-
235
+
222
236
  if tmp_current_relation.nil? or tmp_parrent_id.nil?
223
- p "ArgumentError: 'has_many_update!' don't have data about parent object"
224
- p "* maybe you use 'acts_has_many_for' incorrectly"
225
- p "* if you don't use 'acts_has_many_for' in parent model you can give parent object"
226
- return nil
237
+ raise ArgumentError, """has_many_update don't have data about parent object,
238
+ * maybe you use 'acts_has_many_for' incorrectly,
239
+ * if you don't use 'acts_has_many_for' in parent model you can give parent object"""
227
240
  end
228
241
 
229
242
  new_id, del_id = has_many_update data[0]
230
- parrent = eval(tmp_current_relation.classify).find(tmp_parrent_id)
243
+ parrent = eval(tmp_current_relation.classify).find tmp_parrent_id
231
244
  parrent.update_attributes("#{model.name.foreign_key}" => new_id)
232
245
  parrent.save!
233
246
 
234
247
  destroy unless del_id.nil?
235
248
  model.find new_id
236
249
  end
237
-
250
+
238
251
  #
239
- # +has_many_update+ ( return array) [new_id, del_id]
252
+ # +has_many_update+ ( return array) [new_id, remove_id]
240
253
  # options maybe Hash, or list parameters
241
- # :data( type: hash) - data for updte
242
- # :relation( type: str, symbol) - modifi with tableize (maybe miss)
243
- #
244
-
245
- def has_many_update(*options)
246
- if options.size == 1 && options[0].include?(:data) && options[0].include?(:relation)
247
- data = options[0][:data]
248
- relation = options[0][:relation]
254
+ # data ( type: hash) - data for updte
255
+ # relation( type: str, symbol) - modifi with tableize (maybe miss)
256
+ #
257
+
258
+ def has_many_update *options
259
+ if options.size == 1 && options.first.include?(:data) && options[0].include?(:relation)
260
+ data = options.first[:data]
261
+ relation = options.first[:relation]
262
+ ActiveSupport::Deprecation.warn "Use simple list parameters (data, relation), parameter with 'Hash' type will be romoved in v1.0!"
249
263
  elsif options.size == 2
250
- data = options[0]
264
+ data = options.first
251
265
  relation = options[1]
252
266
  else
253
267
  relation = tmp_current_relation
254
- data = options[0]
268
+ data = options.first
255
269
  end
256
-
257
- data_default = {}
258
- data_default[model.compare] = ""
259
- data = data_default.merge data
270
+
271
+ data = { model.compare => ''}.merge data
260
272
 
261
273
  if relation.blank?
262
- p "Notice: 'has_many_update' don't know about current relation, and check all relations"
274
+ warn "[ARRGUMENT MISSING]: 'has_many_update' don't know about current relation, and check all relations"
263
275
  end
264
-
276
+
265
277
  has_many_cleaner data.symbolize_keys, relation
266
278
  end
267
-
279
+
268
280
  #
269
281
  # +actuale?+ - check the acutuality of element in has_many table
270
- # options maybe Hash, or simple parameter
271
- # :relation( string, symbol) - exclude current relation (maybe miss)
282
+ # options:
283
+ # relation (String, Symbol) - for exclude current relation
272
284
  #
273
-
274
- def actuale? (options={relation: ""})
275
- if options.is_a? Hash and options.include? :relation
276
- relation = options[:relation].to_s.tableize
285
+
286
+ def actuale? opt={relation: ""}
287
+ if opt.is_a? Hash
288
+ opt.assert_valid_keys :relation
289
+ ActiveSupport::Deprecation.warn "Use simple parameter 'String' or 'Symbol', parameter with 'Hash' type will be romoved in v1.0!"
290
+ relation = opt[:relation].to_s.tableize
277
291
  else
278
- relation = options.to_s.tableize
292
+ relation = opt.to_s.tableize
279
293
  end
280
294
 
281
295
  actuale = false
282
296
  model.dependent_relations.each do |dependent_relation|
283
- tmp = self.send(dependent_relation)
297
+ tmp = self.send dependent_relation
284
298
  if relation == dependent_relation
285
299
  actuale ||= tmp.all.size > 1
286
300
  else
@@ -290,9 +304,9 @@ module ActiveRecord
290
304
  actuale
291
305
  end
292
306
  end
293
-
307
+
294
308
  private
295
-
309
+
296
310
  #
297
311
  # +destroy_filter+ - method for before_destroy, check actuale record and
298
312
  # return true for delete or false for leave
@@ -302,22 +316,22 @@ module ActiveRecord
302
316
  not actuale?
303
317
  end
304
318
 
305
- #
319
+ #
306
320
  # base operations in this gem
307
321
  #
308
322
 
309
- def has_many_cleaner(data, relation)
323
+ def has_many_cleaner data, relation
310
324
  compare = { model.compare => data[model.compare] }
311
-
325
+
312
326
  object_id = id
313
327
  delete_id = nil
314
-
328
+
315
329
  if actuale? relation
316
330
  # create new object and finish
317
- object = model.where(compare).first_or_create(data)
331
+ object = model.where(compare).first_or_create data
318
332
  object_id = object.id
319
333
  else
320
- object_tmp = model.where(compare)[0]
334
+ object_tmp = model.where(compare).first
321
335
  unless object_tmp.nil?
322
336
  # set new object and delete old
323
337
  delete_id = (object_id == object_tmp.id) ? nil : object_id
@@ -325,14 +339,14 @@ module ActiveRecord
325
339
  else
326
340
  # update old object
327
341
  if object_id.nil?
328
- object = model.where(compare).first_or_create(data)
342
+ object = model.where(compare).first_or_create data
329
343
  object_id = object.id
330
344
  else
331
345
  if data[model.compare].blank?
332
346
  delete_id = object_id
333
347
  object_id = nil
334
348
  else
335
- update_attributes(data)
349
+ update_attributes data
336
350
  end
337
351
  end
338
352
  end
@@ -1,3 +1,3 @@
1
1
  module ActsHasMany
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_has_many
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-29 00:00:00.000000000 Z
12
+ date: 2012-10-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -113,9 +113,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
113
  version: '0'
114
114
  requirements: []
115
115
  rubyforge_project:
116
- rubygems_version: 1.8.19
116
+ rubygems_version: 1.8.24
117
117
  signing_key:
118
118
  specification_version: 3
119
119
  summary: All records must be used, otherwise they will be deleted. Clear logic with
120
120
  has_many
121
- test_files: []
121
+ test_files:
122
+ - spec/has_many_spec.rb
123
+ - spec/has_many_through_spec.rb
124
+ - spec/helper.rb