acts_has_many 0.1.4 → 0.1.5
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/README.md +4 -6
- data/lib/acts_has_many/active_record/acts/has_many.rb +115 -101
- data/lib/acts_has_many/version.rb +1 -1
- metadata +7 -4
data/README.md
CHANGED
@@ -33,13 +33,13 @@ end
|
|
33
33
|
# OR
|
34
34
|
|
35
35
|
class Company < ActiveRecord::Base
|
36
|
-
acts_has_many
|
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
|
-
#
|
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(
|
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
|
26
|
-
base.extend
|
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
|
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
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
-
|
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
|
124
|
-
|
132
|
+
.map(&:name) if options[:relations].blank?
|
133
|
+
|
134
|
+
dependent_relations = []
|
125
135
|
options[:relations].each do |relation|
|
126
|
-
|
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
|
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
|
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!
|
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
|
-
|
224
|
-
|
225
|
-
|
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
|
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,
|
252
|
+
# +has_many_update+ ( return array) [new_id, remove_id]
|
240
253
|
# options maybe Hash, or list parameters
|
241
|
-
#
|
242
|
-
#
|
243
|
-
#
|
244
|
-
|
245
|
-
def has_many_update
|
246
|
-
if options.size == 1 && options
|
247
|
-
data = options[
|
248
|
-
relation = options[
|
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
|
264
|
+
data = options.first
|
251
265
|
relation = options[1]
|
252
266
|
else
|
253
267
|
relation = tmp_current_relation
|
254
|
-
data = options
|
268
|
+
data = options.first
|
255
269
|
end
|
256
|
-
|
257
|
-
|
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
|
-
|
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
|
271
|
-
#
|
282
|
+
# options:
|
283
|
+
# relation (String, Symbol) - for exclude current relation
|
272
284
|
#
|
273
|
-
|
274
|
-
def actuale?
|
275
|
-
if
|
276
|
-
|
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 =
|
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
|
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
|
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
|
331
|
+
object = model.where(compare).first_or_create data
|
318
332
|
object_id = object.id
|
319
333
|
else
|
320
|
-
object_tmp = model.where(compare)
|
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
|
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
|
349
|
+
update_attributes data
|
336
350
|
end
|
337
351
|
end
|
338
352
|
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
|
+
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-
|
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.
|
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
|