attr_json 1.4.1 → 2.0.0.rc1

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: 3f2658693e8b0c4d99e412e33c8d2ef67a70bb71302f0d3d079326bef2380c44
4
- data.tar.gz: 6acbf7ca9e743a2a22550731baf495306bc087fd3787c02ea19435b94f96a85d
3
+ metadata.gz: 11d5f5f1403cf8388ab7b5b14494a68ff5bdb11c1cd739ae81f78da5b97dbbbc
4
+ data.tar.gz: d787c2b06cc01478cd764201a204e85312bc9204f8c54b9bdbe2c5e597ac00b1
5
5
  SHA512:
6
- metadata.gz: 9a3cf5a739623ba998162b0072b351a2ae07316691dc013c2f88820dc36d5119833d64bc89335379dbd636f65fcf4253f818649f57538c753b0a5d98fc7c5b6c
7
- data.tar.gz: 79a977eb57509ad7035bb5d20e6212568d51b8062de11d536bbeae58acab8bc8db48eba181adeecff97286fa59042b6eb143359b41a7c65d73955fb18c2edc75
6
+ metadata.gz: 8dd9c059292d1fba076323f101f0a3445986db3b41ef6099a4f33a583dd1c8bb1dc58e42fba1f35d74fe87eeb1f3fe4253959377cb98c322fa9e22a99c5d43db
7
+ data.tar.gz: d145d01c73273d4fd1f089b95287fb67adb3c1f6ed12a5c5317a879f230430b760b3abbdf0c27626a2560e612a6823e239ab849ec557a2b412564e2a6bd5ef1c
@@ -29,27 +29,6 @@ jobs:
29
29
  fail-fast: false
30
30
  matrix:
31
31
  include:
32
- - gemfile: rails_5_0
33
- ruby: 2.4
34
-
35
- - gemfile: rails_5_0
36
- ruby: 2.5
37
-
38
- - gemfile: rails_5_1
39
- ruby: 2.4
40
-
41
- - gemfile: rails_5_2
42
- ruby: 2.4
43
-
44
- - gemfile: rails_5_2
45
- ruby: 2.6
46
-
47
- - gemfile: rails_6_0
48
- ruby: 2.6
49
-
50
- - gemfile: rails_6_0
51
- ruby: 2.7
52
-
53
32
  - gemfile: rails_6_1
54
33
  ruby: 2.7
55
34
 
@@ -62,6 +41,10 @@ jobs:
62
41
  - gemfile: rails_7_0
63
42
  ruby: 3.1
64
43
 
44
+ - gemfile: rails_7_0
45
+ ruby: 3.2
46
+
47
+
65
48
  name: ${{ matrix.gemfile }}, ruby ${{ matrix.ruby }}
66
49
 
67
50
  steps:
@@ -45,12 +45,12 @@ jobs:
45
45
  include:
46
46
 
47
47
  - gemfile: rails_edge
48
- ruby: '3.0'
48
+ ruby: '3.1'
49
49
 
50
50
  name: ${{ matrix.gemfile }}, ruby ${{ matrix.ruby }}
51
51
 
52
52
  steps:
53
- - uses: actions/checkout@v2
53
+ - uses: actions/checkout@v3
54
54
 
55
55
  - name: Set up Ruby
56
56
  uses: ruby/setup-ruby@v1
data/Appraisals CHANGED
@@ -1,30 +1,3 @@
1
- appraise "rails-5-0" do
2
- gem 'combustion', '~> 0.9.0'
3
-
4
- gem "rails", "~> 5.0.0"
5
-
6
- # rails 5.1+ includes it by default, but rails 5.0 needs it:
7
- gem 'rails-ujs', require: false
8
-
9
- # Rails 5 won't work with pg 1.0 even though it doesn't say so
10
- gem "pg", "~> 0.18"
11
- end
12
-
13
- appraise "rails-5-1" do
14
- gem 'combustion', '~> 0.9.0'
15
-
16
- gem "rails", "~> 5.1.0"
17
-
18
- gem "pg", "~> 1.0"
19
- end
20
-
21
- appraise "rails-5-2" do
22
- gem 'combustion', '~> 0.9.0'
23
-
24
- gem "rails", "~> 5.2.0"
25
- gem "pg", "~> 1.0"
26
- end
27
-
28
1
  appraise "rails-6-0" do
29
2
  gem 'combustion', "~> 1.0"
30
3
 
data/CHANGELOG.md CHANGED
@@ -4,7 +4,56 @@ Notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased](https://github.com/jrochkind/attr_json/compare/v1.4.0...HEAD)
7
+ ## [Unreleased](https://github.com/jrochkind/attr_json/compare/v3.0.0...HEAD)
8
+
9
+
10
+
11
+ ## [3.0.0.rc1](https://github.com/jrochkind/attr_json/compare/v1.5.0...v3.0.0.rc1)
12
+
13
+ While it has some backwards incompat changes, this is expected not to be a challenging upgrade, please let us know by filing an issue if it's giving you troubles, maybe we can make things easier for you. No changes to data stored in your DB should be needed when upgrading, the persisted data should be compatible between 2.x and 3.x.
14
+
15
+ ### Removed
16
+
17
+ * `AttrJson::Record::Dirty` has been removed, along with the `#attr_json_changes` method. You should now be able to just use standard ActiveRecord dirty tracking with attr_json attributes. https://github.com/jrochkind/attr_json/pull/163 (AttrJson::Record::Dirty was actually badly broken, as reported by @bemueller at https://github.com/jrochkind/attr_json/issues/148)
18
+
19
+ * The `rails_attribute` param to `attr_json` or `attr_json_config` no longer exists. We now always create rails attributes for AttrJson::Record attributes. https://github.com/jrochkind/attr_json/pull/117 and https://github.com/jrochkind/attr_json/pull/158
20
+
21
+ ### Changed
22
+
23
+ * We now create Rails Attribute cover for all attr_json attributes, and we do a better job of keeping the Rails attribute values sync'd with attr_json values. https://github.com/jrochkind/attr_json/pull/117, https://github.com/jrochkind/attr_json/pull/158, and https://github.com/jrochkind/attr_json/pull/163
24
+
25
+ * Drop support for Rails earlier than 6.0 and ruby earlier than 2.7. https://github.com/jrochkind/attr_json/pull/155 https://github.com/jrochkind/attr_json/pull/174
26
+
27
+ * Array types now default to an empty array. If you'd like to turn that off, you can use the somewhat odd `default: AttrJson::AttributeDefinition::NO_DEFAULT_PROVIDED` on attribute definiton. Thanks @g13ydson for suggestion. https://github.com/jrochkind/attr_json/pull/161
28
+
29
+ * time or datetime types used to truncate all fractional seconds to 0. Now they properly allow precision of `ActiveSupport::JSON::Encoding.time_precision` (normally three decimal places, ie milliseconds). And by default the Type::Value's are set to proper precision for cast too. https://github.com/jrochkind/attr_json/pull/173
30
+
31
+ * AttrJson::Models are serialized without nil values in the hash, for more compact representations. This is only done for attributes without defaults. This behavior can be disabled/altered when specifying the type. https://github.com/jrochkind/attr_json/pull/175
32
+
33
+ * config default_accepts_nested_attributes will only apply nested attributes to suitable attribute types (array or nested model), the default won't apply to inapplicable types. https://github.com/jrochkind/attr_json/pull/178
34
+
35
+ ### Added
36
+
37
+ * ActiveRecord-style "timezone-aware attribute" conversion now works properly, in both AttrJson::Record and (similarly) AttrJson::Model. https://github.com/jrochkind/attr_json/pull/164
38
+
39
+ ### Fixed
40
+
41
+ * the `AttrJson::Type::Array` type used for our array types was not properly tracking in-place mutation changes. Now it is https://github.com/jrochkind/attr_json/pull/163
42
+
43
+ * Default nested model validation should allow nils in arrays of models. https://github.com/jrochkind/attr_json/pull/177
44
+
45
+
46
+
47
+ ## [1.5.0](https://github.com/jrochkind/attr_json/compare/v1.4.1...v1.5.0)
48
+
49
+ ### Added
50
+
51
+ * AttrJson::Model#dup will properly deep-dup attributes https://github.com/jrochkind/attr_json/pull/169
52
+
53
+ * AttrJson::Model#freeze will freeze attributes -- but not deep-freeze. https://github.com/jrochkind/attr_json/pull/169
54
+
55
+ * AttrJson::Model has some methods conventional in ActiveModel classes: Klass.attribute_types, Klass.attribute_names, and instance.attribute_names. https://github.com/jrochkind/attr_json/pull/169
56
+
8
57
 
9
58
 
10
59
  ## [1.4.1](https://github.com/jrochkind/attr_json/compare/v1.4.0...v1.4.1)
data/Gemfile CHANGED
@@ -19,7 +19,7 @@ gem 'combustion', '~> 1.1'
19
19
  gem 'rails'
20
20
 
21
21
  gem "pg"
22
- gem "rspec-rails", "~> 4.0"
22
+ gem "rspec-rails", "~> 6.0"
23
23
  gem "simple_form", ">= 4.0"
24
24
  gem 'cocoon', ">= 1.2"
25
25
  gem 'jquery-rails'
@@ -37,7 +37,7 @@ gem "sprockets-rails"
37
37
 
38
38
 
39
39
  gem 'capybara', "~> 3.0"
40
- gem 'webdrivers', '~> 4.0'
40
+ gem 'webdrivers', '~> 5.0'
41
41
  gem "selenium-webdriver"
42
42
 
43
43
  gem "byebug"
data/README.md CHANGED
@@ -3,10 +3,9 @@
3
3
  [![CI Status](https://github.com/jrochkind/attr_json/workflows/CI%20on%20Future%20Rails%20Versions/badge.svg?branch=master)](https://github.com/jrochkind/attr_json/actions?query=workflow%3A%22CI+on+Future+Rails+Versions%22+branch%3Amaster)
4
4
  [![Gem Version](https://badge.fury.io/rb/attr_json.svg)](https://badge.fury.io/rb/attr_json)
5
5
 
6
+ ActiveRecord attributes stored serialized in a json column, super smooth. For Rails 6.0.x through 7.0.x. Ruby 2.7+.
6
7
 
7
- ActiveRecord attributes stored serialized in a json column, super smooth. For Rails 5.0 through 6.1. Ruby 2.4+.
8
-
9
- Typed and cast like Active Record. Supporting [nested models](#nested), [dirty tracking](#dirty), some [querying](#querying) (with postgres [jsonb](https://www.postgresql.org/docs/9.5/static/datatype-json.html) contains), and [working smoothy with form builders](#forms).
8
+ Typed and cast like Active Record. Supporting [nested models](#nested), [dirty tracking](#ar_attributes), some [querying](#querying) (with postgres [jsonb](https://www.postgresql.org/docs/9.5/static/datatype-json.html) contains), and [working smoothy with form builders](#forms).
10
9
 
11
10
  *Use your database as a typed object store via ActiveRecord, in the same models right next to ordinary ActiveRecord column-backed attributes and associations. Your json-serialized `attr_json` attributes use as much of the existing ActiveRecord architecture as we can.*
12
11
 
@@ -18,7 +17,7 @@ has not yet been tested with MySQL.
18
17
  ## Basic Use
19
18
 
20
19
  ```ruby
21
- # migration
20
+ # migration, default column used is `json_attributes, but this can be changed
22
21
  class CreatMyModels < ActiveRecord::Migration[5.0]
23
22
  def change
24
23
  create_table :my_models do |t|
@@ -30,6 +29,14 @@ class CreatMyModels < ActiveRecord::Migration[5.0]
30
29
  end
31
30
  end
32
31
 
32
+ # An embedded model, if desired
33
+ class LangAndValue
34
+ include AttrJson::Model
35
+
36
+ attr_json :lang, :string, default: "en"
37
+ attr_json :value, :string
38
+ end
39
+
33
40
  class MyModel < ActiveRecord::Base
34
41
  include AttrJson::Record
35
42
 
@@ -39,14 +46,37 @@ class MyModel < ActiveRecord::Base
39
46
  attr_json :my_integer, :integer
40
47
  attr_json :my_datetime, :datetime
41
48
 
42
- # You can have an _array_ of those things too.
49
+ # You can have an _array_ of those things too. It will ordinarily default to empty array.
43
50
  attr_json :int_array, :integer, array: true
44
51
 
45
52
  #and/or defaults
46
- attr_json :int_with_default, :integer, default: 100
53
+ attr_json :str_with_default, :string, default: "default value"
54
+
55
+ attr_json :embedded_lang_and_val, LangAndValue.to_type
47
56
  end
57
+
58
+ model = MyModel.create!(
59
+ my_integer: 101,
60
+ my_datetime: DateTime.new(2001,2,3,4,5,6),
61
+ embedded_lang_and_val: LangAndValue.new(value: "a sentance in default language english")
62
+ )
63
+ ```
64
+
65
+ What will get serialized to your `json_attributes` column will look like:
66
+
67
+ ```json
68
+ {
69
+ "my_integer":101,
70
+ "my_datetime":"2001-02-03T04:05:06Z",
71
+ "str_with_default":"default value",
72
+ "embedded_lang_and_val": {
73
+ "lang":"en",
74
+ "value":"a sentance in default language english"
75
+ }
76
+ }
48
77
  ```
49
78
 
79
+
50
80
  These attributes have type-casting behavior very much like ordinary ActiveRecord values.
51
81
 
52
82
  ```ruby
@@ -57,6 +87,8 @@ model.int_array = "12"
57
87
  model.int_array # => [12]
58
88
  model.my_datetime = "2016-01-01 17:45"
59
89
  model.my_datetime # => a Time object representing that, just like AR would cast
90
+ model.embedded_lang_and_val = { value: "val"}
91
+ model.embedded_lang_and_val #=> #<LangAndVal:0x000000010c9a7ad8 @attributes={"value"=>"val"...>
60
92
  ```
61
93
 
62
94
  You can use ordinary ActiveRecord validation methods with `attr_json` attributes.
@@ -64,14 +96,9 @@ You can use ordinary ActiveRecord validation methods with `attr_json` attributes
64
96
  All the `attr_json` attributes are serialized to json as keys in a hash, in a database jsonb/json column. By default, in a column `json_attributes`.
65
97
  If you look at `model.json_attributes`, you'll see values already cast to their ruby representations.
66
98
 
67
- But one way to see something like what it's really like in the db is to
68
- save the record and then use the standard Rails `*_before_type_cast` method.
99
+ To see JSON representations, we can use Rails [\*\_before_type_cast](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/BeforeTypeCast.html) methods, [\*\-in_database](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html#method-i-attribute_in_database) and [\*\_for_database] methods (Rails 7.0+ only).
69
100
 
70
- ```ruby
71
- model.save!
72
- model.json_attributes_before_type_cast
73
- # => string containing: {"my_integer":12,"int_array":[12],"my_datetime":"2016-01-01T17:45:00.000Z"}
74
- ```
101
+ These methods can all be called on the container `json_attributes` json hash attribute (generally showing serialized JSON to string), or any individual attribute (generally showing in-memory JSON-able object). [This is a bit confusing and possibly not entirely consistent, needs more investigation.]
75
102
 
76
103
  ## Specifying db column to use
77
104
 
@@ -229,6 +256,8 @@ m.attr_jsons_before_type_cast
229
256
 
230
257
  You can nest AttrJson::Model objects inside each other, as deeply as you like.
231
258
 
259
+ For use with Rails forms, you may want to use `attr_json_accepts_nested_attributes_for` (like Rails `accepts_nested_attributes_for`, see doc page on [Use with Forms and Form Builders](https://github.com/jrochkind/attr_json/blob/master/doc_src/forms.md).
260
+
232
261
  ### Model-type defaults
233
262
 
234
263
  If you want to set a default for an AttrJson::Model type, you should use a proc argument for
@@ -386,44 +415,29 @@ Use with Rails form builders is supported pretty painlessly. Including with [sim
386
415
 
387
416
  If you have nested AttrJson::Models you'd like to use in your forms much like Rails associated records: Where you would use Rails `accepts_nested_attributes_for`, instead `include AttrJson::NestedAttributes` and use `attr_json_accepts_nested_attributes_for`. Multiple levels of nesting are supported.
388
417
 
389
- To get simple_form to properly detect your attribute types, define your attributes with `rails_attribute: true`. You can default rails_attribute to true with `attr_json_config(default_rails_attribute: true)`
390
-
391
418
  For more info, see doc page on [Use with Forms and Form Builders](doc_src/forms.md).
392
419
 
393
- <a name="dirty"></a>
394
- ## Dirty tracking
420
+ <a name="ar_attributes"></a>
421
+ ## ActiveRecord Attributes and Dirty tracking
395
422
 
396
- Full change-tracking, ActiveRecord::Attributes::Dirty-style, is available in
397
- Rails 5.1+ on `attr_json`s on your ActiveRecord classes that include
398
- `AttrJson::Record`, by including `AttrJson::Record::Dirty`.
399
- Change-tracking methods are available off the `attr_json_changes` method.
423
+ We endeavor to make record-level `attr_json` attributes available as standard ActiveRecord attributes, supporting that full API.
400
424
 
401
- ```ruby
402
- class MyModel < ActiveRecord::Base
403
- include AttrJson::Record
404
- include AttrJson::Record::Dirty
425
+ Standard [Rails dirty tracking](https://api.rubyonrails.org/classes/ActiveModel/Dirty.html) should work properly with AttrJson::Record attributes! We have a test suite demonstrating.
405
426
 
406
- attr_json :str, :string
407
- end
427
+ We actually keep the "canonical" copy of data inside the "container attribute" hash in the ActiveRecord model. This is because this is what will actually get saved when you save. So we have two copies, that we do our best to keep in sync.
408
428
 
409
- model = MyModel.new
410
- model.str = "old"
411
- model.save
412
- model.str = "new"
413
-
414
- # All and only "new" style dirty tracking methods (Raisl 5.1+)
415
- # are available:
416
-
417
- model.attr_json_changes.saved_changes
418
- model.attr_json_changes.changes_to_save
419
- model.attr_json_changes.saved_change_to_str?
420
- model.attr_json_changes.saved_change_to_str
421
- model.attr_json_changes.will_save_change_to_str?
422
- # etc
429
+ They get out of sync if you are doing unusual things like using the ActiveRecord attribute API directly (like calling `write_attribute` with an attr_json attribute). Even if this happens, mostly you won't notice. But one thing it will effect is dirty tracking.
430
+
431
+ If you ever need to sync the ActiveRecord attribute values from the AttrJson "canonical" copies, you can call `active_record_model.attr_json_sync_to_rails_attributes`. If you wanted to be 100% sure of dirty tracking, I suppose you could always call this method first. Sorry, this is the best we could do!
432
+
433
+ Note that ActiveRecord DirtyTracking will give you ruby objects, for instance for nested models, you might get:
434
+
435
+ ```ruby
436
+ record_obj.attribute_change_to_be_saved(:nested_model)
437
+ # => [#<object>, #<object>]
423
438
  ```
424
439
 
425
- More options are available, including merging changes from 'ordinary'
426
- ActiveRecord attributes in. See docs on [Dirty Tracking](./doc_src/dirty_tracking.md)
440
+ If you want to see JSON instead, you could call #as_json on the values. The Rails [\*\_before_type_cast](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/BeforeTypeCast.html) and [\*\-in_database](https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html#method-i-attribute_in_database) methods may also be useful.
427
441
 
428
442
  <a name="why"></a>
429
443
  ## Do you want this?
@@ -478,15 +492,13 @@ to prevent overwriting other updates from processes.
478
492
 
479
493
  ## State of Code, and To Be Done
480
494
 
481
- This code is solid and stable and is being used in production by at least a handful of people, including the primary maintainer, jrochkind.
495
+ This code is solid and stable and is being used in production. If you don't see a lot of activity, it might be because it's stable, rather than abandoned. Check to see if it's passing/supported on recent Rails? We test on "edge" unreleased rails to try to stay ahead of compatibility, and has worked through multiple major Rails verisons with few if any changes needed.
482
496
 
483
- The project is currently getting very little maintainance -- and is still working reliably through Rails releases. It is tested on edge rails and ruby (and has needed very few if any changes with subsequent releases), and I endeavor to keep it working as Rails keeps releasing.
484
-
485
- In order to keep the low-maintenace scenario sustainable, I am *very* cautious accepting new features, especially if they increase code complexity at all. Even if you have a working PR, I may be reluctant to accept it. I'm prioritizing sustainability and stability over new features, and so far this is working out well. However, discussion is always welcome! Especially when paired with code (failing tests for the bugfix or feature you want are super helpful on their own!).
497
+ In order to keep the low-maintenace scenario sustainable, I am *very* cautious accepting new features, especially if they increase code complexity at all. Even if you have a working PR, I may be reluctant to accept it. I'm prioritizing sustainability and stability over new features, and so far this is working out well. However, discussion is always welcome! Especially when paired with code (failing tests for the bugfix or feature you want are super helpful on their own!).
486
498
 
487
499
  We are committed to [semantic versioning](https://semver.org/) and will endeavor to release no backwards breaking changes without a major version. We are also serious about minimizing backwards incompat releases altogether (ie minimiing major version releases).
488
500
 
489
- Feedback of any kind of _very welcome_, please feel free to use the issue tracker. It is hard to get a sense of how many people are actually using this, which is helpful both for my own sense of reward and for anyone to get a sense of the size of the userbase -- feel free to say hi and let us know how you are using it!
501
+ Feedback of any kind of _very welcome_, please feel free to use the issue tracker. It is hard to get a sense of how many people are actually using this, which is helpful both for my own sense of reward and for anyone to get a sense of the size of the userbase -- feel free to say hi and let us know how you are using it!
490
502
 
491
503
  Except for the jsonb_contains stuff using postgres jsonb contains operator, I don't believe any postgres-specific features are used. It ought to work with MySQL, testing and feedback welcome. (Or a PR to test on MySQL?). My own interest is postgres.
492
504
 
@@ -494,13 +506,9 @@ This is still mostly a single-maintainer operation, so has all the sustainabilit
494
506
 
495
507
  ### Possible future features:
496
508
 
497
- * Make AttrJson::Model lean more heavily on ActiveModel::Attributes API that did not fully exist in first version of attr_json [hope for a future attr_json 2.0 release]
498
-
499
- * Make AttrJson::Record insist on creating rails cover attributes (no longer optional) and integrating more fully into rails, including rails dirty tricking, eliminating need for custom dirty tracking implementation. Overall decrease in lines of code. Can use jsonb_accessor as guide for some aspects. [hope for inclusion in future attr_json 2.0 release]
500
-
501
- * partial updates for json hashes would be really nice: Using postgres jsonb merge operators to only overwrite what changed. In my initial attempts, AR doesn't make it easy to customize this. [update: this is hard, probably not coming soon]
509
+ * Make AttrJson::Model lean more heavily on ActiveModel::Attributes API that did not fully exist in first version of attr_json (perhaps not, see https://github.com/jrochkind/attr_json/issues/18)
502
510
 
503
- * seamless compatibility with ransack [update: not necessarily prioritized]
511
+ * partial updates for json hashes would be really nice: Using postgres jsonb merge operators to only overwrite what changed. In my initial attempts, AR doesn't make it easy to customize this. [update: this is hard, probably not coming soon. See https://github.com/jrochkind/attr_json/issues/143]
504
512
 
505
513
  * Should we give AttrJson::Model a before_serialize hook that you might
506
514
  want to use similar to AR before_save? Should AttrJson::Models
data/attr_json.gemspec CHANGED
@@ -11,8 +11,8 @@ Gem::Specification.new do |spec|
11
11
 
12
12
  spec.summary = %q{ActiveRecord attributes stored serialized in a json column, super smooth.}
13
13
  spec.description = %q{ActiveRecord attributes stored serialized in a json column, super smooth.
14
- For Rails 5.0, 5.1, or 5.2. Typed and cast like Active Record. Supporting nested models,
15
- dirty tracking, some querying (with postgres jsonb contains), and working smoothy with form builders.
14
+ Typed and cast like Active Record. Supporting nested models, dirty tracking, some querying
15
+ (with postgres jsonb contains), and working smoothy with form builders.
16
16
 
17
17
  Use your database as a typed object store via ActiveRecord, in the same models right next to
18
18
  ordinary ActiveRecord column-backed attributes and associations. Your json-serialized attr_json
@@ -40,12 +40,12 @@ attributes use as much of the existing ActiveRecord architecture as we can.}
40
40
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
41
41
  spec.require_paths = ["lib"]
42
42
 
43
- spec.required_ruby_version = '>= 2.4.0'
43
+ spec.required_ruby_version = '>= 2.6.0'
44
44
 
45
45
  # Only to get CI to work on versions of Rails other than we release with,
46
46
  # should never release a gem with RAILS_GEM set!
47
47
  unless ENV['APPRAISAL_INITIALIZED'] || ENV["TRAVIS"] || ENV['CI']
48
- spec.add_runtime_dependency "activerecord", ">= 5.0.0", "< 7.1"
48
+ spec.add_runtime_dependency "activerecord", ">= 6.0.0", "< 7.1"
49
49
  end
50
50
 
51
51
  spec.add_development_dependency "bundler"
data/doc_src/forms.md CHANGED
@@ -31,7 +31,7 @@ With ordinary rails associations handled in the ordinary Rails way, you use [acc
31
31
  You can handle a single or array AttrJson::Model attr_json similarly, but you have to:
32
32
 
33
33
  * include AttrJson::NestedAttributes in your model, and then
34
- * use our own similar `attr_json_accepts_nested_attributes_for` instead. It _always_ has `allow_destroy`, and some of the other `accepts_nested_attributes_for` options also don't apply, see method for full options.
34
+ * use our own similar `attr_json_accepts_nested_attributes_for` instead. It _always_ has `allow_destroy`, and some of the other `accepts_nested_attributes_for` options also don't apply, see method for full options -- we expect you will usually want to use this with the `reject_if: :all_blank` option to ignore hashes with no non-nil values.
35
35
 
36
36
  ```ruby
37
37
  class Event
@@ -47,7 +47,7 @@ class MyRecord < ActiveRecord::Base
47
47
  attr_json :one_event, Event.to_type
48
48
  attr_json :many_events, Event.to_type, array: true
49
49
 
50
- attr_json_accepts_nested_attributes_for :one_event, :many_events
50
+ attr_json_accepts_nested_attributes_for :one_event, :many_events, reject_if: :all_blank
51
51
  end
52
52
 
53
53
  # In a form template...
@@ -109,19 +109,8 @@ Remember to add `include AttrJson::NestedAttributes` to all your AttrJson::Model
109
109
 
110
110
  One of the nice parts about [simple_form](https://github.com/plataformatec/simple_form) is how you can just give it `f.input`, and it figures out the right input for you.
111
111
 
112
- AttrJson by default, on an ActiveRecord::Base, doesn't register it's `attr_jsons` in the right way for simple_form to reflect and figure out their types. However, you can ask it to with `rails_attribute: true`.
112
+ AttrJson by default registers `attr_jsons` as Rails attributes, and provides other appropriate implementations in AttrJson::Model classes, such that simple_form should just work. There are limited CI tests in this project to confirm simple_form stays working.
113
113
 
114
- ```ruby
115
- class SomeRecord < ActiveRecord::Base
116
- include AttrJson::Record
117
-
118
- attr_json :my_date, :date, rails_attribute: true
119
- end
120
- ```
121
-
122
- This will use the [ActiveRecord::Base.attribute](http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html) method to register the attribute and type, and SimpleForm will now be able to automatically look up attribute type just as you expect. (Q: Should we make this default on?)
123
-
124
- You don't need to do this in your nested AttrJson::Model classes, SimpleForm will already be able to reflect on their attribute types just fine as is.
125
114
 
126
115
  ### Arrays of simple attributes
127
116
 
@@ -34,23 +34,14 @@
34
34
 
35
35
  @default = if options.has_key?(:default)
36
36
  options[:default]
37
+ elsif options[:array] == true
38
+ -> { [] }
37
39
  else
38
40
  NO_DEFAULT_PROVIDED
39
41
  end
40
42
 
41
- if type.is_a? Symbol
42
- # ActiveModel::Type.lookup may make more sense, but ActiveModel::Type::Date
43
- # seems to have a bug with multi-param assignment. Mostly they return
44
- # the same types, but ActiveRecord::Type::Date works with multi-param assignment.
45
- #
46
- # We pass `adapter: nil` to avoid triggering a db connection.
47
- # See: https://github.com/jrochkind/attr_json/issues/41
48
- # This is at the "cost" of not using any adapter-specific types... which
49
- # maybe preferable anyway?
50
- type = ActiveRecord::Type.lookup(type, adapter: nil)
51
- elsif ! type.is_a? ActiveModel::Type::Value
52
- raise ArgumentError, "Second argument (#{type}) must be a symbol or instance of an ActiveModel::Type::Value subclass"
53
- end
43
+ type = self.class.lookup_type(type)
44
+
54
45
  @type = (options[:array] == true ? AttrJson::Type::Array.new(type) : type)
55
46
  end
56
47
 
@@ -102,5 +93,50 @@
102
93
  def array_type?
103
94
  type.is_a? AttrJson::Type::Array
104
95
  end
96
+
97
+ # Used for figuring out appropriate behavior for nested attribute implementation among
98
+ # other places. true if type is a nested model, either straight or polymorphic
99
+ def single_model_type?
100
+ self.class.single_model_type?(type)
101
+ end
102
+
103
+ def self.single_model_type?(arg_type)
104
+ arg_type.is_a?(AttrJson::Type::Model) || arg_type.is_a?(AttrJson::Type::PolymorphicModel)
105
+ end
106
+
107
+ # Used for figuring out appropriate behavior in nested attribute implementation among
108
+ # other places. true if type is an array of things that are not nested models.
109
+ def array_of_primitive_type?
110
+ array_type? && !self.class.single_model_type?(type.base_type)
111
+ end
112
+
113
+ # Can look up a symbol to a type, or leave a type alone, or raise if it's neither.
114
+ # Extracted into a method, so it can be called from AttrJson::Model#attr_json, for
115
+ # some timezone aware shenanigans.
116
+ def self.lookup_type(type)
117
+ if type.is_a? Symbol
118
+ # ActiveModel::Type.lookup may make more sense, but ActiveModel::Type::Date
119
+ # seems to have a bug with multi-param assignment. Mostly they return
120
+ # the same types, but ActiveRecord::Type::Date works with multi-param assignment.
121
+ #
122
+ # We pass `adapter: nil` to avoid triggering a db connection.
123
+ # See: https://github.com/jrochkind/attr_json/issues/41
124
+ # This is at the "cost" of not using any adapter-specific types... which
125
+ # maybe preferable anyway?
126
+ #
127
+ # AND we add precision for datetime/time types... since we're using Rails json
128
+ # serializing, we're kind of stuck with this precision in current implementation.
129
+ lookup_kwargs = { adapter: nil }
130
+ if type == :datetime || type == :time
131
+ lookup_kwargs = { precision: ActiveSupport::JSON::Encoding.time_precision }
132
+ end
133
+
134
+ type = ActiveRecord::Type.lookup(type, **lookup_kwargs)
135
+ elsif !(type.is_a?(ActiveModel::Type::Value) || type.is_a?(ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter))
136
+ raise ArgumentError, "Second argument (#{type}) must be a symbol or instance of an ActiveModel::Type::Value subclass"
137
+ end
138
+ type
139
+ end
140
+
105
141
  end
106
142
  end
@@ -5,18 +5,17 @@ module AttrJson
5
5
  class Config
6
6
  RECORD_ALLOWED_KEYS = %i{
7
7
  default_container_attribute
8
- default_rails_attribute
9
8
  default_accepts_nested_attributes
10
9
  }
11
10
 
12
11
  MODEL_ALLOWED_KEYS = %i{
13
12
  unknown_key
14
13
  bad_cast
14
+ time_zone_aware_attributes
15
15
  }
16
16
 
17
17
  DEFAULTS = {
18
18
  default_container_attribute: "json_attributes",
19
- default_rails_attribute: false,
20
19
  unknown_key: :raise
21
20
  }
22
21