quickery 1.2.0 → 1.3.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: 5caca192d074a8aa71dd2c6e9bc06a3051b6f7eaec2bc664618af356d41a250d
4
- data.tar.gz: 9acfccf220d83aa4c0d521ba13b4040241273d513160a7e2c4b4afccdb32de8a
3
+ metadata.gz: ef98d8559e4364a5532777fc264d895dab630d914475bf663978798f5fce932c
4
+ data.tar.gz: ab4eda789c789b451d68a7839e508aef9a4178c039c250207a79d85e09b97ccf
5
5
  SHA512:
6
- metadata.gz: 3839d48b10faac8d58778c4373440496781a3c52765478b510b1918441fda4aae743097e65ec4a0841fad599f3dfea3b8279062eb406e4a2a0dd0272885774d5
7
- data.tar.gz: 29cb2b61d408b61eee767267dce79538aa8039e1de9f85e111f62bb330ad1b395d7c810f4ae2e0065ef1ac37f70094c3e0f564ddda97cf46dde5921432cad066
6
+ metadata.gz: 62d2462169148384f2bdd6675bfbbc70a0fc5908b63be6c0e14726f75ac678c083e8c9fa8621f4decb857074d130724c9e7ff7b417f0d5e32e2f92a815ee33e5
7
+ data.tar.gz: 57f167d27cf38b2b4e1753f3ec6fbf81843d6f67e452310041f16acf63daba26ca9202ccc64bda393cca3e1ea30f3acbe6da57ec6b1a6e46b7cb7eedbcd7d1ba
data/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
  bundle install
27
27
  ```
28
28
 
29
- ## Usage Example 1
29
+ ## Usage Example 1 - Mapped Attribute
30
30
 
31
31
  ```ruby
32
32
  # app/models/employee.rb
@@ -63,7 +63,8 @@ end
63
63
 
64
64
  ```bash
65
65
  # bash
66
- rails generate migration add_branch_company_name_to_employees branch_company_name:string
66
+ rails generate quickery:migration employee branch_company_name:string
67
+ # or: rails generate migration add_branch_company_name_to_employees branch_company_name:string
67
68
  bundle exec rake db:migrate
68
69
  ```
69
70
 
@@ -100,7 +101,10 @@ puts employee.branch_company_name
100
101
  # => 'McDonalds'
101
102
  ```
102
103
 
103
- If you already have "old" records before you've integrated quickery or if you have new quickery-defined attributes, you can update these stale records by using `recreate_quickery_cache!`. See example below:
104
+ If you already have "old" records before you've integrated quickery or if you have new quickery-defined attributes, you can update these stale records...
105
+
106
+ 1. by using `autoload_unsynced_quickery_attributes!` (see Usage Example 3 below), or...
107
+ 2. by using `recreate_quickery_cache!`. See example below:
104
108
 
105
109
  ```ruby
106
110
  # rails console
@@ -109,9 +113,9 @@ Employee.find_each do |employee|
109
113
  end
110
114
  ```
111
115
 
112
- ## Usage Example 2
116
+ ## Usage Example 2 - Association via Mapped Attribute
113
117
 
114
- * let `Branch` and `Company` model be the same as the Usage Example 1 above
118
+ * let `Branch` and `Company` models be the same as the Usage Example 1 above
115
119
 
116
120
  ```ruby
117
121
  # app/models/employee.rb
@@ -125,7 +129,8 @@ end
125
129
 
126
130
  ```bash
127
131
  # bash
128
- rails generate migration add_branch_company_id_to_employees branch_company_id:bigint:index
132
+ rails generate quickery:migration employee branch_company_id:bigint:index
133
+ # or: rails generate migration add_branch_company_id_to_employees branch_company_id:bigint:index
129
134
  bundle exec rake db:migrate
130
135
  ```
131
136
 
@@ -150,6 +155,54 @@ puts Employee.joins(branch: :company).where(companies: { id: company.id })
150
155
  # => [#<Employee id: 1>]
151
156
  ```
152
157
 
158
+ ## Usage Example 3 - Autoloading Quickery Attributes
159
+
160
+ > `autoload_unsynced_quickery_attributes!` below is **ONLY** compatible with optional `*_is_synced` attributes, which can be done by passing `--add_is_synced_attributes` to the `quickery:migration` generator. See example below.
161
+
162
+ * let `Branch` and `Company` models be the same as the Usage Example 1 above
163
+
164
+ ```ruby
165
+ # app/models/employee.rb
166
+ class Employee < ApplicationRecord
167
+ belongs_to :branch
168
+
169
+ quickery { branch: { company: { id: :branch_company_name } } }
170
+
171
+ after_find :autoload_unsynced_quickery_attributes!
172
+ end
173
+ ```
174
+
175
+ ```bash
176
+ # bash
177
+ rails generate quickery:migration employee branch_company_name:string --add_is_synced_attributes
178
+ bundle exec rake db:migrate
179
+ ```
180
+
181
+ ```ruby
182
+ # rails console
183
+ company = Company.create!(name: 'Jollibee')
184
+ branch = Branch.create!(company: company)
185
+ employee_created_before_quickery_integration = Employee.create!(branch: branch)
186
+
187
+ puts employee_created_before_quickery_integration.branch_company_name
188
+ # => NoMethodError: undefined method `branch_company_name'
189
+
190
+ # Let's say the employee record above was created long time ago before Quickery was integrated,
191
+ # and then right now, you added the new quickery-attribute `branch_company_name`.
192
+
193
+ # Employee record above now then will have "stale" value for `branch_company_name`,
194
+ # because it will have a value of `nil`.
195
+ # But using `after_find :autoload_unsynced_quickery_attributes!` above, all records will
196
+ # then be guaranteed to have up-to-date quickery attributes even if new quickery-attributes
197
+ # will be defined in the future.
198
+
199
+ puts employee_created_before_quickery_integration.branch_company_name
200
+ # => 'Employee'
201
+
202
+ # if without `after_find :autoload_unsynced_quickery_attributes!`, the puts just above will instead show
203
+ # => nil
204
+ ```
205
+
153
206
  ## Other Usage Examples
154
207
 
155
208
  ```ruby
@@ -281,19 +334,17 @@ class Employee < ApplicationRecord
281
334
 
282
335
  # example (you can rename this method):
283
336
  def self.quickery_format_values(values)
284
- formatted_values = {}
285
-
286
337
  :branch_company_name.tap do |attr|
287
338
  # 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
339
+ values[attr] = values[attr].squish.upcase if values.has_key? attr
289
340
  end
290
341
 
291
342
  :user_first_name.tap do |attr|
292
343
  # only save the first 30 characters of user_first_name string
293
- formatted_values[attr] = values[attr][0...30] if values.has_key? attr
344
+ values[attr] = values[attr][0...30] if values.has_key? attr
294
345
  end
295
346
 
296
- formatted_values
347
+ values
297
348
  end
298
349
  end
299
350
  ```
@@ -310,6 +361,8 @@ class Employee < ApplicationRecord
310
361
  employee.assign_attributes(quickery_with_computed_values(employee, new_values))
311
362
  end
312
363
 
364
+ # IMPORTANT: for big tables, `find_each` below can be slow (consider moving into a background job or if possible use the default behaviour which is `update_all`)
365
+
313
366
  def self.quickery_before_association_update(employees, record_to_be_updated, new_values)
314
367
  employee.find_each do |employee|
315
368
  employee.update!(quickery_with_computed_values(employee, new_values))
@@ -326,22 +379,22 @@ class Employee < ApplicationRecord
326
379
 
327
380
  # example (you can rename this method):
328
381
  def self.quickery_with_computed_values(employee, values)
329
- with_computed_values = {}
330
-
331
382
  if values.has_key?(:user_first_name) || values.has_key?(:user_last_name)
383
+ employee.user_first_name = values[:user_first_name] if values.has_key?(:user_first_name)
384
+ employee.user_last_name = values[:user_last_name] if values.has_key?(:user_last_name)
332
385
  # concatenate first name and last name
333
- with_computed_values[:user_full_name] = "#{values[:user_first_name]} #{values[:user_last_name]}".strip
386
+ values[:user_full_name] = "#{employee.user_first_name} #{employee.user_last_name}".strip
334
387
  end
335
388
 
336
389
  # you can add logic that specifically depends on the record like the following:
337
390
  if employee.is_current_employee?
338
- if values.has_key? :branch_company_name
391
+ if values.has_key? :branch_company_id
339
392
  # 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}"
393
+ values[:unique_codename] = "#{employee.branch.company.id}-#{employee.branch.id}-#{employee.id}"
341
394
  end
342
395
  end
343
396
 
344
- with_computed_values
397
+ values
345
398
  end
346
399
  end
347
400
  ```
@@ -352,6 +405,56 @@ end
352
405
 
353
406
  ## DSL
354
407
 
408
+ ### Quickery Migration Generator:
409
+
410
+ `rails generate quickery:migration ...` acts as if you are doing a `rails generate model ...` except that it's ONLY going to generate a migration file, therefore:
411
+
412
+ * Usage format: `rails generate quickery:migration model_name attribute_name_1:type attribute_name_2:type ...`
413
+ * Optional `--add_is_synced_attributes` can be passed to the command to support "autoloading". See Usage Example 3 above.
414
+
415
+ #### Example 1
416
+ ```
417
+ rails generate quickery:migration employee branch_company_name:string branch_company_id:bigint:index
418
+ ```
419
+
420
+ ...will generate:
421
+
422
+ ```
423
+ # db/migrate/TIMESTAMP_add_quickery_branch_company_name_branch_company_id_to_employees.rb
424
+ class AddQuickeryBranchCompanyNameBranchCompanyIdToEmployees < ActiveRecord::Migration[5.2]
425
+ def change
426
+ change_table :employees do |t|
427
+ t.string :branch_company_name
428
+ t.integer :branch_company_id
429
+ end
430
+ add_index :employees, :branch_company_id
431
+ end
432
+ end
433
+ ```
434
+
435
+ #### Example 2
436
+
437
+ ```
438
+ rails generate quickery:migration employee branch_company_name:string branch_company_id:bigint:index --add_is_synced_attributes
439
+ ```
440
+
441
+ ...will generate:
442
+
443
+ ```
444
+ # db/migrate/TIMESTAMP_add_quickery_branch_company_name_branch_company_id_to_employees.rb
445
+ class AddQuickeryBranchCompanyNameBranchCompanyIdToEmployees < ActiveRecord::Migration[5.2]
446
+ def change
447
+ change_table :employees do |t|
448
+ t.string :branch_company_name
449
+ t.boolean :branch_company_name_is_synced, null: false, default: false
450
+ t.integer :branch_company_id
451
+ t.boolean :branch_company_id_is_synced, null: false, default: false
452
+ end
453
+ add_index :employees, :branch_company_id
454
+ end
455
+ end
456
+ ```
457
+
355
458
  ### For any subclass of `ActiveRecord::Base`:
356
459
 
357
460
  * defines a set of "hidden" Quickery `before_create`, `before_update`, and `before_destroy` callbacks needed by Quickery to perform the "syncing" of attribute values
@@ -362,17 +465,17 @@ end
362
465
 
363
466
  ##### `quickery(mappings)`
364
467
  * mappings (Hash)
365
- * each mapping will create a `Quickery::QuickeryBuilder` object. i.e:
468
+ * each mapping will create a `Quickery::QuickeryBuilder` object. i.e:s
366
469
  * `{ branch: { name: :branch_name }` will create one `Quickery::QuickeryBuilder`, while
367
470
  * `{ branch: { name: :branch_name, id: :branch_id }` will create two `Quickery::QuickeryBuilder`
368
471
  * In this particular example, you are required to specify `belongs_to :branch` in this model
369
- * Similarly, you are required to specify `belongs_to :company` inside `Branch` model, `belongs_to :country` inside `Company` model; etc...
370
- * quickery-defined attributes such as say `:branch_company_country_category_name` are updated by Quickery automatically whenever any of it's dependent records across models have been changed. Note that updates in this way do not trigger model callbacks, as I wanted to isolate logic and scope of Quickery by not triggering model callbacks that you already have.
472
+ * Similarly, depending on your defined mappings, i.e. `{ branch: { company: { country: { name: :branch_company_country_name } } } }`, you would be required to specify `belongs_to :company` inside `Branch` model, `belongs_to :country` inside `Company` model; etc...
473
+ * quickery-defined attributes such as say `:branch_company_country_category_name` are updated by Quickery automatically whenever any of it's dependent records / dependee-attribute across models have been changed or destroyed. Note that updates in this way do not trigger model callbacks, unless you manually overrode the quickery model methods: `self.quickery_before_association_update` or `self.quickery_before_association_destroy`, and changed the default behaviour to no longer use `update_all`. I use `update_all` by default to improve speed and to bypass validations because attributes that will be updated are just your quickery-defined attributes anyway, and chances are you would not want any validations for these attributes.
371
474
  * quickery-defined attributes such as say `:branch_company_country_category_name` are READ-only! Do not update these attributes manually. You can, but it will not automatically update the other end, and thus will break data integrity. If you want to re-update these attributes to match the other end, see `recreate_quickery_cache!` below.
372
475
 
373
476
  ##### `quickery_builders`
374
477
  * returns an `Array` of `Quickery::QuickeryBuilder` objects that have already been defined
375
- * for more info, see `quickery(&block)` above
478
+ * for more info, see `quickery(mappings)` above
376
479
  * you normally do not need to use this method
377
480
 
378
481
  #### Instance Methods:
@@ -408,10 +511,34 @@ end
408
511
  # => { branch_company_country_id: 1, branch_compnay_country_name: 'Ireland' }
409
512
  ```
410
513
 
514
+ ##### `autoload_unsynced_quickery_attributes!`
515
+ * only works in conjuction with `*_is_synced` attributes.
516
+ * this will update the record's "still unsynced" quickery-attributes.
517
+ * if all of the record's quickery-attributes are already "synced", then this method does nothing more
518
+ * intended to be used as callback method for `after_find` to automatically support both 1) "old-records" that before quickery has been integrated, and 2) new quickery-attributes to be defined in the future
519
+ * i.e. you can do something like the following:
520
+
521
+ ```ruby
522
+ class Employee < ApplicationRecord
523
+ belongs_to :branch
524
+ quickery branch: { company: { name: :branch_company_name } }
525
+ after_find :autoload_unsynced_quickery_attributes!
526
+ end
527
+
528
+ an_employee_long_time_ago_before_quickery_was_even_integrated = Employee.first
529
+
530
+ puts an_employee_long_time_ago_before_quickery_was_even_integrated.branch_company_name
531
+ # => 'Jollibee'
532
+
533
+ # otherwise, if there is no `after_find :autoload_unsynced_quickery_attributes!`, the `puts` above will instead return
534
+ # => nil
535
+ ```
536
+
411
537
  ## TODOs
412
538
  * Possibly support two-way mapping of attributes? So that you can do, say... `employee.update!(branch_company_name: 'somenewcompanyname')`
413
539
  * Support `has_many` as currently only `belongs_to` is supported. This would then allow us to cache Array of values.
414
540
  * Support custom-methods-values like [`persistize`](https://github.com/bebanjo/persistize), if it's easy enough to integrate something similar
541
+ * Provide a better DSL for "Computed Values" and also probably "Formatted Values" as the current example above, though flexible, looks like it has too much code and the method can potentially grow very big; probably separate into a defined method per computed/formatted value?
415
542
 
416
543
  ## Other Similar Gems
417
544
  See [my detailed comparisons](other_similar_gems_comparison.md)
@@ -436,6 +563,8 @@ See [my detailed comparisons](other_similar_gems_comparison.md)
436
563
  5. Create new Pull Request
437
564
 
438
565
  ## Changelog
566
+ * 1.3.0
567
+ * implemented tracking of which quickery-attributes have already been synced / not yet via additional optional `*_is_synced` attributes; used in conjuction with [`autoload_unsynced_quickery_attributes!`](#autoload_unsynced_quickery_attributes) intentionally to be declared as callback method for `after_find`, which will make sure that new quickery-attributes defined in the future will work immediately for the record, and that the developer won't worry about doing the `recreate_quickery_cache!` anymore, as the record is guaranteed to be always up-to-date.
439
568
  * 1.2.0
440
569
  * DONE: (TODO) added overrideable methods for custom callback logic (i.e. move update logic instead into a background job)
441
570
  * 1.1.0
@@ -0,0 +1,44 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module Quickery
4
+ module Generators
5
+ class MigrationGenerator < ActiveRecord::Generators::Base
6
+ desc 'Generate migration for quickery attributes'
7
+ source_root File.expand_path('../templates', __FILE__)
8
+
9
+ argument :attributes, required: true, type: :array, desc: 'The quickery-attributes',
10
+ banner: 'company_name:string company_country_id:integer company_country_name:string ...'
11
+
12
+ class_option :add_is_synced_attributes, desc: 'Add extra `*_is_synced` attribute per quickery-attribute', default: nil
13
+
14
+ def generate_migration
15
+ migration_template("migration.rb.erb",
16
+ "db/migrate/#{migration_file_name}.rb",
17
+ migration_version: migration_version)
18
+ end
19
+
20
+ def migration_name
21
+ "add_quickery_#{attributes.map(&:name).join("_")}_to_#{name.underscore.pluralize}"
22
+ end
23
+
24
+ def migration_file_name
25
+ "#{migration_name}"
26
+ end
27
+
28
+ def migration_class_name
29
+ migration_name.camelize
30
+ end
31
+
32
+ def migration_version
33
+ if Rails.version.start_with? "5"
34
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
35
+ end
36
+ end
37
+
38
+ # https://github.com/rails/rails/blob/v5.2.1/activerecord/lib/rails/generators/active_record/migration/migration_generator.rb#L62
39
+ def attributes_with_index
40
+ attributes.select { |a| !a.reference? && a.has_index? }
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,15 @@
1
+ class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ change_table :<%= table_name %> do |t|
4
+ <% attributes.each do |attribute| -%>
5
+ t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
6
+ <% if options[:add_is_synced_attributes] -%>
7
+ t.boolean :<%= attribute.name %>_is_synced, null: false, default: false
8
+ <% end -%>
9
+ <% end -%>
10
+ end
11
+ <% attributes_with_index.each do |attribute| -%>
12
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
13
+ <% end -%>
14
+ end
15
+ end
@@ -41,6 +41,9 @@ module Quickery
41
41
 
42
42
  new_values[depender_column_name] = new_value
43
43
  end
44
+
45
+ # set to true because on-create, all quickery-attributes are evaluated and assigned
46
+ new_values[:"#{depender_column_name}_is_synced"] = true if has_attribute? :"#{depender_column_name}_is_synced"
44
47
  end
45
48
 
46
49
  self.class.quickery_before_create_or_update(self, new_values)
@@ -68,6 +71,7 @@ module Quickery
68
71
  end
69
72
 
70
73
  new_values[depender_column_name] = new_value
74
+ new_values[:"#{depender_column_name}_is_synced"] = true if has_attribute? :"#{depender_column_name}_is_synced"
71
75
  end
72
76
  end
73
77
 
@@ -87,10 +91,14 @@ module Quickery
87
91
 
88
92
  dependent_records = association_chain_dependee.dependent_records(self)
89
93
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
90
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
91
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
92
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
93
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
94
+ records_sql_identifier = dependent_records.to_sql.to_sym
95
+ dependent_records_attributes_to_be_updated[records_sql_identifier] ||= {}.with_indifferent_access
96
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:dependent_records] ||= dependent_records
97
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values] ||= {}.with_indifferent_access
98
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][depender_column_name.to_sym] = new_value
99
+ if dependent_records.model.column_names.include? "#{depender_column_name}_is_synced"
100
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][:"#{depender_column_name}_is_synced"] = true
101
+ end
94
102
  end
95
103
  end
96
104
  end
@@ -111,10 +119,15 @@ module Quickery
111
119
 
112
120
  dependent_records = association_chain_intermediary.dependent_records(self)
113
121
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
114
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
115
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
116
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
117
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
122
+ records_sql_identifier = dependent_records.to_sql.to_sym
123
+ dependent_records_attributes_to_be_updated[records_sql_identifier] ||= {}.with_indifferent_access
124
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:dependent_records] ||= dependent_records
125
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values] ||= {}.with_indifferent_access
126
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][depender_column_name.to_sym] = new_value
127
+
128
+ if dependent_records.model.column_names.include? "#{depender_column_name}_is_synced"
129
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][:"#{depender_column_name}_is_synced"] = true
130
+ end
118
131
  end
119
132
  end
120
133
  end
@@ -143,10 +156,14 @@ module Quickery
143
156
 
144
157
  dependent_records = association_chain_dependee.dependent_records(self)
145
158
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
146
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
147
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
148
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
149
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
159
+ records_sql_identifier = dependent_records.to_sql.to_sym
160
+ dependent_records_attributes_to_be_updated[records_sql_identifier] ||= {}.with_indifferent_access
161
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:dependent_records] ||= dependent_records
162
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values] ||= {}.with_indifferent_access
163
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][depender_column_name.to_sym] = new_value
164
+ if dependent_records.model.column_names.include? "#{depender_column_name}_is_synced"
165
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][:"#{depender_column_name}_is_synced"] = true
166
+ end
150
167
  end
151
168
  end
152
169
  end
@@ -162,10 +179,14 @@ module Quickery
162
179
 
163
180
  dependent_records = association_chain_intermediary.dependent_records(self)
164
181
  # use the SQL as the uniqueness identifier, so that multiple quickery-attributes dependent-records are updated in one go, instead of updating each
165
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym] ||= {}.with_indifferent_access
166
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:dependent_records] ||= dependent_records
167
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values] ||= {}.with_indifferent_access
168
- dependent_records_attributes_to_be_updated[dependent_records.to_sql.to_sym][:new_values][depender_column_name.to_sym] = new_value
182
+ records_sql_identifier = dependent_records.to_sql.to_sym
183
+ dependent_records_attributes_to_be_updated[records_sql_identifier] ||= {}.with_indifferent_access
184
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:dependent_records] ||= dependent_records
185
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values] ||= {}.with_indifferent_access
186
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][depender_column_name.to_sym] = new_value
187
+ if dependent_records.model.column_names.include? "#{depender_column_name}_is_synced"
188
+ dependent_records_attributes_to_be_updated[records_sql_identifier][:new_values][:"#{depender_column_name}_is_synced"] = true
189
+ end
169
190
  end
170
191
  end
171
192
  end
@@ -19,6 +19,8 @@ module Quickery
19
19
  mappings_builder.map_attributes
20
20
  end
21
21
 
22
+ private
23
+
22
24
  # subclass overrideable
23
25
  def quickery_before_create_or_update(dependent_record, new_values)
24
26
  dependent_record.assign_attributes(new_values)
@@ -44,7 +46,7 @@ module Quickery
44
46
  end
45
47
 
46
48
  def determine_quickery_value(depender_column_name)
47
- quickery_builder = self.class.quickery_builders[depender_column_name]
49
+ quickery_builder = self.class.quickery_builders[depender_column_name.to_sym]
48
50
 
49
51
  raise ArgumentError, "No defined quickery builder for #{depender_column_name}. Defined values are #{self.class.quickery_builders.keys}" unless quickery_builder
50
52
 
@@ -59,6 +61,23 @@ module Quickery
59
61
  end
60
62
  quickery_values
61
63
  end
64
+
65
+ # only considers quickery-defined attributes that has corresponding *_is_synced attribute
66
+ def autoload_unsynced_quickery_attributes!
67
+ model = self.class
68
+ new_values = {}.with_indifferent_access
69
+
70
+ defined_quickery_attribute_names = model.quickery_builders.keys
71
+
72
+ defined_quickery_attribute_names.each do |defined_quickery_attribute_name|
73
+ if has_attribute?(:"#{defined_quickery_attribute_name}_is_synced") && !send(:"#{defined_quickery_attribute_name}_is_synced")
74
+ new_values[defined_quickery_attribute_name] = determine_quickery_value(defined_quickery_attribute_name)
75
+ new_values[:"#{defined_quickery_attribute_name}_is_synced"] = true
76
+ end
77
+ end
78
+
79
+ update_columns(new_values) if new_values.present?
80
+ end
62
81
  end
63
82
  end
64
83
  end
@@ -1,3 +1,3 @@
1
1
  module Quickery
2
- VERSION = '1.2.0'
2
+ VERSION = '1.3.0'
3
3
  end
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.2.0
4
+ version: 1.3.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-15 00:00:00.000000000 Z
11
+ date: 2018-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -247,6 +247,8 @@ files:
247
247
  - gemfiles/.bundle/config
248
248
  - gemfiles/rails_4.gemfile
249
249
  - gemfiles/rails_5.gemfile
250
+ - lib/generators/quickery/migration/migration_generator.rb
251
+ - lib/generators/quickery/migration/templates/migration.rb.erb
250
252
  - lib/quickery.rb
251
253
  - lib/quickery/active_record_extensions.rb
252
254
  - lib/quickery/active_record_extensions/callbacks.rb