attr_json 1.5.0 → 2.0.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: 3cd2566fed014325bee56f5c062080d3c929a790dbb3b287e92b086c2fa3180f
4
- data.tar.gz: ffa8e7b471dce27a2708b12e6a2bf27edb5b20d1345656ca026ecc4b263a01a7
3
+ metadata.gz: 979ced874e097dcf41e911b60320b8cf05dde0a3fce0256b7127d0ad28de4854
4
+ data.tar.gz: cfa4e62ba695c5f952adcef69a47453781891f91e854bbe83cf83d4360364773
5
5
  SHA512:
6
- metadata.gz: f8db6d4211a2dd9f4b9d8a5482b723597958082617e139157c325e8e3b9dddf15216d21bd56daece5d5b3674acdc8e099a22998ad452473a4bf0834774b7a21f
7
- data.tar.gz: 13e2cd5b4b10f67f4ecfc1be8732c6a33a7f7a7fdb561b6d8f4f89ae39c74e4b0b153ae10fdf5d650a239534f5b28cd33750aaff90009eeec8877677e765a935
6
+ metadata.gz: 054c84ddcd6d63b3020656ba64a200c43a8994d28be693a61d37dee5a25352b215e375354ca55ea3cd8f3e80b6427639ba279d2075a52aaa9f9b7a4364506d75
7
+ data.tar.gz: f2fe2af4a190f7e6c7fe18f2fff235158f209929a0ded8d66543833b8d8b2ca55b93dece3363f71b93000e4c174c48ce3516ab291948dad88b109d0d973987a5
@@ -29,26 +29,11 @@ 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
32
  - gemfile: rails_6_0
48
- ruby: 2.6
33
+ ruby: 2.7
49
34
 
50
35
  - gemfile: rails_6_0
51
- ruby: 2.7
36
+ ruby: '3.0'
52
37
 
53
38
  - gemfile: rails_6_1
54
39
  ruby: 2.7
data/Appraisals CHANGED
@@ -1,35 +1,9 @@
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
 
31
4
  gem "rails", ">= 6.0.0", "< 6.1"
32
5
  gem "pg", "~> 1.0"
6
+ gem "rspec-rails", "~> 5.0"
33
7
  end
34
8
 
35
9
  appraise "rails-6-1" do
@@ -59,4 +33,15 @@ appraise "rails-edge" do
59
33
 
60
34
  gem "rails", git: "https://github.com/rails/rails.git", branch: "main"
61
35
  gem "pg", "~> 1.0"
36
+
37
+ # Edge rails, future Rails 7.1 currently allows rack 3 -- but rails itself
38
+ # and some of our other dependencies may not actually work with rack 3 yet,
39
+ # let's test under rack 2. (Nothing in this gem deals with levels as low as rack)
40
+ #
41
+ # Bundler was having trouble resolving unless we specified rackup and rack-session
42
+ # limits too, I think it was a bundler failure, we actually only care about
43
+ # rack < 3 here.
44
+ gem "rack", "~> 2.0"
45
+ gem "rackup", "< 2"
46
+ gem "rack-session", "< 2"
62
47
  end
data/CHANGELOG.md CHANGED
@@ -4,7 +4,59 @@ 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.1...HEAD)
7
+ ## [Unreleased](https://github.com/jrochkind/attr_json/compare/v2.0.0...HEAD)
8
+
9
+ ### Changed
10
+
11
+ *
12
+
13
+ *
14
+
15
+ *
16
+
17
+ ### Added
18
+
19
+ *
20
+
21
+ *
22
+
23
+ *
24
+
25
+
26
+ ## [2.0.0](https://github.com/jrochkind/attr_json/compare/v1.5.0...v2.0.0)
27
+
28
+ 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 1.x and 2.x.
29
+
30
+ ### Removed
31
+
32
+ * `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)
33
+
34
+ * 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
35
+
36
+ ### Changed
37
+
38
+ * 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
39
+
40
+ * 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
41
+
42
+ * 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
43
+
44
+ * 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
45
+
46
+ * 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
47
+
48
+ * 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
49
+
50
+ ### Added
51
+
52
+ * 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
53
+
54
+ ### Fixed
55
+
56
+ * 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
57
+
58
+ * Default nested model validation should allow nils in arrays of models. https://github.com/jrochkind/attr_json/pull/177
59
+
8
60
 
9
61
 
10
62
  ## [1.5.0](https://github.com/jrochkind/attr_json/compare/v1.4.1...v1.5.0)
@@ -17,6 +69,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
69
 
18
70
  * 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
71
 
72
+
73
+
20
74
  ## [1.4.1](https://github.com/jrochkind/attr_json/compare/v1.4.0...v1.4.1)
21
75
 
22
76
  ### 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
- ActiveRecord attributes stored serialized in a json column, super smooth. For Rails 5.0 through 7.0. 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,13 @@ 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
+ You *can* edit nested models "in place", they will be properly saved.
260
+
261
+ m.lang_and_value.lang = "de"
262
+ m.save! # no problem!
263
+
264
+ 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).
265
+
232
266
  ### Model-type defaults
233
267
 
234
268
  If you want to set a default for an AttrJson::Model type, you should use a proc argument for
@@ -386,44 +420,29 @@ Use with Rails form builders is supported pretty painlessly. Including with [sim
386
420
 
387
421
  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
422
 
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
423
  For more info, see doc page on [Use with Forms and Form Builders](doc_src/forms.md).
392
424
 
393
- <a name="dirty"></a>
394
- ## Dirty tracking
425
+ <a name="ar_attributes"></a>
426
+ ## ActiveRecord Attributes and Dirty tracking
395
427
 
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.
428
+ We endeavor to make record-level `attr_json` attributes available as standard ActiveRecord attributes, supporting that full API.
400
429
 
401
- ```ruby
402
- class MyModel < ActiveRecord::Base
403
- include AttrJson::Record
404
- include AttrJson::Record::Dirty
430
+ 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
431
 
406
- attr_json :str, :string
407
- end
432
+ 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
433
 
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
434
+ 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.
435
+
436
+ 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!
437
+
438
+ Note that ActiveRecord DirtyTracking will give you ruby objects, for instance for nested models, you might get:
439
+
440
+ ```ruby
441
+ record_obj.attribute_change_to_be_saved(:nested_model)
442
+ # => [#<object>, #<object>]
423
443
  ```
424
444
 
425
- More options are available, including merging changes from 'ordinary'
426
- ActiveRecord attributes in. See docs on [Dirty Tracking](./doc_src/dirty_tracking.md)
445
+ 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
446
 
428
447
  <a name="why"></a>
429
448
  ## Do you want this?
@@ -478,9 +497,7 @@ to prevent overwriting other updates from processes.
478
497
 
479
498
  ## State of Code, and To Be Done
480
499
 
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.
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.
500
+ 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
501
 
485
502
  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
503
 
@@ -494,13 +511,9 @@ This is still mostly a single-maintainer operation, so has all the sustainabilit
494
511
 
495
512
  ### Possible future features:
496
513
 
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]
514
+ * 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)
500
515
 
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]
502
-
503
- * seamless compatibility with ransack [update: not necessarily prioritized]
516
+ * 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
517
 
505
518
  * Should we give AttrJson::Model a before_serialize hook that you might
506
519
  want to use similar to AR before_save? Should AttrJson::Models
@@ -533,9 +546,9 @@ We use [appraisal](https://github.com/thoughtbot/appraisal) to test with multipl
533
546
 
534
547
  There is a `./bin/console` that will give you a console in the context of attr_json and all it's dependencies, including the combustion rails app, and the models defined there.
535
548
 
536
- ## Acknowledements and Prior Art
549
+ ## Acknowledements, Prior Art, alternatives
537
550
 
538
- * The excellent work [Sean Griffin](https://twitter.com/sgrif) did on ActiveModel::Type
551
+ * The excellent work [sgrif](https://twitter.com/sgrif) did on ActiveModel::Type
539
552
  really lays the groundwork and makes this possible. Plus many other Rails developers.
540
553
  Rails has a reputation for being composed of messy or poorly designed code, but
541
554
  it's some really nice design in Rails that allows us to do some pretty powerful
@@ -555,3 +568,5 @@ There is a `./bin/console` that will give you a console in the context of attr_j
555
568
  haven't looked at it too much.
556
569
 
557
570
  * [store_model](https://github.com/DmitryTsepelev/store_model) was created after `attr_json`, and has some overlapping functionality.
571
+
572
+ * [store_attribute](https://github.com/palkan/store_attribute) is also a more recent addition. while it's not specifically about JSON, it could be used with an underlying JSON coder to give you typed json attributes.
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
 
@@ -5,14 +5,14 @@ source "https://rubygems.org"
5
5
  gem "combustion", "~> 1.0"
6
6
  gem "rails", ">= 6.0.0", "< 6.1"
7
7
  gem "pg", "~> 1.0"
8
- gem "rspec-rails", "~> 4.0"
8
+ gem "rspec-rails", "~> 5.0"
9
9
  gem "simple_form", ">= 4.0"
10
10
  gem "cocoon", ">= 1.2"
11
11
  gem "jquery-rails"
12
12
  gem "coffee-rails"
13
13
  gem "sprockets-rails"
14
14
  gem "capybara", "~> 3.0"
15
- gem "webdrivers", "~> 4.0"
15
+ gem "webdrivers", "~> 5.0"
16
16
  gem "selenium-webdriver"
17
17
  gem "byebug"
18
18
 
@@ -5,14 +5,14 @@ source "https://rubygems.org"
5
5
  gem "combustion", "~> 1.0"
6
6
  gem "rails", "~> 6.1.0"
7
7
  gem "pg", "~> 1.0"
8
- gem "rspec-rails", "~> 4.0"
8
+ gem "rspec-rails", "~> 6.0"
9
9
  gem "simple_form", ">= 4.0"
10
10
  gem "cocoon", ">= 1.2"
11
11
  gem "jquery-rails"
12
12
  gem "coffee-rails"
13
13
  gem "sprockets-rails"
14
14
  gem "capybara", "~> 3.0"
15
- gem "webdrivers", "~> 4.0"
15
+ gem "webdrivers", "~> 5.0"
16
16
  gem "selenium-webdriver"
17
17
  gem "byebug"
18
18
 
@@ -5,14 +5,14 @@ source "https://rubygems.org"
5
5
  gem "combustion", "~> 1.0"
6
6
  gem "rails", "~> 7.0.0"
7
7
  gem "pg", "~> 1.0"
8
- gem "rspec-rails", "~> 4.0"
8
+ gem "rspec-rails", "~> 6.0"
9
9
  gem "simple_form", ">= 4.0"
10
10
  gem "cocoon", ">= 1.2"
11
11
  gem "jquery-rails"
12
12
  gem "coffee-rails"
13
13
  gem "sprockets-rails"
14
14
  gem "capybara", "~> 3.0"
15
- gem "webdrivers", "~> 4.0"
15
+ gem "webdrivers", "~> 5.0"
16
16
  gem "selenium-webdriver"
17
17
  gem "byebug"
18
18
 
@@ -5,15 +5,18 @@ source "https://rubygems.org"
5
5
  gem "combustion", "~> 1.0", github: "pat/combustion"
6
6
  gem "rails", git: "https://github.com/rails/rails.git", branch: "main"
7
7
  gem "pg", "~> 1.0"
8
- gem "rspec-rails", "~> 4.0"
8
+ gem "rspec-rails", "~> 6.0"
9
9
  gem "simple_form", ">= 4.0"
10
10
  gem "cocoon", ">= 1.2"
11
11
  gem "jquery-rails"
12
12
  gem "coffee-rails"
13
13
  gem "sprockets-rails"
14
14
  gem "capybara", "~> 3.0"
15
- gem "webdrivers", "~> 4.0"
15
+ gem "webdrivers", "~> 5.0"
16
16
  gem "selenium-webdriver"
17
17
  gem "byebug"
18
+ gem "rack", "~> 2.0"
19
+ gem "rackup", "< 2"
20
+ gem "rack-session", "< 2"
18
21
 
19
22
  gemspec path: "../"
@@ -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