iknow_view_models 3.1.8 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +6 -6
- data/.rubocop.yml +18 -0
- data/Appraisals +6 -6
- data/Gemfile +6 -2
- data/Rakefile +5 -5
- data/gemfiles/rails_5_2.gemfile +5 -5
- data/gemfiles/rails_6_0.gemfile +9 -0
- data/iknow_view_models.gemspec +40 -38
- data/lib/iknow_view_models.rb +9 -7
- data/lib/iknow_view_models/version.rb +1 -1
- data/lib/view_model.rb +31 -17
- data/lib/view_model/access_control.rb +5 -2
- data/lib/view_model/access_control/composed.rb +10 -9
- data/lib/view_model/access_control/open.rb +2 -0
- data/lib/view_model/access_control/read_only.rb +2 -0
- data/lib/view_model/access_control/tree.rb +11 -6
- data/lib/view_model/access_control_error.rb +4 -1
- data/lib/view_model/active_record.rb +17 -15
- data/lib/view_model/active_record/association_data.rb +2 -1
- data/lib/view_model/active_record/association_manipulation.rb +6 -4
- data/lib/view_model/active_record/cache.rb +114 -34
- data/lib/view_model/active_record/cache/cacheable_view.rb +2 -2
- data/lib/view_model/active_record/collection_nested_controller.rb +3 -3
- data/lib/view_model/active_record/controller.rb +68 -1
- data/lib/view_model/active_record/controller_base.rb +4 -1
- data/lib/view_model/active_record/nested_controller_base.rb +1 -0
- data/lib/view_model/active_record/update_context.rb +8 -6
- data/lib/view_model/active_record/update_data.rb +32 -30
- data/lib/view_model/active_record/update_operation.rb +17 -13
- data/lib/view_model/active_record/visitor.rb +0 -1
- data/lib/view_model/after_transaction_runner.rb +0 -1
- data/lib/view_model/callbacks.rb +3 -1
- data/lib/view_model/controller.rb +13 -3
- data/lib/view_model/deserialization_error.rb +15 -12
- data/lib/view_model/error.rb +12 -10
- data/lib/view_model/error_view.rb +3 -1
- data/lib/view_model/migratable_view.rb +78 -0
- data/lib/view_model/migration.rb +48 -0
- data/lib/view_model/migration/no_path_error.rb +26 -0
- data/lib/view_model/migration/one_way_error.rb +24 -0
- data/lib/view_model/migration/unspecified_version_error.rb +24 -0
- data/lib/view_model/migrator.rb +108 -0
- data/lib/view_model/record.rb +15 -14
- data/lib/view_model/reference.rb +3 -1
- data/lib/view_model/references.rb +8 -5
- data/lib/view_model/registry.rb +14 -2
- data/lib/view_model/schemas.rb +9 -4
- data/lib/view_model/serialization_error.rb +4 -1
- data/lib/view_model/serialize_context.rb +4 -4
- data/lib/view_model/test_helpers.rb +8 -3
- data/lib/view_model/test_helpers/arvm_builder.rb +21 -15
- data/lib/view_model/traversal_context.rb +2 -1
- data/nix/dependencies.nix +5 -0
- data/nix/gem/generate.rb +2 -1
- data/shell.nix +8 -3
- data/test/.rubocop.yml +14 -0
- data/test/helpers/arvm_test_models.rb +12 -9
- data/test/helpers/arvm_test_utilities.rb +5 -3
- data/test/helpers/controller_test_helpers.rb +55 -32
- data/test/helpers/match_enumerator.rb +1 -0
- data/test/helpers/query_logging.rb +2 -1
- data/test/helpers/test_access_control.rb +5 -3
- data/test/helpers/viewmodel_spec_helpers.rb +88 -22
- data/test/unit/view_model/access_control_test.rb +144 -144
- data/test/unit/view_model/active_record/alias_test.rb +15 -13
- data/test/unit/view_model/active_record/belongs_to_test.rb +40 -39
- data/test/unit/view_model/active_record/cache_test.rb +68 -31
- data/test/unit/view_model/active_record/cloner_test.rb +67 -63
- data/test/unit/view_model/active_record/controller_test.rb +113 -65
- data/test/unit/view_model/active_record/counter_test.rb +10 -9
- data/test/unit/view_model/active_record/customization_test.rb +59 -58
- data/test/unit/view_model/active_record/has_many_test.rb +112 -111
- data/test/unit/view_model/active_record/has_many_through_poly_test.rb +15 -14
- data/test/unit/view_model/active_record/has_many_through_test.rb +33 -38
- data/test/unit/view_model/active_record/has_one_test.rb +37 -36
- data/test/unit/view_model/active_record/migration_test.rb +161 -0
- data/test/unit/view_model/active_record/namespacing_test.rb +19 -17
- data/test/unit/view_model/active_record/poly_test.rb +44 -45
- data/test/unit/view_model/active_record/shared_test.rb +30 -28
- data/test/unit/view_model/active_record/version_test.rb +9 -7
- data/test/unit/view_model/active_record_test.rb +72 -72
- data/test/unit/view_model/callbacks_test.rb +19 -15
- data/test/unit/view_model/controller_test.rb +4 -2
- data/test/unit/view_model/record_test.rb +158 -145
- data/test/unit/view_model/registry_test.rb +38 -0
- data/test/unit/view_model/traversal_context_test.rb +4 -5
- data/test/unit/view_model_test.rb +18 -16
- metadata +38 -12
- data/.travis.yml +0 -31
- data/appveyor.yml +0 -22
- data/gemfiles/rails_6_0_beta.gemfile +0 -9
| @@ -1,14 +1,16 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require "minitest/unit"
         | 
| 3 | 
            -
            require "minitest/hooks"
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 4 2 |  | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 3 | 
            +
            require 'minitest/autorun'
         | 
| 4 | 
            +
            require 'minitest/unit'
         | 
| 5 | 
            +
            require 'minitest/hooks'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            require_relative '../../../helpers/arvm_test_models'
         | 
| 8 | 
            +
            require_relative '../../../helpers/viewmodel_spec_helpers'
         | 
| 7 9 |  | 
| 8 10 | 
             
            # MiniTest::Spec.register_spec_type(/./, Minitest::HooksSpec)
         | 
| 9 11 |  | 
| 10 | 
            -
            require  | 
| 11 | 
            -
            require  | 
| 12 | 
            +
            require 'view_model'
         | 
| 13 | 
            +
            require 'view_model/active_record'
         | 
| 12 14 |  | 
| 13 15 | 
             
            class ViewModel::ActiveRecord
         | 
| 14 16 | 
             
              class ClonerTest < ActiveSupport::TestCase
         | 
| @@ -18,7 +20,7 @@ class ViewModel::ActiveRecord | |
| 18 20 | 
             
                let(:viewmodel) { create_viewmodel! }
         | 
| 19 21 | 
             
                let(:model)     { viewmodel.model }
         | 
| 20 22 |  | 
| 21 | 
            -
                describe  | 
| 23 | 
            +
                describe 'with single model' do
         | 
| 22 24 | 
             
                  include ViewModelSpecHelpers::Single
         | 
| 23 25 |  | 
| 24 26 | 
             
                  def model_attributes
         | 
| @@ -26,15 +28,15 @@ class ViewModel::ActiveRecord | |
| 26 28 | 
             
                  end
         | 
| 27 29 |  | 
| 28 30 | 
             
                  def new_model
         | 
| 29 | 
            -
                    model_class.new(name:  | 
| 31 | 
            +
                    model_class.new(name: 'a', nonview: 'b')
         | 
| 30 32 | 
             
                  end
         | 
| 31 33 |  | 
| 32 | 
            -
                  it  | 
| 34 | 
            +
                  it 'persists the test setup' do
         | 
| 33 35 | 
             
                    assert(viewmodel.model.persisted?)
         | 
| 34 36 | 
             
                    refute(viewmodel.model.new_record?)
         | 
| 35 37 | 
             
                  end
         | 
| 36 38 |  | 
| 37 | 
            -
                  it  | 
| 39 | 
            +
                  it 'can clone the model' do
         | 
| 38 40 | 
             
                    clone_model = Cloner.new.clone(viewmodel)
         | 
| 39 41 | 
             
                    assert(clone_model.new_record?)
         | 
| 40 42 | 
             
                    assert_nil(clone_model.id)
         | 
| @@ -45,75 +47,75 @@ class ViewModel::ActiveRecord | |
| 45 47 | 
             
                  end
         | 
| 46 48 |  | 
| 47 49 | 
             
                  class IgnoreParentCloner < Cloner
         | 
| 48 | 
            -
                    def visit_model_view( | 
| 50 | 
            +
                    def visit_model_view(_node, _model)
         | 
| 49 51 | 
             
                      ignore!
         | 
| 50 52 | 
             
                    end
         | 
| 51 53 | 
             
                  end
         | 
| 52 54 |  | 
| 53 | 
            -
                  it  | 
| 55 | 
            +
                  it 'can ignore a model' do
         | 
| 54 56 | 
             
                    clone_model = IgnoreParentCloner.new.clone(viewmodel)
         | 
| 55 57 | 
             
                    assert_nil(clone_model)
         | 
| 56 58 | 
             
                  end
         | 
| 57 59 |  | 
| 58 60 | 
             
                  class IgnoreAllCloner < Cloner
         | 
| 59 | 
            -
                    def pre_visit( | 
| 61 | 
            +
                    def pre_visit(_node, _model)
         | 
| 60 62 | 
             
                      ignore!
         | 
| 61 63 | 
             
                    end
         | 
| 62 64 | 
             
                  end
         | 
| 63 65 |  | 
| 64 | 
            -
                  it  | 
| 66 | 
            +
                  it 'can ignore a model in pre-visit' do
         | 
| 65 67 | 
             
                    clone_model = IgnoreAllCloner.new.clone(viewmodel)
         | 
| 66 68 | 
             
                    assert_nil(clone_model)
         | 
| 67 69 | 
             
                  end
         | 
| 68 70 |  | 
| 69 71 | 
             
                  class AlterAttributeCloner < Cloner
         | 
| 70 | 
            -
                    def visit_model_view( | 
| 71 | 
            -
                      model.name =  | 
| 72 | 
            +
                    def visit_model_view(_node, model)
         | 
| 73 | 
            +
                      model.name = 'changed'
         | 
| 72 74 | 
             
                    end
         | 
| 73 75 | 
             
                  end
         | 
| 74 76 |  | 
| 75 | 
            -
                  it  | 
| 77 | 
            +
                  it 'can alter a model attribute' do
         | 
| 76 78 | 
             
                    clone_model = AlterAttributeCloner.new.clone(viewmodel)
         | 
| 77 79 | 
             
                    assert(clone_model.new_record?)
         | 
| 78 80 | 
             
                    assert_nil(clone_model.id)
         | 
| 79 | 
            -
                    assert_equal( | 
| 80 | 
            -
                    refute_equal( | 
| 81 | 
            +
                    assert_equal('changed', clone_model.name)
         | 
| 82 | 
            +
                    refute_equal('changed', model.name)
         | 
| 81 83 | 
             
                    assert_equal(model.nonview, clone_model.nonview)
         | 
| 82 84 | 
             
                    clone_model.save!
         | 
| 83 85 | 
             
                    refute_equal(model, clone_model)
         | 
| 84 86 | 
             
                  end
         | 
| 85 87 |  | 
| 86 88 | 
             
                  class PostAlterAttributeCloner < Cloner
         | 
| 87 | 
            -
                    def end_visit_model_view( | 
| 88 | 
            -
                      model.name =  | 
| 89 | 
            +
                    def end_visit_model_view(_node, model)
         | 
| 90 | 
            +
                      model.name = 'changed'
         | 
| 89 91 | 
             
                    end
         | 
| 90 92 | 
             
                  end
         | 
| 91 93 |  | 
| 92 | 
            -
                  it  | 
| 94 | 
            +
                  it 'can alter a model attribute post-visit' do
         | 
| 93 95 | 
             
                    clone_model = PostAlterAttributeCloner.new.clone(viewmodel)
         | 
| 94 96 | 
             
                    assert(clone_model.new_record?)
         | 
| 95 97 | 
             
                    assert_nil(clone_model.id)
         | 
| 96 | 
            -
                    assert_equal( | 
| 97 | 
            -
                    refute_equal( | 
| 98 | 
            +
                    assert_equal('changed', clone_model.name)
         | 
| 99 | 
            +
                    refute_equal('changed', model.name)
         | 
| 98 100 | 
             
                    assert_equal(model.nonview, clone_model.nonview)
         | 
| 99 101 | 
             
                    clone_model.save!
         | 
| 100 102 | 
             
                    refute_equal(model, clone_model)
         | 
| 101 103 | 
             
                  end
         | 
| 102 104 | 
             
                end
         | 
| 103 105 |  | 
| 104 | 
            -
                describe  | 
| 106 | 
            +
                describe 'with a child' do
         | 
| 105 107 | 
             
                  def new_child_model
         | 
| 106 | 
            -
                    child_model_class.new(name:  | 
| 108 | 
            +
                    child_model_class.new(name: 'b')
         | 
| 107 109 | 
             
                  end
         | 
| 108 110 |  | 
| 109 111 | 
             
                  def new_model
         | 
| 110 | 
            -
                    model_class.new(name:  | 
| 112 | 
            +
                    model_class.new(name: 'a', child: new_child_model)
         | 
| 111 113 | 
             
                  end
         | 
| 112 114 |  | 
| 113 115 | 
             
                  module BehavesLikeConstructingAChild
         | 
| 114 116 | 
             
                    extend ActiveSupport::Concern
         | 
| 115 117 | 
             
                    included do
         | 
| 116 | 
            -
                      it  | 
| 118 | 
            +
                      it 'persists the test setup' do
         | 
| 117 119 | 
             
                        assert(viewmodel.model.persisted?)
         | 
| 118 120 | 
             
                        refute(viewmodel.model.new_record?)
         | 
| 119 121 | 
             
                        assert(viewmodel.model.child.persisted?)
         | 
| @@ -123,7 +125,7 @@ class ViewModel::ActiveRecord | |
| 123 125 | 
             
                  end
         | 
| 124 126 |  | 
| 125 127 | 
             
                  class IgnoreChildAssociationCloner < Cloner
         | 
| 126 | 
            -
                    def visit_model_view( | 
| 128 | 
            +
                    def visit_model_view(_node, _model)
         | 
| 127 129 | 
             
                      ignore_association!(:child)
         | 
| 128 130 | 
             
                    end
         | 
| 129 131 | 
             
                  end
         | 
| @@ -131,7 +133,7 @@ class ViewModel::ActiveRecord | |
| 131 133 | 
             
                  module BehavesLikeCloningAChild
         | 
| 132 134 | 
             
                    extend ActiveSupport::Concern
         | 
| 133 135 | 
             
                    included do
         | 
| 134 | 
            -
                      it  | 
| 136 | 
            +
                      it 'can clone the model and child' do
         | 
| 135 137 | 
             
                        clone_model = Cloner.new.clone(viewmodel)
         | 
| 136 138 |  | 
| 137 139 | 
             
                        assert(clone_model.new_record?)
         | 
| @@ -148,7 +150,7 @@ class ViewModel::ActiveRecord | |
| 148 150 | 
             
                        refute_equal(model.child, clone_model.child)
         | 
| 149 151 | 
             
                      end
         | 
| 150 152 |  | 
| 151 | 
            -
                      it  | 
| 153 | 
            +
                      it 'can ignore the child association' do
         | 
| 152 154 | 
             
                        clone_model = IgnoreChildAssociationCloner.new.clone(viewmodel)
         | 
| 153 155 |  | 
| 154 156 | 
             
                        assert(clone_model.new_record?)
         | 
| @@ -160,66 +162,67 @@ class ViewModel::ActiveRecord | |
| 160 162 | 
             
                    end
         | 
| 161 163 | 
             
                  end
         | 
| 162 164 |  | 
| 163 | 
            -
                  describe  | 
| 165 | 
            +
                  describe 'as belongs_to' do
         | 
| 164 166 | 
             
                    include ViewModelSpecHelpers::ParentAndBelongsToChild
         | 
| 165 167 | 
             
                    include BehavesLikeConstructingAChild
         | 
| 166 168 | 
             
                    include BehavesLikeCloningAChild
         | 
| 167 169 | 
             
                  end
         | 
| 168 170 |  | 
| 169 | 
            -
                  describe  | 
| 171 | 
            +
                  describe 'as has_one' do
         | 
| 170 172 | 
             
                    include ViewModelSpecHelpers::ParentAndHasOneChild
         | 
| 171 173 | 
             
                    include BehavesLikeConstructingAChild
         | 
| 172 174 | 
             
                    include BehavesLikeCloningAChild
         | 
| 173 175 | 
             
                  end
         | 
| 174 176 |  | 
| 175 | 
            -
                  describe  | 
| 177 | 
            +
                  describe 'as belongs_to shared child' do
         | 
| 176 178 | 
             
                    include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
         | 
| 177 179 | 
             
                    include BehavesLikeConstructingAChild
         | 
| 178 | 
            -
                    it "can clone the model but not the child" do
         | 
| 179 | 
            -
                        clone_model = Cloner.new.clone(viewmodel)
         | 
| 180 180 |  | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
                        assert_equal(model.name, clone_model.name)
         | 
| 181 | 
            +
                    it 'can clone the model but not the child' do
         | 
| 182 | 
            +
                      clone_model = Cloner.new.clone(viewmodel)
         | 
| 184 183 |  | 
| 185 | 
            -
             | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 184 | 
            +
                      assert(clone_model.new_record?)
         | 
| 185 | 
            +
                      assert_nil(clone_model.id)
         | 
| 186 | 
            +
                      assert_equal(model.name, clone_model.name)
         | 
| 188 187 |  | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 188 | 
            +
                      clone_child = clone_model.child
         | 
| 189 | 
            +
                      refute(clone_child.new_record?)
         | 
| 190 | 
            +
                      assert_equal(model.child, clone_child)
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                      clone_model.save!
         | 
| 193 | 
            +
                      refute_equal(model, clone_model)
         | 
| 194 | 
            +
                      assert_equal(model.child, clone_model.child)
         | 
| 195 | 
            +
                    end
         | 
| 193 196 | 
             
                  end
         | 
| 194 197 | 
             
                end
         | 
| 195 198 |  | 
| 196 199 | 
             
                class IgnoreChildrenAssociationCloner < Cloner
         | 
| 197 | 
            -
                  def visit_model_view( | 
| 200 | 
            +
                  def visit_model_view(_node, _model)
         | 
| 198 201 | 
             
                    ignore_association!(:children)
         | 
| 199 202 | 
             
                  end
         | 
| 200 203 | 
             
                end
         | 
| 201 204 |  | 
| 202 | 
            -
                describe  | 
| 205 | 
            +
                describe 'with has_many children' do
         | 
| 203 206 | 
             
                  include ViewModelSpecHelpers::ParentAndHasManyChildren
         | 
| 204 207 | 
             
                  def new_child_models
         | 
| 205 | 
            -
                    [ | 
| 208 | 
            +
                    ['b', 'c'].map { |n| child_model_class.new(name: n) }
         | 
| 206 209 | 
             
                  end
         | 
| 207 210 |  | 
| 208 211 | 
             
                  def new_model
         | 
| 209 | 
            -
                    model_class.new(name:  | 
| 212 | 
            +
                    model_class.new(name: 'a', children: new_child_models)
         | 
| 210 213 | 
             
                  end
         | 
| 211 214 |  | 
| 212 | 
            -
                  it  | 
| 215 | 
            +
                  it 'persists the test setup' do
         | 
| 213 216 | 
             
                    assert(viewmodel.model.persisted?)
         | 
| 214 217 | 
             
                    refute(viewmodel.model.new_record?)
         | 
| 215 218 | 
             
                    assert_equal(2, viewmodel.model.children.size)
         | 
| 216 | 
            -
                    viewmodel.model.children.each do | | 
| 219 | 
            +
                    viewmodel.model.children.each do |child|
         | 
| 217 220 | 
             
                      assert(child.persisted?)
         | 
| 218 221 | 
             
                      refute(child.new_record?)
         | 
| 219 222 | 
             
                    end
         | 
| 220 223 | 
             
                  end
         | 
| 221 224 |  | 
| 222 | 
            -
                  it  | 
| 225 | 
            +
                  it 'can clone the model' do
         | 
| 223 226 | 
             
                    clone_model = Cloner.new.clone(viewmodel)
         | 
| 224 227 |  | 
| 225 228 | 
             
                    assert(clone_model.new_record?)
         | 
| @@ -244,9 +247,10 @@ class ViewModel::ActiveRecord | |
| 244 247 | 
             
                  class IgnoreFirstChildCloner < Cloner
         | 
| 245 248 | 
             
                    def initialize
         | 
| 246 249 | 
             
                      @ignored_first = false
         | 
| 250 | 
            +
                      super
         | 
| 247 251 | 
             
                    end
         | 
| 248 252 |  | 
| 249 | 
            -
                    def visit_child_view( | 
| 253 | 
            +
                    def visit_child_view(_node, _model)
         | 
| 250 254 | 
             
                      unless @ignored_first
         | 
| 251 255 | 
             
                        @ignored_first = true
         | 
| 252 256 | 
             
                        ignore!
         | 
| @@ -254,7 +258,7 @@ class ViewModel::ActiveRecord | |
| 254 258 | 
             
                    end
         | 
| 255 259 | 
             
                  end
         | 
| 256 260 |  | 
| 257 | 
            -
                  it  | 
| 261 | 
            +
                  it 'can ignore subset of children' do
         | 
| 258 262 | 
             
                    clone_model = IgnoreFirstChildCloner.new.clone(viewmodel)
         | 
| 259 263 |  | 
| 260 264 | 
             
                    assert(clone_model.new_record?)
         | 
| @@ -265,7 +269,7 @@ class ViewModel::ActiveRecord | |
| 265 269 | 
             
                    assert_equal(model.children[1].name, clone_model.children[0].name)
         | 
| 266 270 | 
             
                  end
         | 
| 267 271 |  | 
| 268 | 
            -
                  it  | 
| 272 | 
            +
                  it 'can ignore the children association' do
         | 
| 269 273 | 
             
                    clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
         | 
| 270 274 |  | 
| 271 275 | 
             
                    assert(clone_model.new_record?)
         | 
| @@ -276,19 +280,19 @@ class ViewModel::ActiveRecord | |
| 276 280 | 
             
                  end
         | 
| 277 281 | 
             
                end
         | 
| 278 282 |  | 
| 279 | 
            -
                describe  | 
| 283 | 
            +
                describe 'with has_many_through shared children' do
         | 
| 280 284 | 
             
                  include ViewModelSpecHelpers::ParentAndHasManyThroughChildren
         | 
| 281 285 | 
             
                  def new_model_children
         | 
| 282 | 
            -
                    [ | 
| 286 | 
            +
                    ['b', 'c'].map.with_index do |n, i|
         | 
| 283 287 | 
             
                      join_model_class.new(child: child_model_class.new(name: n), position: i)
         | 
| 284 288 | 
             
                    end
         | 
| 285 289 | 
             
                  end
         | 
| 286 290 |  | 
| 287 291 | 
             
                  def new_model
         | 
| 288 | 
            -
                    model_class.new( | 
| 292 | 
            +
                    model_class.new(name: 'a', model_children: new_model_children)
         | 
| 289 293 | 
             
                  end
         | 
| 290 294 |  | 
| 291 | 
            -
                  it  | 
| 295 | 
            +
                  it 'persists the test setup' do
         | 
| 292 296 | 
             
                    assert(viewmodel.model.persisted?)
         | 
| 293 297 | 
             
                    refute(viewmodel.model.new_record?)
         | 
| 294 298 | 
             
                    assert_equal(2, viewmodel.model.model_children.size)
         | 
| @@ -301,7 +305,7 @@ class ViewModel::ActiveRecord | |
| 301 305 | 
             
                    end
         | 
| 302 306 | 
             
                  end
         | 
| 303 307 |  | 
| 304 | 
            -
                  it  | 
| 308 | 
            +
                  it 'can clone the model and join model but not the child' do
         | 
| 305 309 | 
             
                    clone_model = Cloner.new.clone(viewmodel)
         | 
| 306 310 |  | 
| 307 311 | 
             
                    assert(clone_model.new_record?)
         | 
| @@ -325,7 +329,7 @@ class ViewModel::ActiveRecord | |
| 325 329 | 
             
                    end
         | 
| 326 330 | 
             
                  end
         | 
| 327 331 |  | 
| 328 | 
            -
                  it  | 
| 332 | 
            +
                  it 'can ignore the children association' do
         | 
| 329 333 | 
             
                    clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
         | 
| 330 334 |  | 
| 331 335 | 
             
                    assert(clone_model.new_record?)
         | 
| @@ -1,14 +1,14 @@ | |
| 1 | 
            -
            #  | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require  | 
| 3 | 
            +
            require 'minitest/autorun'
         | 
| 4 4 | 
             
            require 'minitest/unit'
         | 
| 5 5 | 
             
            require 'minitest/hooks'
         | 
| 6 6 |  | 
| 7 | 
            -
            require  | 
| 8 | 
            -
            require  | 
| 7 | 
            +
            require 'view_model'
         | 
| 8 | 
            +
            require 'view_model/active_record'
         | 
| 9 9 |  | 
| 10 | 
            -
            require_relative  | 
| 11 | 
            -
            require_relative  | 
| 10 | 
            +
            require_relative '../../../helpers/controller_test_helpers'
         | 
| 11 | 
            +
            require_relative '../../../helpers/callback_tracer'
         | 
| 12 12 |  | 
| 13 13 | 
             
            class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
         | 
| 14 14 | 
             
              include ARVMTestUtilities
         | 
| @@ -88,7 +88,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 88 88 | 
             
                super
         | 
| 89 89 | 
             
                @parent = Parent.create(name: 'p',
         | 
| 90 90 | 
             
                                        children: [Child.new(name: 'c1', position: 1.0),
         | 
| 91 | 
            -
                                                   Child.new(name: 'c2', position: 2.0)],
         | 
| 91 | 
            +
                                                   Child.new(name: 'c2', position: 2.0),],
         | 
| 92 92 | 
             
                                        label: Label.new,
         | 
| 93 93 | 
             
                                        target: Target.new)
         | 
| 94 94 |  | 
| @@ -98,7 +98,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 98 98 | 
             
              end
         | 
| 99 99 |  | 
| 100 100 | 
             
              def test_show
         | 
| 101 | 
            -
                parentcontroller = ParentController.new(id: @parent.id)
         | 
| 101 | 
            +
                parentcontroller = ParentController.new(params: { id: @parent.id })
         | 
| 102 102 | 
             
                parentcontroller.invoke(:show)
         | 
| 103 103 |  | 
| 104 104 | 
             
                assert_equal({ 'data' => @parent_view.to_hash },
         | 
| @@ -109,8 +109,41 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 109 109 | 
             
                assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
         | 
| 110 110 | 
             
              end
         | 
| 111 111 |  | 
| 112 | 
            +
              def test_migrated_show
         | 
| 113 | 
            +
                parentcontroller = ParentController.new(
         | 
| 114 | 
            +
                  params: { id: @parent.id },
         | 
| 115 | 
            +
                  headers: { 'X-ViewModel-Versions' => { ParentView.view_name => 1 }.to_json })
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                parentcontroller.invoke(:show)
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                expected_view = @parent_view.to_hash
         | 
| 120 | 
            +
                                  .except('name')
         | 
| 121 | 
            +
                                  .merge('old_name' => @parent.name,
         | 
| 122 | 
            +
                                         ViewModel::VERSION_ATTRIBUTE => 1,
         | 
| 123 | 
            +
                                         ViewModel::MIGRATED_ATTRIBUTE => true)
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                assert_equal({ 'data' => expected_view },
         | 
| 126 | 
            +
                             parentcontroller.hash_response)
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                assert_equal(200, parentcontroller.status)
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
              def test_invalid_migration_header
         | 
| 134 | 
            +
                parentcontroller = ParentController.new(
         | 
| 135 | 
            +
                  params: { id: @parent.id },
         | 
| 136 | 
            +
                  headers: { 'X-ViewModel-Versions' => 'not a json' })
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                parentcontroller.invoke(:show)
         | 
| 139 | 
            +
                assert_equal(400, parentcontroller.status)
         | 
| 140 | 
            +
                assert_match(/Invalid JSON/i,
         | 
| 141 | 
            +
                             parentcontroller.hash_response['error']['detail'],
         | 
| 142 | 
            +
                             'json error propagated')
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
             | 
| 112 145 | 
             
              def test_index
         | 
| 113 | 
            -
                p2      = Parent.create(name:  | 
| 146 | 
            +
                p2      = Parent.create(name: 'p2')
         | 
| 114 147 | 
             
                p2_view = ParentView.new(p2)
         | 
| 115 148 |  | 
| 116 149 | 
             
                parentcontroller = ParentController.new
         | 
| @@ -119,7 +152,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 119 152 | 
             
                assert_equal(200, parentcontroller.status)
         | 
| 120 153 |  | 
| 121 154 | 
             
                assert_equal(parentcontroller.hash_response,
         | 
| 122 | 
            -
                             {  | 
| 155 | 
            +
                             { 'data' => [@parent_view.to_hash, p2_view.to_hash] })
         | 
| 123 156 |  | 
| 124 157 | 
             
                assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
         | 
| 125 158 | 
             
              end
         | 
| @@ -131,10 +164,10 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 131 164 | 
             
                    'label'    => { '_type' => 'Label', 'text' => 'l' },
         | 
| 132 165 | 
             
                    'target'   => { '_type' => 'Target', 'text' => 't' },
         | 
| 133 166 | 
             
                    'children' => [{ '_type' => 'Child', 'name' => 'c1' },
         | 
| 134 | 
            -
                                   { '_type' => 'Child', 'name' => 'c2' }]
         | 
| 167 | 
            +
                                   { '_type' => 'Child', 'name' => 'c2' },],
         | 
| 135 168 | 
             
                }
         | 
| 136 169 |  | 
| 137 | 
            -
                parentcontroller = ParentController.new(data: data)
         | 
| 170 | 
            +
                parentcontroller = ParentController.new(params: { data: data })
         | 
| 138 171 | 
             
                parentcontroller.invoke(:create)
         | 
| 139 172 |  | 
| 140 173 | 
             
                assert_equal(200, parentcontroller.status)
         | 
| @@ -148,15 +181,31 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 148 181 | 
             
                assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
         | 
| 149 182 | 
             
              end
         | 
| 150 183 |  | 
| 184 | 
            +
              def test_migrated_create
         | 
| 185 | 
            +
                data = {
         | 
| 186 | 
            +
                  '_type'    => 'Parent',
         | 
| 187 | 
            +
                  '_version' => 1,
         | 
| 188 | 
            +
                  'old_name' => 'p2',
         | 
| 189 | 
            +
                }
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                parentcontroller = ParentController.new(params: { data: data, versions: { ParentView.view_name => 1 } })
         | 
| 192 | 
            +
                parentcontroller.invoke(:create)
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                assert_equal(200, parentcontroller.status)
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                p2 = Parent.where(name: 'p2').first
         | 
| 197 | 
            +
                assert(p2.present?, 'p2 created')
         | 
| 198 | 
            +
              end
         | 
| 199 | 
            +
             | 
| 151 200 | 
             
              def test_create_empty
         | 
| 152 | 
            -
                parentcontroller = ParentController.new(data: [])
         | 
| 201 | 
            +
                parentcontroller = ParentController.new(params: { data: [] })
         | 
| 153 202 | 
             
                parentcontroller.invoke(:create)
         | 
| 154 203 |  | 
| 155 204 | 
             
                assert_equal(400, parentcontroller.status)
         | 
| 156 205 | 
             
              end
         | 
| 157 206 |  | 
| 158 207 | 
             
              def test_create_invalid
         | 
| 159 | 
            -
                parentcontroller = ParentController.new(data: 42)
         | 
| 208 | 
            +
                parentcontroller = ParentController.new(params: { data: 42 })
         | 
| 160 209 | 
             
                parentcontroller.invoke(:create)
         | 
| 161 210 |  | 
| 162 211 | 
             
                assert_equal(400, parentcontroller.status)
         | 
| @@ -167,7 +216,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 167 216 | 
             
                         '_type' => 'Parent',
         | 
| 168 217 | 
             
                         'name'  => 'new' }
         | 
| 169 218 |  | 
| 170 | 
            -
                parentcontroller = ParentController.new(id: @parent.id, data: data)
         | 
| 219 | 
            +
                parentcontroller = ParentController.new(params: { id: @parent.id, data: data })
         | 
| 171 220 | 
             
                parentcontroller.invoke(:create)
         | 
| 172 221 |  | 
| 173 222 | 
             
                assert_equal(200, parentcontroller.status)
         | 
| @@ -182,7 +231,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 182 231 | 
             
              end
         | 
| 183 232 |  | 
| 184 233 | 
             
              def test_destroy
         | 
| 185 | 
            -
                parentcontroller = ParentController.new(id: @parent.id)
         | 
| 234 | 
            +
                parentcontroller = ParentController.new(params: { id: @parent.id })
         | 
| 186 235 | 
             
                parentcontroller.invoke(:destroy)
         | 
| 187 236 |  | 
| 188 237 | 
             
                assert_equal(200, parentcontroller.status)
         | 
| @@ -196,7 +245,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 196 245 | 
             
              end
         | 
| 197 246 |  | 
| 198 247 | 
             
              def test_show_missing
         | 
| 199 | 
            -
                parentcontroller = ParentController.new(id: 9999)
         | 
| 248 | 
            +
                parentcontroller = ParentController.new(params: { id: 9999 })
         | 
| 200 249 | 
             
                parentcontroller.invoke(:show)
         | 
| 201 250 |  | 
| 202 251 | 
             
                assert_equal(404, parentcontroller.status)
         | 
| @@ -206,10 +255,10 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 206 255 | 
             
                                 'status' => 404,
         | 
| 207 256 | 
             
                                 'detail' => "Couldn't find Parent(s) with id(s)=[9999]",
         | 
| 208 257 | 
             
                                 'title' => nil,
         | 
| 209 | 
            -
                                 'code' | 
| 210 | 
            -
                                 'meta' => { 'nodes' => [{ '_type' =>  | 
| 258 | 
            +
                                 'code' => 'DeserializationError.NotFound',
         | 
| 259 | 
            +
                                 'meta' => { 'nodes' => [{ '_type' => 'Parent', 'id' => 9999 }] },
         | 
| 211 260 | 
             
                                 'exception' => nil,
         | 
| 212 | 
            -
                                 'causes' => nil }},
         | 
| 261 | 
            +
                                 'causes' => nil } },
         | 
| 213 262 | 
             
                             parentcontroller.hash_response)
         | 
| 214 263 | 
             
              end
         | 
| 215 264 |  | 
| @@ -218,7 +267,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 218 267 | 
             
                         'children' => [{ '_type' => 'Child',
         | 
| 219 268 | 
             
                                          'age'   => 42 }] }
         | 
| 220 269 |  | 
| 221 | 
            -
                parentcontroller = ParentController.new(data: data)
         | 
| 270 | 
            +
                parentcontroller = ParentController.new(params: { data: data })
         | 
| 222 271 | 
             
                parentcontroller.invoke(:create)
         | 
| 223 272 |  | 
| 224 273 | 
             
                assert_equal({ 'error' => {
         | 
| @@ -227,13 +276,13 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 227 276 | 
             
                                 'status' => 400,
         | 
| 228 277 | 
             
                                 'detail' => 'Validation failed: \'age\' must be less than 42',
         | 
| 229 278 | 
             
                                 'title' => nil,
         | 
| 230 | 
            -
                                 'code' | 
| 231 | 
            -
                                 'meta' => { 'nodes' => [{ '_type' =>  | 
| 279 | 
            +
                                 'code' => 'DeserializationError.Validation',
         | 
| 280 | 
            +
                                 'meta' => { 'nodes' => [{ '_type' => 'Child', 'id' => nil }],
         | 
| 232 281 | 
             
                                             'attribute' => 'age',
         | 
| 233 282 | 
             
                                             'message' => 'must be less than 42',
         | 
| 234 | 
            -
                                             'details' => { 'error' => 'less_than', 'value' => 42, 'count' => 42 }},
         | 
| 283 | 
            +
                                             'details' => { 'error' => 'less_than', 'value' => 42, 'count' => 42 } },
         | 
| 235 284 | 
             
                                 'exception' => nil,
         | 
| 236 | 
            -
                                 'causes' => nil }},
         | 
| 285 | 
            +
                                 'causes' => nil } },
         | 
| 237 286 | 
             
                             parentcontroller.hash_response)
         | 
| 238 287 | 
             
              end
         | 
| 239 288 |  | 
| @@ -241,17 +290,17 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 241 290 | 
             
                data = { '_type'    => 'Parent',
         | 
| 242 291 | 
             
                         'children' => [{ '_type' => 'Child',
         | 
| 243 292 | 
             
                                          'age'   => 1 }] }
         | 
| 244 | 
            -
                parentcontroller = ParentController.new(data: data)
         | 
| 293 | 
            +
                parentcontroller = ParentController.new(params: { data: data })
         | 
| 245 294 | 
             
                parentcontroller.invoke(:create)
         | 
| 246 295 |  | 
| 247 296 | 
             
                assert_equal(400, parentcontroller.status)
         | 
| 248 | 
            -
                assert_match( | 
| 249 | 
            -
                             parentcontroller.hash_response[ | 
| 250 | 
            -
                              | 
| 297 | 
            +
                assert_match(/check constraint/i,
         | 
| 298 | 
            +
                             parentcontroller.hash_response['error']['detail'],
         | 
| 299 | 
            +
                             'Database error propagated')
         | 
| 251 300 | 
             
              end
         | 
| 252 301 |  | 
| 253 302 | 
             
              def test_destroy_missing
         | 
| 254 | 
            -
                parentcontroller = ParentController.new(id: 9999)
         | 
| 303 | 
            +
                parentcontroller = ParentController.new(params: { id: 9999 })
         | 
| 255 304 | 
             
                parentcontroller.invoke(:destroy)
         | 
| 256 305 |  | 
| 257 306 | 
             
                assert_equal({ 'error' => {
         | 
| @@ -260,8 +309,8 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 260 309 | 
             
                                 'status' => 404,
         | 
| 261 310 | 
             
                                 'detail' => "Couldn't find Parent(s) with id(s)=[9999]",
         | 
| 262 311 | 
             
                                 'title' => nil,
         | 
| 263 | 
            -
                                 'code' | 
| 264 | 
            -
                                 'meta' => {  | 
| 312 | 
            +
                                 'code' => 'DeserializationError.NotFound',
         | 
| 313 | 
            +
                                 'meta' => { 'nodes' => [{ '_type' => 'Parent', 'id' => 9999 }] },
         | 
| 265 314 | 
             
                                 'exception' => nil,
         | 
| 266 315 | 
             
                                 'causes' => nil } },
         | 
| 267 316 | 
             
                             parentcontroller.hash_response)
         | 
| @@ -273,7 +322,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 273 322 | 
             
              def test_nested_collection_index_associated
         | 
| 274 323 | 
             
                _distractor = Parent.create(name: 'p2', children: [Child.new(name: 'c3', position: 1)])
         | 
| 275 324 |  | 
| 276 | 
            -
                childcontroller = ChildController.new(parent_id: @parent.id)
         | 
| 325 | 
            +
                childcontroller = ChildController.new(params: { parent_id: @parent.id })
         | 
| 277 326 | 
             
                childcontroller.invoke(:index_associated)
         | 
| 278 327 |  | 
| 279 328 | 
             
                assert_equal(200, childcontroller.status)
         | 
| @@ -300,7 +349,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 300 349 |  | 
| 301 350 | 
             
              def test_nested_collection_append_one
         | 
| 302 351 | 
             
                data = { '_type' => 'Child', 'name' => 'c3' }
         | 
| 303 | 
            -
                childcontroller = ChildController.new(parent_id: @parent.id, data: data)
         | 
| 352 | 
            +
                childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
         | 
| 304 353 |  | 
| 305 354 | 
             
                childcontroller.invoke(:append)
         | 
| 306 355 |  | 
| @@ -308,7 +357,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 308 357 |  | 
| 309 358 | 
             
                @parent.reload
         | 
| 310 359 |  | 
| 311 | 
            -
                assert_equal(%w | 
| 360 | 
            +
                assert_equal(%w[c1 c2 c3], @parent.children.order(:position).pluck(:name))
         | 
| 312 361 | 
             
                assert_equal({ 'data' => ChildView.new(@parent.children.last).to_hash },
         | 
| 313 362 | 
             
                             childcontroller.hash_response)
         | 
| 314 363 |  | 
| @@ -317,17 +366,17 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 317 366 |  | 
| 318 367 | 
             
              def test_nested_collection_append_many
         | 
| 319 368 | 
             
                data = [{ '_type' => 'Child', 'name' => 'c3' },
         | 
| 320 | 
            -
                        { '_type' => 'Child', 'name' => 'c4' }]
         | 
| 369 | 
            +
                        { '_type' => 'Child', 'name' => 'c4' },]
         | 
| 321 370 |  | 
| 322 | 
            -
                childcontroller = ChildController.new(parent_id: @parent.id, data: data)
         | 
| 371 | 
            +
                childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
         | 
| 323 372 | 
             
                childcontroller.invoke(:append)
         | 
| 324 373 |  | 
| 325 374 | 
             
                assert_equal(200, childcontroller.status, childcontroller.hash_response)
         | 
| 326 375 |  | 
| 327 376 | 
             
                @parent.reload
         | 
| 328 377 |  | 
| 329 | 
            -
                assert_equal(%w | 
| 330 | 
            -
                new_children_hashes = @parent.children.last(2).map{ |c| ChildView.new(c).to_hash }
         | 
| 378 | 
            +
                assert_equal(%w[c1 c2 c3 c4], @parent.children.order(:position).pluck(:name))
         | 
| 379 | 
            +
                new_children_hashes = @parent.children.last(2).map { |c| ChildView.new(c).to_hash }
         | 
| 331 380 | 
             
                assert_equal({ 'data' => new_children_hashes },
         | 
| 332 381 | 
             
                             childcontroller.hash_response)
         | 
| 333 382 |  | 
| @@ -339,25 +388,25 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 339 388 | 
             
                # Parent.children
         | 
| 340 389 | 
             
                old_children = @parent.children
         | 
| 341 390 |  | 
| 342 | 
            -
                data = [{'_type' => 'Child', 'name' => 'newc1'},
         | 
| 343 | 
            -
                        {'_type' => 'Child', 'name' => 'newc2'}]
         | 
| 391 | 
            +
                data = [{ '_type' => 'Child', 'name' => 'newc1' },
         | 
| 392 | 
            +
                        { '_type' => 'Child', 'name' => 'newc2' },]
         | 
| 344 393 |  | 
| 345 | 
            -
                childcontroller = ChildController.new(parent_id: @parent.id, data: data)
         | 
| 394 | 
            +
                childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
         | 
| 346 395 | 
             
                childcontroller.invoke(:replace)
         | 
| 347 396 |  | 
| 348 397 | 
             
                assert_equal(200, childcontroller.status, childcontroller.hash_response)
         | 
| 349 398 |  | 
| 350 399 | 
             
                @parent.reload
         | 
| 351 400 |  | 
| 352 | 
            -
                assert_equal(%w | 
| 401 | 
            +
                assert_equal(%w[newc1 newc2], @parent.children.order(:position).pluck(:name))
         | 
| 353 402 | 
             
                assert_predicate(Child.where(id: old_children.map(&:id)), :empty?)
         | 
| 354 403 |  | 
| 355 404 | 
             
                assert_all_hooks_nested_inside_parent_hook(childcontroller.hook_trace)
         | 
| 356 405 | 
             
              end
         | 
| 357 406 |  | 
| 358 407 | 
             
              def test_nested_collection_replace_bad_data
         | 
| 359 | 
            -
                data = [{  | 
| 360 | 
            -
                childcontroller = ChildController.new(parent_id: @parent.id, data: data)
         | 
| 408 | 
            +
                data = [{ 'name' => 'nc' }]
         | 
| 409 | 
            +
                childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
         | 
| 361 410 |  | 
| 362 411 | 
             
                childcontroller.invoke(:replace)
         | 
| 363 412 |  | 
| @@ -368,14 +417,14 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 368 417 |  | 
| 369 418 | 
             
              def test_nested_collection_disassociate_one
         | 
| 370 419 | 
             
                old_child = @parent.children.first
         | 
| 371 | 
            -
                childcontroller = ChildController.new(parent_id: @parent.id, id: old_child.id)
         | 
| 420 | 
            +
                childcontroller = ChildController.new(params: { parent_id: @parent.id, id: old_child.id })
         | 
| 372 421 | 
             
                childcontroller.invoke(:disassociate)
         | 
| 373 422 |  | 
| 374 423 | 
             
                assert_equal(200, childcontroller.status, childcontroller.hash_response)
         | 
| 375 424 |  | 
| 376 425 | 
             
                @parent.reload
         | 
| 377 426 |  | 
| 378 | 
            -
                assert_equal(%w | 
| 427 | 
            +
                assert_equal(%w[c2], @parent.children.order(:position).pluck(:name))
         | 
| 379 428 | 
             
                assert_predicate(Child.where(id: old_child.id), :empty?)
         | 
| 380 429 |  | 
| 381 430 | 
             
                assert_all_hooks_nested_inside_parent_hook(childcontroller.hook_trace)
         | 
| @@ -384,7 +433,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 384 433 | 
             
              def test_nested_collection_disassociate_many
         | 
| 385 434 | 
             
                old_children = @parent.children
         | 
| 386 435 |  | 
| 387 | 
            -
                childcontroller = ChildController.new(parent_id: @parent.id)
         | 
| 436 | 
            +
                childcontroller = ChildController.new(params: { parent_id: @parent.id })
         | 
| 388 437 | 
             
                childcontroller.invoke(:disassociate_all)
         | 
| 389 438 |  | 
| 390 439 | 
             
                assert_equal(200, childcontroller.status, childcontroller.hash_response)
         | 
| @@ -400,14 +449,14 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 400 449 | 
             
              # direct methods on nested controller
         | 
| 401 450 | 
             
              def test_nested_collection_destroy
         | 
| 402 451 | 
             
                old_child = @parent.children.first
         | 
| 403 | 
            -
                childcontroller = ChildController.new(id: old_child.id)
         | 
| 452 | 
            +
                childcontroller = ChildController.new(params: { id: old_child.id })
         | 
| 404 453 | 
             
                childcontroller.invoke(:destroy)
         | 
| 405 454 |  | 
| 406 455 | 
             
                assert_equal(200, childcontroller.status, childcontroller.hash_response)
         | 
| 407 456 |  | 
| 408 457 | 
             
                @parent.reload
         | 
| 409 458 |  | 
| 410 | 
            -
                assert_equal(%w | 
| 459 | 
            +
                assert_equal(%w[c2], @parent.children.order(:position).pluck(:name))
         | 
| 411 460 | 
             
                assert_predicate(Child.where(id: old_child.id), :empty?)
         | 
| 412 461 | 
             
              end
         | 
| 413 462 |  | 
| @@ -418,7 +467,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 418 467 | 
             
                         '_type' => 'Child',
         | 
| 419 468 | 
             
                         'name' => 'new_name' }
         | 
| 420 469 |  | 
| 421 | 
            -
                childcontroller = ChildController.new(data: data)
         | 
| 470 | 
            +
                childcontroller = ChildController.new(params: { data: data })
         | 
| 422 471 | 
             
                childcontroller.invoke(:create)
         | 
| 423 472 |  | 
| 424 473 | 
             
                assert_equal(200, childcontroller.status, childcontroller.hash_response)
         | 
| @@ -430,26 +479,25 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 430 479 | 
             
                             childcontroller.hash_response)
         | 
| 431 480 | 
             
              end
         | 
| 432 481 |  | 
| 433 | 
            -
             | 
| 482 | 
            +
              def test_nested_collection_show
         | 
| 434 483 | 
             
                old_child = @parent.children.first
         | 
| 435 484 |  | 
| 436 | 
            -
                childcontroller = ChildController.new(id: old_child.id)
         | 
| 485 | 
            +
                childcontroller = ChildController.new(params: { id: old_child.id })
         | 
| 437 486 | 
             
                childcontroller.invoke(:show)
         | 
| 438 487 |  | 
| 439 488 | 
             
                assert_equal({ 'data' => ChildView.new(old_child).to_hash },
         | 
| 440 489 | 
             
                             childcontroller.hash_response)
         | 
| 441 490 |  | 
| 442 491 | 
             
                assert_equal(200, childcontroller.status)
         | 
| 443 | 
            -
             | 
| 444 | 
            -
             | 
| 492 | 
            +
              end
         | 
| 445 493 |  | 
| 446 494 | 
             
              ## Single association
         | 
| 447 495 |  | 
| 448 496 | 
             
              def test_nested_singular_replace_from_parent
         | 
| 449 497 | 
             
                old_label = @parent.label
         | 
| 450 498 |  | 
| 451 | 
            -
                data = {'_type' => 'Label', 'text' => 'new label'}
         | 
| 452 | 
            -
                labelcontroller = LabelController.new(parent_id: @parent.id, data: data)
         | 
| 499 | 
            +
                data = { '_type' => 'Label', 'text' => 'new label' }
         | 
| 500 | 
            +
                labelcontroller = LabelController.new(params: { parent_id: @parent.id, data: data })
         | 
| 453 501 | 
             
                labelcontroller.invoke(:create_associated)
         | 
| 454 502 |  | 
| 455 503 | 
             
                assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
         | 
| @@ -471,7 +519,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 471 519 | 
             
              def test_nested_singular_show_from_parent
         | 
| 472 520 | 
             
                old_label = @parent.label
         | 
| 473 521 |  | 
| 474 | 
            -
                labelcontroller = LabelController.new(parent_id: @parent.id)
         | 
| 522 | 
            +
                labelcontroller = LabelController.new(params: { parent_id: @parent.id })
         | 
| 475 523 | 
             
                labelcontroller.invoke(:show_associated)
         | 
| 476 524 |  | 
| 477 525 | 
             
                assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
         | 
| @@ -485,7 +533,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 485 533 | 
             
              def test_nested_singular_destroy_from_parent
         | 
| 486 534 | 
             
                old_label = @parent.label
         | 
| 487 535 |  | 
| 488 | 
            -
                labelcontroller = LabelController.new(parent_id: @parent.id)
         | 
| 536 | 
            +
                labelcontroller = LabelController.new(params: { parent_id: @parent.id })
         | 
| 489 537 | 
             
                labelcontroller.invoke(:destroy_associated)
         | 
| 490 538 |  | 
| 491 539 | 
             
                @parent.reload
         | 
| @@ -502,8 +550,8 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 502 550 | 
             
              def test_nested_singular_update_from_parent
         | 
| 503 551 | 
             
                old_label = @parent.label
         | 
| 504 552 |  | 
| 505 | 
            -
                data = {'_type' => 'Label', 'id' => old_label.id, 'text' => 'new label'}
         | 
| 506 | 
            -
                labelcontroller = LabelController.new(parent_id: @parent.id, data: data)
         | 
| 553 | 
            +
                data = { '_type' => 'Label', 'id' => old_label.id, 'text' => 'new label' }
         | 
| 554 | 
            +
                labelcontroller = LabelController.new(params: { parent_id: @parent.id, data: data })
         | 
| 507 555 | 
             
                labelcontroller.invoke(:create_associated)
         | 
| 508 556 |  | 
| 509 557 | 
             
                assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
         | 
| @@ -520,7 +568,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 520 568 | 
             
              def test_nested_singular_show_from_id
         | 
| 521 569 | 
             
                old_label = @parent.label
         | 
| 522 570 |  | 
| 523 | 
            -
                labelcontroller = LabelController.new(id: old_label.id)
         | 
| 571 | 
            +
                labelcontroller = LabelController.new(params: { id: old_label.id })
         | 
| 524 572 | 
             
                labelcontroller.invoke(:show)
         | 
| 525 573 |  | 
| 526 574 | 
             
                assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
         | 
| @@ -534,7 +582,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 534 582 | 
             
                # foreign key violation. Destroy target instead.
         | 
| 535 583 | 
             
                old_target = @parent.target
         | 
| 536 584 |  | 
| 537 | 
            -
                targetcontroller = TargetController.new(id: old_target.id)
         | 
| 585 | 
            +
                targetcontroller = TargetController.new(params: { id: old_target.id })
         | 
| 538 586 | 
             
                targetcontroller.invoke(:destroy)
         | 
| 539 587 |  | 
| 540 588 | 
             
                @parent.reload
         | 
| @@ -549,8 +597,8 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase | |
| 549 597 | 
             
              def test_nested_singular_update
         | 
| 550 598 | 
             
                old_label = @parent.label
         | 
| 551 599 |  | 
| 552 | 
            -
                data = {'_type' => 'Label', 'id' => old_label.id, 'text' => 'new label'}
         | 
| 553 | 
            -
                labelcontroller = LabelController.new(data: data)
         | 
| 600 | 
            +
                data = { '_type' => 'Label', 'id' => old_label.id, 'text' => 'new label' }
         | 
| 601 | 
            +
                labelcontroller = LabelController.new(params: { data: data })
         | 
| 554 602 | 
             
                labelcontroller.invoke(:create)
         | 
| 555 603 |  | 
| 556 604 | 
             
                assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
         |