attr_json 1.5.0 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +0 -21
- data/Appraisals +0 -27
- data/CHANGELOG.md +40 -1
- data/README.md +60 -52
- data/attr_json.gemspec +4 -4
- data/doc_src/forms.md +3 -14
- data/lib/attr_json/attribute_definition.rb +49 -13
- data/lib/attr_json/config.rb +1 -2
- data/lib/attr_json/model.rb +127 -16
- data/lib/attr_json/nested_attributes/writer.rb +4 -6
- data/lib/attr_json/nested_attributes.rb +5 -1
- data/lib/attr_json/record.rb +95 -74
- data/lib/attr_json/type/array.rb +10 -3
- data/lib/attr_json/type/model.rb +13 -4
- data/lib/attr_json/version.rb +1 -1
- data/lib/attr_json.rb +0 -5
- data/playground_models.rb +2 -2
- metadata +9 -14
- data/doc_src/dirty_tracking.md +0 -155
- data/gemfiles/rails_5_0.gemfile +0 -20
- data/gemfiles/rails_5_1.gemfile +0 -19
- data/gemfiles/rails_5_2.gemfile +0 -19
- data/lib/attr_json/record/dirty.rb +0 -287
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11d5f5f1403cf8388ab7b5b14494a68ff5bdb11c1cd739ae81f78da5b97dbbbc
|
4
|
+
data.tar.gz: d787c2b06cc01478cd764201a204e85312bc9204f8c54b9bdbe2c5e597ac00b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8dd9c059292d1fba076323f101f0a3445986db3b41ef6099a4f33a583dd1c8bb1dc58e42fba1f35d74fe87eeb1f3fe4253959377cb98c322fa9e22a99c5d43db
|
7
|
+
data.tar.gz: d145d01c73273d4fd1f089b95287fb67adb3c1f6ed12a5c5317a879f230430b760b3abbdf0c27626a2560e612a6823e239ab849ec557a2b412564e2a6bd5ef1c
|
data/.github/workflows/ci.yml
CHANGED
@@ -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
|
|
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,44 @@ 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/
|
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
|
+
|
8
45
|
|
9
46
|
|
10
47
|
## [1.5.0](https://github.com/jrochkind/attr_json/compare/v1.4.1...v1.5.0)
|
@@ -17,6 +54,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
17
54
|
|
18
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
|
19
56
|
|
57
|
+
|
58
|
+
|
20
59
|
## [1.4.1](https://github.com/jrochkind/attr_json/compare/v1.4.0...v1.4.1)
|
21
60
|
|
22
61
|
### Fixed
|
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
|
-
|
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 :
|
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
|
-
|
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
|
-
|
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="
|
394
|
-
## Dirty tracking
|
420
|
+
<a name="ar_attributes"></a>
|
421
|
+
## ActiveRecord Attributes and Dirty tracking
|
395
422
|
|
396
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
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
|
-
|
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,9 +492,7 @@ 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
|
482
|
-
|
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.
|
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.
|
484
496
|
|
485
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
|
|
@@ -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
|
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
|
-
*
|
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
|
-
|
15
|
-
|
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.
|
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", ">=
|
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
|
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
|
-
|
42
|
-
|
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
|
data/lib/attr_json/config.rb
CHANGED
@@ -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
|
|