quickery 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06ee53003d29d3dfa2bf9cd981c5d6f154bb49a8a07538d846acff0b30adb52d
4
- data.tar.gz: 2bf0d7a7e35f9d46ec2fabeacd11f36479f4165c1110b8e75d3336e91329d5f9
3
+ metadata.gz: 5caca192d074a8aa71dd2c6e9bc06a3051b6f7eaec2bc664618af356d41a250d
4
+ data.tar.gz: 9acfccf220d83aa4c0d521ba13b4040241273d513160a7e2c4b4afccdb32de8a
5
5
  SHA512:
6
- metadata.gz: 290d4b4ba0ee7b2f239619231c07ceb848a79d3b858b0b03287644459a67ed5ae826e426b6b291debee23afecaca4221434df1c21fda53bb8d662791f8afda0e
7
- data.tar.gz: 1c3b3f6b7817550bf272e342b88c70964ff8955f9bc73fe81e6c234f0036c19d4ed8278cf6b0ec45346d8dee010842060b51d3e17c8593a753ffb6943dc1fc35
6
+ metadata.gz: 3839d48b10faac8d58778c4373440496781a3c52765478b510b1918441fda4aae743097e65ec4a0841fad599f3dfea3b8279062eb406e4a2a0dd0272885774d5
7
+ data.tar.gz: 29cb2b61d408b61eee767267dce79538aa8039e1de9f85e111f62bb330ad1b395d7c810f4ae2e0065ef1ac37f70094c3e0f564ddda97cf46dde5921432cad066
data/README.md CHANGED
@@ -184,6 +184,168 @@ class Employee < ApplicationRecord
184
184
  end
185
185
  ```
186
186
 
187
+ ## Advanced Usage
188
+
189
+ Quickery defines the following for `ActiveRecord::Base` of which you can optionally override in any of your models for advanced usage, i.e:
190
+
191
+ ```ruby
192
+ class Employee < ApplicationRecord
193
+ belongs_to :branch
194
+
195
+ quickery branch: { company: { name: :branch_company_name } }
196
+
197
+ # this method will be called before an Employee gets created or updated
198
+ # new_values is a Hash of quickery-defined attribute changes; say: `{ :branch_company_name => 'Jollibee' }`
199
+ # i.e. when some_employee.update(branch: some_branch)
200
+ def self.quickery_before_create_or_update(employee, new_values)
201
+ employee.assign_attributes(new_values) # default behaviour of this method
202
+ end
203
+
204
+ # this method will be called before any updates happen on any of the association (that a quickery-defined attribute in this model depends on)
205
+ # i.e. when some_branch.update(company: some_company)
206
+ # i.e. when some_company.update(name: 'New Company Name')
207
+ def self.quickery_before_association_update(employees, record_to_be_updated, new_values)
208
+ employees.update_all(new_values) # default behaviour of this method
209
+ end
210
+
211
+ # this method will be called before any of the association gets destroyed (that a quickery-defined attribute in this model depends on)
212
+ # i.e. when some_branch.destroy
213
+ # i.e. when some_company.destroy
214
+ def self.quickery_before_association_destroy(employees, record_to_be_destroyed, new_values)
215
+ employees.update_all(new_values) # default behaviour of this method
216
+ end
217
+ end
218
+ ```
219
+
220
+ ### Advanced Usage: Background Job
221
+
222
+ ```ruby
223
+ class Employee < ApplicationRecord
224
+ belongs_to :branch
225
+
226
+ quickery branch: { company: { name: :branch_company_name } }
227
+
228
+ def self.quickery_before_create_or_update(employee, new_values)
229
+ employee.assign_attributes(new_values)
230
+ end
231
+
232
+ # because updates can be slow for a very big DB table, then you can move the update logic into a background job
233
+ # you can even batch the updates into a job like below
234
+
235
+ def self.quickery_before_association_update(employees, record_to_be_updated, new_values)
236
+ employees.find_in_batches(batch_size: 2000) do |grouped_employees|
237
+ BatchQuickeryUpdatesJob.perform_later(self.class.to_s, grouped_employees.pluck(:id), new_values)
238
+ end
239
+ end
240
+
241
+ def self.quickery_before_association_destroy(employees, record_to_be_destroyed, new_values)
242
+ employees.find_in_batches(batch_size: 2000) do |grouped_employees|
243
+ BatchQuickeryUpdatesJob.perform_later(self.class.to_s, grouped_employees.pluck(:id), new_values)
244
+ end
245
+ end
246
+ end
247
+
248
+ # app/jobs/batch_quickery_updates_job.rb
249
+ class BatchQuickeryUpdatesJob < ApplicationJob
250
+ # or probably you have a :low_priority queue?
251
+ queue_as :default
252
+
253
+ def perform(model_str, ids, new_values)
254
+ model = model_str.safe_constantize
255
+ model.where(id: ids).update_all(new_values)
256
+ end
257
+ end
258
+ ```
259
+
260
+ ### Advanced Usage: Formatting Values
261
+
262
+ ```ruby
263
+ class Employee < ApplicationRecord
264
+ belongs_to :branch
265
+
266
+ quickery branch: { company: { name: :branch_company_name } }
267
+
268
+ def self.quickery_before_create_or_update(employee, new_values)
269
+ employee.assign_attributes(quickery_format_values(new_values))
270
+ end
271
+
272
+ def self.quickery_before_association_update(employees, record_to_be_updated, new_values)
273
+ employees.update_all(quickery_format_values(new_values))
274
+ end
275
+
276
+ def self.quickery_before_association_destroy(employees, record_to_be_destroyed, new_values)
277
+ employees.update_all(quickery_format_values(new_values))
278
+ end
279
+
280
+ private
281
+
282
+ # example (you can rename this method):
283
+ def self.quickery_format_values(values)
284
+ formatted_values = {}
285
+
286
+ :branch_company_name.tap do |attr|
287
+ # remove trailing white spaces and force-single-space between words, and then capitalise all characters
288
+ formatted_values[attr] = values[attr].squish.upcase if values.has_key? attr
289
+ end
290
+
291
+ :user_first_name.tap do |attr|
292
+ # only save the first 30 characters of user_first_name string
293
+ formatted_values[attr] = values[attr][0...30] if values.has_key? attr
294
+ end
295
+
296
+ formatted_values
297
+ end
298
+ end
299
+ ```
300
+
301
+ ### Advanced Usage: Computed Attributes / Values
302
+
303
+ ```ruby
304
+ class Employee < ApplicationRecord
305
+ belongs_to :branch
306
+
307
+ quickery branch: { company: { name: :branch_company_name } }
308
+
309
+ def self.quickery_before_create_or_update(employee, new_values)
310
+ employee.assign_attributes(quickery_with_computed_values(employee, new_values))
311
+ end
312
+
313
+ def self.quickery_before_association_update(employees, record_to_be_updated, new_values)
314
+ employee.find_each do |employee|
315
+ employee.update!(quickery_with_computed_values(employee, new_values))
316
+ end
317
+ end
318
+
319
+ def self.quickery_before_association_destroy(employees, record_to_be_destroyed, new_values)
320
+ employee.find_each do |employee|
321
+ employee.update!(quickery_with_computed_values(employee, new_values))
322
+ end
323
+ end
324
+
325
+ private
326
+
327
+ # example (you can rename this method):
328
+ def self.quickery_with_computed_values(employee, values)
329
+ with_computed_values = {}
330
+
331
+ if values.has_key?(:user_first_name) || values.has_key?(:user_last_name)
332
+ # concatenate first name and last name
333
+ with_computed_values[:user_full_name] = "#{values[:user_first_name]} #{values[:user_last_name]}".strip
334
+ end
335
+
336
+ # you can add logic that specifically depends on the record like the following:
337
+ if employee.is_current_employee?
338
+ if values.has_key? :branch_company_name
339
+ # concatenate a unique code for the employee: i.e. a value of "11-5-1239"
340
+ with_computed_values[:unique_codename] = "#{employee.branch.company.id}-#{employee.branch.id}-#{employee.id}"
341
+ end
342
+ end
343
+
344
+ with_computed_values
345
+ end
346
+ end
347
+ ```
348
+
187
349
  ## Gotchas
188
350
  * Quickery makes use of Rails model callbacks such as `before_update`. This meant that data-integrity holds unless `update_columns` or `update_column` is used which bypasses model callbacks, or unless any manual SQL update is performed.
189
351
  * Quickery does not automatically update old records existing in the database that were created before you integrate Quickery, or before you add new/more Quickery-attributes for that model. One solution is [`recreate_quickery_cache!`](#recreate_quickery_cache) below.
@@ -194,6 +356,8 @@ end
194
356
 
195
357
  * defines a set of "hidden" Quickery `before_create`, `before_update`, and `before_destroy` callbacks needed by Quickery to perform the "syncing" of attribute values
196
358
 
359
+ * can override `self.quickery_before_create_or_update`, `self.quickery_before_association_update`, `self.quickery_before_association_destroy` for advanced usage such as moving the update logic into a background job, or formatting of the quickery-defined attributes, etc...
360
+
197
361
  #### Class Methods:
198
362
 
199
363
  ##### `quickery(mappings)`
@@ -248,7 +412,6 @@ end
248
412
  * Possibly support two-way mapping of attributes? So that you can do, say... `employee.update!(branch_company_name: 'somenewcompanyname')`
249
413
  * Support `has_many` as currently only `belongs_to` is supported. This would then allow us to cache Array of values.
250
414
  * Support custom-methods-values like [`persistize`](https://github.com/bebanjo/persistize), if it's easy enough to integrate something similar
251
- * Support background-processing like in [`flattery`](https://github.com/evendis/flattery)
252
415
 
253
416
  ## Other Similar Gems
254
417
  See [my detailed comparisons](other_similar_gems_comparison.md)
@@ -273,6 +436,8 @@ See [my detailed comparisons](other_similar_gems_comparison.md)
273
436
  5. Create new Pull Request
274
437
 
275
438
  ## Changelog
439
+ * 1.2.0
440
+ * DONE: (TODO) added overrideable methods for custom callback logic (i.e. move update logic instead into a background job)
276
441
  * 1.1.0
277
442
  * added helper method [`determine_quickery_values`](#determine_quickery_values)
278
443
  * fixed `recreate_quickery_cache!` raising `NilClass` error when the immediate association is nil
@@ -3,5 +3,4 @@ Dir[__dir__ + '/quickery/active_record_extensions/*.rb'].each {|file| require fi
3
3
  Dir[__dir__ + '/quickery/errors/*.rb'].each {|file| require file }
4
4
 
5
5
  module Quickery
6
- # Your code goes here...
7
6
  end
@@ -24,6 +24,8 @@ module Quickery
24
24
  changed_attributes = changes.keys
25
25
 
26
26
  if model.quickery_association_chain_dependers.present?
27
+ new_values = {}.with_indifferent_access
28
+
27
29
  model.quickery_association_chain_dependers.each do |association_chain_depender|
28
30
  quickery_builder = association_chain_depender.quickery_builder
29
31
  depender_column_name = quickery_builder.depender_column_name
@@ -37,9 +39,11 @@ module Quickery
37
39
  new_value = dependee_record.send(dependee_column_name)
38
40
  end
39
41
 
40
- assign_attributes(depender_column_name => new_value)
42
+ new_values[depender_column_name] = new_value
41
43
  end
42
44
  end
45
+
46
+ self.class.quickery_before_create_or_update(self, new_values)
43
47
  end
44
48
  end
45
49
 
@@ -48,6 +52,8 @@ module Quickery
48
52
  changed_attributes = changes.keys
49
53
 
50
54
  if model.quickery_association_chain_dependers.present?
55
+ new_values = {}.with_indifferent_access
56
+
51
57
  model.quickery_association_chain_dependers.each do |association_chain_depender|
52
58
  quickery_builder = association_chain_depender.quickery_builder
53
59
  depender_column_name = quickery_builder.depender_column_name
@@ -61,12 +67,14 @@ module Quickery
61
67
  new_value = dependee_record.send(dependee_column_name)
62
68
  end
63
69
 
64
- assign_attributes(depender_column_name => new_value)
70
+ new_values[depender_column_name] = new_value
65
71
  end
66
72
  end
73
+
74
+ self.class.quickery_before_create_or_update(self, new_values)
67
75
  end
68
76
 
69
- dependent_records_attributes_to_be_updated = {}
77
+ dependent_records_attributes_to_be_updated = {}.with_indifferent_access
70
78
 
71
79
  if model.quickery_association_chain_dependees.present?
72
80
  model.quickery_association_chain_dependees.each do |association_chain_dependee|
@@ -79,9 +87,9 @@ module Quickery
79
87
 
80
88
  dependent_records = association_chain_dependee.dependent_records(self)
81
89
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
82
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}
90
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
83
91
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
84
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}
92
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
85
93
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
86
94
  end
87
95
  end
@@ -103,9 +111,9 @@ module Quickery
103
111
 
104
112
  dependent_records = association_chain_intermediary.dependent_records(self)
105
113
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
106
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}
114
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
107
115
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
108
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}
116
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
109
117
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
110
118
  end
111
119
  end
@@ -115,14 +123,14 @@ module Quickery
115
123
  dependent_records = hash.fetch(:dependent_records)
116
124
  new_values = hash.fetch(:new_values)
117
125
 
118
- dependent_records.update_all(new_values)
126
+ dependent_records.model.quickery_before_association_update(dependent_records, self, new_values)
119
127
  end
120
128
  end
121
129
 
122
130
  def quickery_before_destroy_callback
123
131
  model = self.class
124
132
 
125
- dependent_records_attributes_to_be_updated = {}
133
+ dependent_records_attributes_to_be_updated = {}.with_indifferent_access
126
134
 
127
135
  if model.quickery_association_chain_dependees.present?
128
136
  model.quickery_association_chain_dependees.each do |association_chain_dependee|
@@ -135,9 +143,9 @@ module Quickery
135
143
 
136
144
  dependent_records = association_chain_dependee.dependent_records(self)
137
145
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
138
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}
146
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
139
147
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
140
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}
148
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
141
149
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
142
150
  end
143
151
  end
@@ -154,9 +162,9 @@ module Quickery
154
162
 
155
163
  dependent_records = association_chain_intermediary.dependent_records(self)
156
164
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
157
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}
165
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
158
166
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
159
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}
167
+ dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
160
168
  dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
161
169
  end
162
170
  end
@@ -166,7 +174,7 @@ module Quickery
166
174
  dependent_records = hash.fetch(:dependent_records)
167
175
  new_values = hash.fetch(:new_values)
168
176
 
169
- dependent_records.update_all(new_values)
177
+ dependent_records.model.quickery_before_association_destroy(dependent_records, self, new_values)
170
178
  end
171
179
  end
172
180
  end
@@ -18,6 +18,21 @@ module Quickery
18
18
  mappings_builder = MappingsBuilder.new(model: self, mappings: mappings.with_indifferent_access)
19
19
  mappings_builder.map_attributes
20
20
  end
21
+
22
+ # subclass overrideable
23
+ def quickery_before_create_or_update(dependent_record, new_values)
24
+ dependent_record.assign_attributes(new_values)
25
+ end
26
+
27
+ # subclass overrideable
28
+ def quickery_before_association_update(dependent_records, record_to_be_updated, new_values)
29
+ dependent_records.update_all(new_values)
30
+ end
31
+
32
+ # subclass overrideable
33
+ def quickery_before_association_destroy(dependent_records, record_to_be_destroyed, new_values)
34
+ dependent_records.update_all(new_values)
35
+ end
21
36
  end
22
37
 
23
38
  module InstanceMethods
@@ -1,3 +1,3 @@
1
1
  module Quickery
2
- VERSION = '1.1.0'
2
+ VERSION = '1.2.0'
3
3
  end
@@ -109,9 +109,6 @@
109
109
  * Rails 4 seems to be also not supported. I was getting `ArgumentError (wrong number of arguments (given 1, expected 0))` when doing `User.create` inside rails console.
110
110
 
111
111
  * [flattery v0.1.0](https://github.com/evendis/flattery) :
112
- * Pros against Quickery:
113
- * allows custom update method
114
- * allows "updates" as a background process
115
112
  * Cons against Quickery:
116
113
  * Rails 5 is not part of its supported list in their github page. And just to try it out on a Rails 5 app, `Flattery::ValueProvider` did not seem to work, because values are not pushed to the `:notes`'s `:category_name` values.
117
114
  * batch-update in one go for multiple quickery-defined attributes instead of updating each
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quickery
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jules Roman Polidario
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-13 00:00:00.000000000 Z
11
+ date: 2018-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties