rails_ops 1.2.3 → 1.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9aebb67a89b1cc32ee09838441c6fd5739fb40f44662d9f09519ffbb09a63066
4
- data.tar.gz: 16dde2b894f56aef4f774a8d7b421b4928ee566b058d54c5d4aa7446ee877270
3
+ metadata.gz: f1937c4aa90d37d096b10168ebffa90a755be0e1c7a52dc250f95d66c2b6b7f0
4
+ data.tar.gz: 5cc13627f981463d58248762486a724cc3ae84a3e36a3ce0bf4f6edc72af7096
5
5
  SHA512:
6
- metadata.gz: 6bc197031923788967f7f972bef74c2f7d122d6aa23287911c9bcde5ed95434ac7612a3366a99641c2fca30acc069c8591a62af5c0edf603fb77fc5609799297
7
- data.tar.gz: 11a35f00a823959e1e0dd8859f32d404ca7a2b7c38c9f17695332e5a0bea40b0452be88f57a50e58d695264e3bae5f8ca7d88d2fc98f4649de28038705518a49
6
+ metadata.gz: f40e55561302426eea0c42554d9b2b9db3ed3806db11bc821cf14598244c1f0921343f3db138e7be366370d9d5011c3a1bf95f8a3868919dfe7bf96517e0e8a9
7
+ data.tar.gz: 9028d762c7ee9a9c6a515aaec868cea270bb970450c982038573ce83ff0f689f86e4721fe9b6487c7ad69560ec08bbfc879b2e19a97fd7a7c97eabf7e3c71d52
@@ -29,6 +29,8 @@ jobs:
29
29
  ruby-version: '3.0.1'
30
30
  - rails-version: '7.0'
31
31
  ruby-version: '3.1.0'
32
+ - rails-version: '7.0'
33
+ ruby-version: '3.2.0'
32
34
  name: Test against Ruby ${{ matrix.ruby-version }} / Rails ${{ matrix.rails-version }}
33
35
  env:
34
36
  BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_${{ matrix.rails-version }}.gemfile
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
+ /bin
2
+ /RUBY_VERSION
1
3
  /.bundle/
2
4
  /.yardoc
3
5
  /Gemfile.lock
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.4.0 (2023-02-21)
4
+
5
+ ### Changes
6
+
7
+ * #33: Improve resolving `param_key` in nested model operations.
8
+
9
+ ### Upgrading
10
+
11
+ Please see #33 for more information on this change. If all of your operations
12
+ follow the standard naming conventions (e.g. `Operations::User::Update` for
13
+ updating a model named `User`), no changes will be necessary. If you don't, you
14
+ may need to manually specify a `param_key` when using nested model operations
15
+ (see [Model nesting](README.md#param-key) for more information).
16
+
17
+ ## 1.3.0 (2023-01-23)
18
+
19
+ * Add `lock_mode` DSL method
20
+ * Set `Load` operations to use shared locking, and `Update` and `Destroy`
21
+ operations to use exclusive locking. Please make sure your operations
22
+ inherit from the correct parent operation, and change the locking mode
23
+ if it is not the correct one for your operation. More info can be found
24
+ in the section "Locking" in the Readme
25
+
3
26
  ## 1.2.3 (2023-01-04)
4
27
 
5
28
  * Fix marshalling of operation models. This is especially useful for use in
data/README.md CHANGED
@@ -1133,6 +1133,32 @@ class Operations::User::Update < RailsOps::Operation::Model::Update
1133
1133
  end
1134
1134
  ```
1135
1135
 
1136
+ Please note that for performance reasons, the `Load` operation (and any
1137
+ operations inheriting from it) use a shared lock, i.e. it issues
1138
+ an `LOCK IN SHARE MODE` / `FOR SHARE` statement. The `Update` and `Destroy`
1139
+ operations (as well as operations inheriting from it) however use the default
1140
+ `lock` method of ActiveRecord, which will issue an exclusive lock.
1141
+
1142
+ If you want to change the mode, you can use the `lock_mode` DSL method, which
1143
+ has two possible modes:
1144
+
1145
+ * `:shared` for the shared lock mode
1146
+ * `:exclusive` for the exclusive lock mode
1147
+
1148
+ For example, if you have an operation loading a record which you'd want to
1149
+ lock exclusively, you'd need to write the following:
1150
+
1151
+ ```ruby
1152
+ class Operations::User::Update < RailsOps::Operation::Model::Load
1153
+ model ::User
1154
+ lock_mode :exclusive
1155
+ end
1156
+ ```
1157
+
1158
+ One caveat is, that shared locking is only supported for MySQl (MariaDB),
1159
+ Postgresql and Oracle DB databases, any other database will always use an
1160
+ exlusive lock.
1161
+
1136
1162
  ### Creating models
1137
1163
 
1138
1164
  For creating models, you can use the base class
@@ -1354,6 +1380,21 @@ class User
1354
1380
  end
1355
1381
  ```
1356
1382
 
1383
+ #### Param key
1384
+
1385
+ When nesting a model operation, the sub operation is called automatically by
1386
+ RailsOps. For this purpose, it needs to know which `param_key` to use for
1387
+ calling the sub operation, e.g. `user: { name: 'Jane Doe' }`. Normally, this is
1388
+ derived by calling `<sub-op-model-class>.model_name.param_key`. If your
1389
+ operation for some reason expects a different param key, you can specify it
1390
+ using the option `param_key`, e.g.:
1391
+
1392
+ ```ruby
1393
+ # Operation Operations::Group::Create will receive the following params:
1394
+ # { my_custom_key: { ... } }
1395
+ nest_model_op :group, Operations::Group::Create, param_key: :my_custom_key
1396
+ ```
1397
+
1357
1398
  #### Custom parameters
1358
1399
 
1359
1400
  In the above examples, all `group_attributes` are automatically passed to the
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.3
1
+ 1.4.0
@@ -14,7 +14,7 @@ module RailsOps::Mixins::Model::Nesting
14
14
  end
15
15
 
16
16
  module ClassMethods
17
- def nest_model_op(attribute, klass, lookup_via_id_on_update: true, allow_id: false, &params_block)
17
+ def nest_model_op(attribute, klass, lookup_via_id_on_update: true, allow_id: false, param_key: nil, &params_block)
18
18
  # ---------------------------------------------------------------
19
19
  # Make sure we're working with an extension / copy
20
20
  # of the given model class
@@ -123,11 +123,11 @@ module RailsOps::Mixins::Model::Nesting
123
123
  end
124
124
 
125
125
  # Wrap parameters for nested model operation
126
- model_class = config[:klass].name.deconstantize.demodulize.underscore.to_sym
126
+ param_key ||= config[:klass].model.model_name.param_key
127
127
 
128
128
  if action == :create
129
129
  wrapped_params = {
130
- model_class => op_params
130
+ param_key => op_params
131
131
  }
132
132
  elsif action == :update
133
133
  if config[:lookup_via_id_on_update]
@@ -139,7 +139,7 @@ module RailsOps::Mixins::Model::Nesting
139
139
 
140
140
  wrapped_params = {
141
141
  :id => id,
142
- model_class => op_params
142
+ param_key => op_params
143
143
  }
144
144
  else
145
145
  fail "Unsupported action #{action}."
@@ -5,14 +5,13 @@ module RailsOps
5
5
  # with default procs which is not supported by `Marshal.dump`. This mixin
6
6
  # therefore excludes this instance variable from being dumped and loaded.
7
7
  module Marshalling
8
- UNMARSHALED_VARIABLES = %i[@parent_op].freeze
8
+ UNMARSHALED_VARIABLES = %i(@parent_op).freeze
9
9
 
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  def marshal_dump
13
- instance_variables.reject{|m| UNMARSHALED_VARIABLES.include? m}.inject({}) do |vars, attr|
13
+ instance_variables.reject { |m| UNMARSHALED_VARIABLES.include? m }.each_with_object({}) do |attr, vars|
14
14
  vars[attr] = instance_variable_get(attr)
15
- vars
16
15
  end
17
16
  end
18
17
 
@@ -1,5 +1,6 @@
1
1
  class RailsOps::Operation::Model::Destroy < RailsOps::Operation::Model::Load
2
2
  model_authorization_action :destroy
3
+ lock_mode :exclusive
3
4
 
4
5
  def model_authorization
5
6
  return unless authorization_enabled?
@@ -1,6 +1,7 @@
1
1
  class RailsOps::Operation::Model::Load < RailsOps::Operation::Model
2
2
  class_attribute :_lock_model_at_build
3
3
  class_attribute :_load_model_authorization_action
4
+ class_attribute :_lock_mode
4
5
 
5
6
  policy :on_init do
6
7
  model_authorization
@@ -39,6 +40,24 @@ class RailsOps::Operation::Model::Load < RailsOps::Operation::Model
39
40
  _lock_model_at_build.nil? ? RailsOps.config.lock_models_at_build? : _lock_model_at_build
40
41
  end
41
42
 
43
+ # Method to set the lock mode, which can either be :exclusive to use
44
+ # an exclusive write lock, or :shared to use a shared lock. Please note
45
+ # that currently, :shared only works for MySql, Postgresql and Oracle DB,
46
+ # other adapters always use the exclusive lock.
47
+ def self.lock_mode(lock_mode)
48
+ fail "Unknown lock mode #{lock_mode}" unless %i(shared exclusive).include?(lock_mode)
49
+
50
+ self._lock_mode = lock_mode
51
+ end
52
+
53
+ # Get the lock_mode or the default of :exclusive
54
+ def self.lock_mode_or_default
55
+ _lock_mode.presence || :exclusive
56
+ end
57
+
58
+ # Set the lock mode for load operations (and it's children) to :shared
59
+ lock_mode :shared
60
+
42
61
  def model_id_field
43
62
  :id
44
63
  end
@@ -52,7 +71,7 @@ class RailsOps::Operation::Model::Load < RailsOps::Operation::Model
52
71
  relation = self.class.model
53
72
 
54
73
  # Express intention to lock if required
55
- relation = relation.lock if self.class.lock_model_at_build?
74
+ relation = lock_relation(relation)
56
75
 
57
76
  # Fetch (and possibly lock) model
58
77
  return relation.find_by!(model_id_field => params[model_id_field])
@@ -69,4 +88,38 @@ class RailsOps::Operation::Model::Load < RailsOps::Operation::Model
69
88
  def extract_id_from_params
70
89
  params[model_id_field]
71
90
  end
91
+
92
+ private
93
+
94
+ def lock_relation(relation)
95
+ # Directly return the relation if we don't want to lock the relation
96
+ return relation unless self.class.lock_model_at_build?
97
+
98
+ if self.class.lock_mode_or_default == :shared
99
+ # Lock the relation in shared mode
100
+ return relation.lock(shared_lock_statement)
101
+ else
102
+ # Lock the relation in exclusive mode
103
+ return relation.lock
104
+ end
105
+ end
106
+
107
+ def shared_lock_statement
108
+ adapter_type = ActiveRecord::Base.connection.adapter_name.downcase.to_sym
109
+
110
+ case adapter_type
111
+ when :mysql, :mysql2
112
+ return 'LOCK IN SHARE MODE'
113
+ when :postgresql
114
+ return 'FOR SHARE'
115
+ when :oracleenhanced
116
+ return 'LOCK IN SHARE MODE'
117
+ end
118
+
119
+ # Don't return anything, which will make the `lock` statement
120
+ # use the normal, exclusive lock. This might be suboptimal for other
121
+ # database adapters, but we'd rather lock too restrictive, such that
122
+ # no race-conditions may occur.
123
+ return nil
124
+ end
72
125
  end
@@ -1,5 +1,6 @@
1
1
  class RailsOps::Operation::Model::Update < RailsOps::Operation::Model::Load
2
2
  model_authorization_action :update
3
+ lock_mode :exclusive
3
4
 
4
5
  # As this operation might extend the model class, we need to make sure that
5
6
  # the operation works using an extended 'copy' of the given model class.
data/rails_ops.gemspec CHANGED
@@ -1,18 +1,18 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rails_ops 1.2.3 ruby lib
2
+ # stub: rails_ops 1.4.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rails_ops".freeze
6
- s.version = "1.2.3"
6
+ s.version = "1.4.0"
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Sitrox".freeze]
11
- s.date = "2023-01-04"
12
- s.files = [".github/workflows/rubocop.yml".freeze, ".github/workflows/ruby.yml".freeze, ".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, "Appraisals".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "gemfiles/rails_6.0.gemfile".freeze, "gemfiles/rails_6.1.gemfile".freeze, "gemfiles/rails_7.0.gemfile".freeze, "lib/generators/operation/USAGE".freeze, "lib/generators/operation/operation_generator.rb".freeze, "lib/generators/operation/templates/controller.erb".freeze, "lib/generators/operation/templates/create.erb".freeze, "lib/generators/operation/templates/destroy.erb".freeze, "lib/generators/operation/templates/load.erb".freeze, "lib/generators/operation/templates/update.erb".freeze, "lib/generators/operation/templates/view.erb".freeze, "lib/rails_ops.rb".freeze, "lib/rails_ops/authorization_backend/abstract.rb".freeze, "lib/rails_ops/authorization_backend/can_can_can.rb".freeze, "lib/rails_ops/configuration.rb".freeze, "lib/rails_ops/context.rb".freeze, "lib/rails_ops/controller_mixin.rb".freeze, "lib/rails_ops/exceptions.rb".freeze, "lib/rails_ops/hooked_job.rb".freeze, "lib/rails_ops/hookup.rb".freeze, "lib/rails_ops/hookup/dsl.rb".freeze, "lib/rails_ops/hookup/dsl_validator.rb".freeze, "lib/rails_ops/hookup/hook.rb".freeze, "lib/rails_ops/log_subscriber.rb".freeze, "lib/rails_ops/mixins.rb".freeze, "lib/rails_ops/mixins/authorization.rb".freeze, "lib/rails_ops/mixins/log_settings.rb".freeze, "lib/rails_ops/mixins/model.rb".freeze, "lib/rails_ops/mixins/model/authorization.rb".freeze, "lib/rails_ops/mixins/model/nesting.rb".freeze, "lib/rails_ops/mixins/param_authorization.rb".freeze, "lib/rails_ops/mixins/policies.rb".freeze, "lib/rails_ops/mixins/require_context.rb".freeze, "lib/rails_ops/mixins/routes.rb".freeze, "lib/rails_ops/mixins/schema_validation.rb".freeze, "lib/rails_ops/mixins/sub_ops.rb".freeze, "lib/rails_ops/model_mixins.rb".freeze, "lib/rails_ops/model_mixins/ar_extension.rb".freeze, "lib/rails_ops/model_mixins/marshalling.rb".freeze, "lib/rails_ops/model_mixins/parent_op.rb".freeze, "lib/rails_ops/model_mixins/sti_fixes.rb".freeze, "lib/rails_ops/model_mixins/virtual_attributes.rb".freeze, "lib/rails_ops/model_mixins/virtual_attributes/virtual_column_wrapper.rb".freeze, "lib/rails_ops/model_mixins/virtual_has_one.rb".freeze, "lib/rails_ops/model_mixins/virtual_model_name.rb".freeze, "lib/rails_ops/operation.rb".freeze, "lib/rails_ops/operation/model.rb".freeze, "lib/rails_ops/operation/model/create.rb".freeze, "lib/rails_ops/operation/model/destroy.rb".freeze, "lib/rails_ops/operation/model/load.rb".freeze, "lib/rails_ops/operation/model/update.rb".freeze, "lib/rails_ops/profiler.rb".freeze, "lib/rails_ops/profiler/node.rb".freeze, "lib/rails_ops/railtie.rb".freeze, "lib/rails_ops/scoped_env.rb".freeze, "lib/rails_ops/virtual_model.rb".freeze, "rails_ops.gemspec".freeze, "test/db/models.rb".freeze, "test/db/schema.rb".freeze, "test/dummy/Rakefile".freeze, "test/dummy/app/assets/config/manifest.js".freeze, "test/dummy/app/assets/images/.keep".freeze, "test/dummy/app/assets/javascripts/application.js".freeze, "test/dummy/app/assets/javascripts/cable.js".freeze, "test/dummy/app/assets/javascripts/channels/.keep".freeze, "test/dummy/app/assets/stylesheets/application.css".freeze, "test/dummy/app/channels/application_cable/channel.rb".freeze, "test/dummy/app/channels/application_cable/connection.rb".freeze, "test/dummy/app/controllers/application_controller.rb".freeze, "test/dummy/app/controllers/concerns/.keep".freeze, "test/dummy/app/helpers/application_helper.rb".freeze, "test/dummy/app/jobs/application_job.rb".freeze, "test/dummy/app/mailers/application_mailer.rb".freeze, "test/dummy/app/models/animal.rb".freeze, "test/dummy/app/models/application_record.rb".freeze, "test/dummy/app/models/bird.rb".freeze, "test/dummy/app/models/cat.rb".freeze, "test/dummy/app/models/concerns/.keep".freeze, "test/dummy/app/models/dog.rb".freeze, "test/dummy/app/models/flower.rb".freeze, "test/dummy/app/models/group.rb".freeze, "test/dummy/app/models/nightingale.rb".freeze, "test/dummy/app/models/phoenix.rb".freeze, "test/dummy/app/models/user.rb".freeze, "test/dummy/app/views/layouts/application.html.erb".freeze, "test/dummy/app/views/layouts/mailer.html.erb".freeze, "test/dummy/app/views/layouts/mailer.text.erb".freeze, "test/dummy/bin/bundle".freeze, "test/dummy/bin/rails".freeze, "test/dummy/bin/rake".freeze, "test/dummy/bin/setup".freeze, "test/dummy/bin/update".freeze, "test/dummy/bin/yarn".freeze, "test/dummy/config.ru".freeze, "test/dummy/config/application.rb".freeze, "test/dummy/config/boot.rb".freeze, "test/dummy/config/cable.yml".freeze, "test/dummy/config/database.yml".freeze, "test/dummy/config/environment.rb".freeze, "test/dummy/config/environments/development.rb".freeze, "test/dummy/config/environments/production.rb".freeze, "test/dummy/config/environments/test.rb".freeze, "test/dummy/config/initializers/application_controller_renderer.rb".freeze, "test/dummy/config/initializers/assets.rb".freeze, "test/dummy/config/initializers/backtrace_silencers.rb".freeze, "test/dummy/config/initializers/cookies_serializer.rb".freeze, "test/dummy/config/initializers/filter_parameter_logging.rb".freeze, "test/dummy/config/initializers/inflections.rb".freeze, "test/dummy/config/initializers/mime_types.rb".freeze, "test/dummy/config/initializers/rails_ops.rb".freeze, "test/dummy/config/initializers/wrap_parameters.rb".freeze, "test/dummy/config/locales/en.yml".freeze, "test/dummy/config/puma.rb".freeze, "test/dummy/config/routes.rb".freeze, "test/dummy/config/secrets.yml".freeze, "test/dummy/config/spring.rb".freeze, "test/dummy/db/schema.rb".freeze, "test/dummy/lib/assets/.keep".freeze, "test/dummy/log/.keep".freeze, "test/dummy/package.json".freeze, "test/dummy/public/404.html".freeze, "test/dummy/public/422.html".freeze, "test/dummy/public/500.html".freeze, "test/dummy/public/apple-touch-icon-precomposed.png".freeze, "test/dummy/public/apple-touch-icon.png".freeze, "test/dummy/public/favicon.ico".freeze, "test/dummy/tmp/.keep".freeze, "test/test_helper.rb".freeze, "test/unit/rails_ops/generators/operation_generator_test.rb".freeze, "test/unit/rails_ops/mixins/model/nesting.rb".freeze, "test/unit/rails_ops/mixins/param_authorization_test.rb".freeze, "test/unit/rails_ops/mixins/policies_test.rb".freeze, "test/unit/rails_ops/operation/model/create_test.rb".freeze, "test/unit/rails_ops/operation/model/load_test.rb".freeze, "test/unit/rails_ops/operation/model/sti_test.rb".freeze, "test/unit/rails_ops/operation/model/update_test.rb".freeze, "test/unit/rails_ops/operation/model_test.rb".freeze, "test/unit/rails_ops/operation/update_auth_test.rb".freeze, "test/unit/rails_ops/operation/update_lazy_auth_test.rb".freeze, "test/unit/rails_ops/operation_test.rb".freeze]
13
- s.rubygems_version = "3.3.11".freeze
11
+ s.date = "2023-02-21"
12
+ s.files = [".github/workflows/rubocop.yml".freeze, ".github/workflows/ruby.yml".freeze, ".gitignore".freeze, ".releaser_config".freeze, ".rubocop.yml".freeze, "Appraisals".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "gemfiles/rails_6.0.gemfile".freeze, "gemfiles/rails_6.1.gemfile".freeze, "gemfiles/rails_7.0.gemfile".freeze, "lib/generators/operation/USAGE".freeze, "lib/generators/operation/operation_generator.rb".freeze, "lib/generators/operation/templates/controller.erb".freeze, "lib/generators/operation/templates/create.erb".freeze, "lib/generators/operation/templates/destroy.erb".freeze, "lib/generators/operation/templates/load.erb".freeze, "lib/generators/operation/templates/update.erb".freeze, "lib/generators/operation/templates/view.erb".freeze, "lib/rails_ops.rb".freeze, "lib/rails_ops/authorization_backend/abstract.rb".freeze, "lib/rails_ops/authorization_backend/can_can_can.rb".freeze, "lib/rails_ops/configuration.rb".freeze, "lib/rails_ops/context.rb".freeze, "lib/rails_ops/controller_mixin.rb".freeze, "lib/rails_ops/exceptions.rb".freeze, "lib/rails_ops/hooked_job.rb".freeze, "lib/rails_ops/hookup.rb".freeze, "lib/rails_ops/hookup/dsl.rb".freeze, "lib/rails_ops/hookup/dsl_validator.rb".freeze, "lib/rails_ops/hookup/hook.rb".freeze, "lib/rails_ops/log_subscriber.rb".freeze, "lib/rails_ops/mixins.rb".freeze, "lib/rails_ops/mixins/authorization.rb".freeze, "lib/rails_ops/mixins/log_settings.rb".freeze, "lib/rails_ops/mixins/model.rb".freeze, "lib/rails_ops/mixins/model/authorization.rb".freeze, "lib/rails_ops/mixins/model/nesting.rb".freeze, "lib/rails_ops/mixins/param_authorization.rb".freeze, "lib/rails_ops/mixins/policies.rb".freeze, "lib/rails_ops/mixins/require_context.rb".freeze, "lib/rails_ops/mixins/routes.rb".freeze, "lib/rails_ops/mixins/schema_validation.rb".freeze, "lib/rails_ops/mixins/sub_ops.rb".freeze, "lib/rails_ops/model_mixins.rb".freeze, "lib/rails_ops/model_mixins/ar_extension.rb".freeze, "lib/rails_ops/model_mixins/marshalling.rb".freeze, "lib/rails_ops/model_mixins/parent_op.rb".freeze, "lib/rails_ops/model_mixins/sti_fixes.rb".freeze, "lib/rails_ops/model_mixins/virtual_attributes.rb".freeze, "lib/rails_ops/model_mixins/virtual_attributes/virtual_column_wrapper.rb".freeze, "lib/rails_ops/model_mixins/virtual_has_one.rb".freeze, "lib/rails_ops/model_mixins/virtual_model_name.rb".freeze, "lib/rails_ops/operation.rb".freeze, "lib/rails_ops/operation/model.rb".freeze, "lib/rails_ops/operation/model/create.rb".freeze, "lib/rails_ops/operation/model/destroy.rb".freeze, "lib/rails_ops/operation/model/load.rb".freeze, "lib/rails_ops/operation/model/update.rb".freeze, "lib/rails_ops/profiler.rb".freeze, "lib/rails_ops/profiler/node.rb".freeze, "lib/rails_ops/railtie.rb".freeze, "lib/rails_ops/scoped_env.rb".freeze, "lib/rails_ops/virtual_model.rb".freeze, "rails_ops.gemspec".freeze, "test/db/models.rb".freeze, "test/db/schema.rb".freeze, "test/dummy/Rakefile".freeze, "test/dummy/app/assets/config/manifest.js".freeze, "test/dummy/app/assets/images/.keep".freeze, "test/dummy/app/assets/javascripts/application.js".freeze, "test/dummy/app/assets/javascripts/cable.js".freeze, "test/dummy/app/assets/javascripts/channels/.keep".freeze, "test/dummy/app/assets/stylesheets/application.css".freeze, "test/dummy/app/channels/application_cable/channel.rb".freeze, "test/dummy/app/channels/application_cable/connection.rb".freeze, "test/dummy/app/controllers/application_controller.rb".freeze, "test/dummy/app/controllers/concerns/.keep".freeze, "test/dummy/app/helpers/application_helper.rb".freeze, "test/dummy/app/jobs/application_job.rb".freeze, "test/dummy/app/mailers/application_mailer.rb".freeze, "test/dummy/app/models/animal.rb".freeze, "test/dummy/app/models/application_record.rb".freeze, "test/dummy/app/models/bird.rb".freeze, "test/dummy/app/models/cat.rb".freeze, "test/dummy/app/models/computer.rb".freeze, "test/dummy/app/models/concerns/.keep".freeze, "test/dummy/app/models/cpu.rb".freeze, "test/dummy/app/models/dog.rb".freeze, "test/dummy/app/models/flower.rb".freeze, "test/dummy/app/models/group.rb".freeze, "test/dummy/app/models/mainboard.rb".freeze, "test/dummy/app/models/nightingale.rb".freeze, "test/dummy/app/models/phoenix.rb".freeze, "test/dummy/app/models/user.rb".freeze, "test/dummy/app/views/layouts/application.html.erb".freeze, "test/dummy/app/views/layouts/mailer.html.erb".freeze, "test/dummy/app/views/layouts/mailer.text.erb".freeze, "test/dummy/bin/bundle".freeze, "test/dummy/bin/rails".freeze, "test/dummy/bin/rake".freeze, "test/dummy/bin/setup".freeze, "test/dummy/bin/update".freeze, "test/dummy/bin/yarn".freeze, "test/dummy/config.ru".freeze, "test/dummy/config/application.rb".freeze, "test/dummy/config/boot.rb".freeze, "test/dummy/config/cable.yml".freeze, "test/dummy/config/database.yml".freeze, "test/dummy/config/environment.rb".freeze, "test/dummy/config/environments/development.rb".freeze, "test/dummy/config/environments/production.rb".freeze, "test/dummy/config/environments/test.rb".freeze, "test/dummy/config/initializers/application_controller_renderer.rb".freeze, "test/dummy/config/initializers/assets.rb".freeze, "test/dummy/config/initializers/backtrace_silencers.rb".freeze, "test/dummy/config/initializers/cookies_serializer.rb".freeze, "test/dummy/config/initializers/filter_parameter_logging.rb".freeze, "test/dummy/config/initializers/inflections.rb".freeze, "test/dummy/config/initializers/mime_types.rb".freeze, "test/dummy/config/initializers/rails_ops.rb".freeze, "test/dummy/config/initializers/wrap_parameters.rb".freeze, "test/dummy/config/locales/en.yml".freeze, "test/dummy/config/puma.rb".freeze, "test/dummy/config/routes.rb".freeze, "test/dummy/config/secrets.yml".freeze, "test/dummy/config/spring.rb".freeze, "test/dummy/db/schema.rb".freeze, "test/dummy/lib/assets/.keep".freeze, "test/dummy/log/.keep".freeze, "test/dummy/package.json".freeze, "test/dummy/public/404.html".freeze, "test/dummy/public/422.html".freeze, "test/dummy/public/500.html".freeze, "test/dummy/public/apple-touch-icon-precomposed.png".freeze, "test/dummy/public/apple-touch-icon.png".freeze, "test/dummy/public/favicon.ico".freeze, "test/dummy/tmp/.keep".freeze, "test/test_helper.rb".freeze, "test/unit/rails_ops/generators/operation_generator_test.rb".freeze, "test/unit/rails_ops/mixins/model/deep_nesting_test.rb".freeze, "test/unit/rails_ops/mixins/param_authorization_test.rb".freeze, "test/unit/rails_ops/mixins/policies_test.rb".freeze, "test/unit/rails_ops/operation/model/create_test.rb".freeze, "test/unit/rails_ops/operation/model/load_test.rb".freeze, "test/unit/rails_ops/operation/model/sti_test.rb".freeze, "test/unit/rails_ops/operation/model/update_test.rb".freeze, "test/unit/rails_ops/operation/model_test.rb".freeze, "test/unit/rails_ops/operation/update_auth_test.rb".freeze, "test/unit/rails_ops/operation/update_lazy_auth_test.rb".freeze, "test/unit/rails_ops/operation_test.rb".freeze]
13
+ s.rubygems_version = "3.3.20".freeze
14
14
  s.summary = "An operations service layer for rails projects.".freeze
15
- s.test_files = ["test/db/models.rb".freeze, "test/db/schema.rb".freeze, "test/dummy/Rakefile".freeze, "test/dummy/app/assets/config/manifest.js".freeze, "test/dummy/app/assets/images/.keep".freeze, "test/dummy/app/assets/javascripts/application.js".freeze, "test/dummy/app/assets/javascripts/cable.js".freeze, "test/dummy/app/assets/javascripts/channels/.keep".freeze, "test/dummy/app/assets/stylesheets/application.css".freeze, "test/dummy/app/channels/application_cable/channel.rb".freeze, "test/dummy/app/channels/application_cable/connection.rb".freeze, "test/dummy/app/controllers/application_controller.rb".freeze, "test/dummy/app/controllers/concerns/.keep".freeze, "test/dummy/app/helpers/application_helper.rb".freeze, "test/dummy/app/jobs/application_job.rb".freeze, "test/dummy/app/mailers/application_mailer.rb".freeze, "test/dummy/app/models/animal.rb".freeze, "test/dummy/app/models/application_record.rb".freeze, "test/dummy/app/models/bird.rb".freeze, "test/dummy/app/models/cat.rb".freeze, "test/dummy/app/models/concerns/.keep".freeze, "test/dummy/app/models/dog.rb".freeze, "test/dummy/app/models/flower.rb".freeze, "test/dummy/app/models/group.rb".freeze, "test/dummy/app/models/nightingale.rb".freeze, "test/dummy/app/models/phoenix.rb".freeze, "test/dummy/app/models/user.rb".freeze, "test/dummy/app/views/layouts/application.html.erb".freeze, "test/dummy/app/views/layouts/mailer.html.erb".freeze, "test/dummy/app/views/layouts/mailer.text.erb".freeze, "test/dummy/bin/bundle".freeze, "test/dummy/bin/rails".freeze, "test/dummy/bin/rake".freeze, "test/dummy/bin/setup".freeze, "test/dummy/bin/update".freeze, "test/dummy/bin/yarn".freeze, "test/dummy/config.ru".freeze, "test/dummy/config/application.rb".freeze, "test/dummy/config/boot.rb".freeze, "test/dummy/config/cable.yml".freeze, "test/dummy/config/database.yml".freeze, "test/dummy/config/environment.rb".freeze, "test/dummy/config/environments/development.rb".freeze, "test/dummy/config/environments/production.rb".freeze, "test/dummy/config/environments/test.rb".freeze, "test/dummy/config/initializers/application_controller_renderer.rb".freeze, "test/dummy/config/initializers/assets.rb".freeze, "test/dummy/config/initializers/backtrace_silencers.rb".freeze, "test/dummy/config/initializers/cookies_serializer.rb".freeze, "test/dummy/config/initializers/filter_parameter_logging.rb".freeze, "test/dummy/config/initializers/inflections.rb".freeze, "test/dummy/config/initializers/mime_types.rb".freeze, "test/dummy/config/initializers/rails_ops.rb".freeze, "test/dummy/config/initializers/wrap_parameters.rb".freeze, "test/dummy/config/locales/en.yml".freeze, "test/dummy/config/puma.rb".freeze, "test/dummy/config/routes.rb".freeze, "test/dummy/config/secrets.yml".freeze, "test/dummy/config/spring.rb".freeze, "test/dummy/db/schema.rb".freeze, "test/dummy/lib/assets/.keep".freeze, "test/dummy/log/.keep".freeze, "test/dummy/package.json".freeze, "test/dummy/public/404.html".freeze, "test/dummy/public/422.html".freeze, "test/dummy/public/500.html".freeze, "test/dummy/public/apple-touch-icon-precomposed.png".freeze, "test/dummy/public/apple-touch-icon.png".freeze, "test/dummy/public/favicon.ico".freeze, "test/dummy/tmp/.keep".freeze, "test/test_helper.rb".freeze, "test/unit/rails_ops/generators/operation_generator_test.rb".freeze, "test/unit/rails_ops/mixins/model/nesting.rb".freeze, "test/unit/rails_ops/mixins/param_authorization_test.rb".freeze, "test/unit/rails_ops/mixins/policies_test.rb".freeze, "test/unit/rails_ops/operation/model/create_test.rb".freeze, "test/unit/rails_ops/operation/model/load_test.rb".freeze, "test/unit/rails_ops/operation/model/sti_test.rb".freeze, "test/unit/rails_ops/operation/model/update_test.rb".freeze, "test/unit/rails_ops/operation/model_test.rb".freeze, "test/unit/rails_ops/operation/update_auth_test.rb".freeze, "test/unit/rails_ops/operation/update_lazy_auth_test.rb".freeze, "test/unit/rails_ops/operation_test.rb".freeze]
15
+ s.test_files = ["test/db/models.rb".freeze, "test/db/schema.rb".freeze, "test/dummy/Rakefile".freeze, "test/dummy/app/assets/config/manifest.js".freeze, "test/dummy/app/assets/images/.keep".freeze, "test/dummy/app/assets/javascripts/application.js".freeze, "test/dummy/app/assets/javascripts/cable.js".freeze, "test/dummy/app/assets/javascripts/channels/.keep".freeze, "test/dummy/app/assets/stylesheets/application.css".freeze, "test/dummy/app/channels/application_cable/channel.rb".freeze, "test/dummy/app/channels/application_cable/connection.rb".freeze, "test/dummy/app/controllers/application_controller.rb".freeze, "test/dummy/app/controllers/concerns/.keep".freeze, "test/dummy/app/helpers/application_helper.rb".freeze, "test/dummy/app/jobs/application_job.rb".freeze, "test/dummy/app/mailers/application_mailer.rb".freeze, "test/dummy/app/models/animal.rb".freeze, "test/dummy/app/models/application_record.rb".freeze, "test/dummy/app/models/bird.rb".freeze, "test/dummy/app/models/cat.rb".freeze, "test/dummy/app/models/computer.rb".freeze, "test/dummy/app/models/concerns/.keep".freeze, "test/dummy/app/models/cpu.rb".freeze, "test/dummy/app/models/dog.rb".freeze, "test/dummy/app/models/flower.rb".freeze, "test/dummy/app/models/group.rb".freeze, "test/dummy/app/models/mainboard.rb".freeze, "test/dummy/app/models/nightingale.rb".freeze, "test/dummy/app/models/phoenix.rb".freeze, "test/dummy/app/models/user.rb".freeze, "test/dummy/app/views/layouts/application.html.erb".freeze, "test/dummy/app/views/layouts/mailer.html.erb".freeze, "test/dummy/app/views/layouts/mailer.text.erb".freeze, "test/dummy/bin/bundle".freeze, "test/dummy/bin/rails".freeze, "test/dummy/bin/rake".freeze, "test/dummy/bin/setup".freeze, "test/dummy/bin/update".freeze, "test/dummy/bin/yarn".freeze, "test/dummy/config.ru".freeze, "test/dummy/config/application.rb".freeze, "test/dummy/config/boot.rb".freeze, "test/dummy/config/cable.yml".freeze, "test/dummy/config/database.yml".freeze, "test/dummy/config/environment.rb".freeze, "test/dummy/config/environments/development.rb".freeze, "test/dummy/config/environments/production.rb".freeze, "test/dummy/config/environments/test.rb".freeze, "test/dummy/config/initializers/application_controller_renderer.rb".freeze, "test/dummy/config/initializers/assets.rb".freeze, "test/dummy/config/initializers/backtrace_silencers.rb".freeze, "test/dummy/config/initializers/cookies_serializer.rb".freeze, "test/dummy/config/initializers/filter_parameter_logging.rb".freeze, "test/dummy/config/initializers/inflections.rb".freeze, "test/dummy/config/initializers/mime_types.rb".freeze, "test/dummy/config/initializers/rails_ops.rb".freeze, "test/dummy/config/initializers/wrap_parameters.rb".freeze, "test/dummy/config/locales/en.yml".freeze, "test/dummy/config/puma.rb".freeze, "test/dummy/config/routes.rb".freeze, "test/dummy/config/secrets.yml".freeze, "test/dummy/config/spring.rb".freeze, "test/dummy/db/schema.rb".freeze, "test/dummy/lib/assets/.keep".freeze, "test/dummy/log/.keep".freeze, "test/dummy/package.json".freeze, "test/dummy/public/404.html".freeze, "test/dummy/public/422.html".freeze, "test/dummy/public/500.html".freeze, "test/dummy/public/apple-touch-icon-precomposed.png".freeze, "test/dummy/public/apple-touch-icon.png".freeze, "test/dummy/public/favicon.ico".freeze, "test/dummy/tmp/.keep".freeze, "test/test_helper.rb".freeze, "test/unit/rails_ops/generators/operation_generator_test.rb".freeze, "test/unit/rails_ops/mixins/model/deep_nesting_test.rb".freeze, "test/unit/rails_ops/mixins/param_authorization_test.rb".freeze, "test/unit/rails_ops/mixins/policies_test.rb".freeze, "test/unit/rails_ops/operation/model/create_test.rb".freeze, "test/unit/rails_ops/operation/model/load_test.rb".freeze, "test/unit/rails_ops/operation/model/sti_test.rb".freeze, "test/unit/rails_ops/operation/model/update_test.rb".freeze, "test/unit/rails_ops/operation/model_test.rb".freeze, "test/unit/rails_ops/operation/update_auth_test.rb".freeze, "test/unit/rails_ops/operation/update_lazy_auth_test.rb".freeze, "test/unit/rails_ops/operation_test.rb".freeze]
16
16
 
17
17
  if s.respond_to? :specification_version then
18
18
  s.specification_version = 4
@@ -0,0 +1,3 @@
1
+ class Computer < ApplicationRecord
2
+ belongs_to :mainboard, optional: true, autosave: false, validate: true
3
+ end
@@ -0,0 +1,2 @@
1
+ class Cpu < ApplicationRecord
2
+ end
@@ -0,0 +1,3 @@
1
+ class Mainboard < ApplicationRecord
2
+ belongs_to :cpu, optional: true, autosave: false, validate: true
3
+ end
@@ -14,4 +14,18 @@ ActiveRecord::Schema.define do
14
14
  create_table :flowers, force: true do |t|
15
15
  t.boolean :planted, null: false, default: true
16
16
  end
17
+
18
+ create_table :computers, force: true do |t|
19
+ t.string :name
20
+ t.references :mainboard
21
+ end
22
+
23
+ create_table :mainboards, force: true do |t|
24
+ t.string :name
25
+ t.references :cpu
26
+ end
27
+
28
+ create_table :cpus, force: true do |t|
29
+ t.string :name
30
+ end
17
31
  end
@@ -0,0 +1,144 @@
1
+ require 'test_helper'
2
+
3
+ class RailsOps::Mixins::Model::DeepNestingTest < ActiveSupport::TestCase
4
+ include TestHelper
5
+
6
+ CPU_CREATION_OP = Class.new(RailsOps::Operation::Model::Create) do
7
+ model Cpu do
8
+ validates :name, presence: true
9
+ end
10
+ end
11
+
12
+ MAINBOARD_CREATION_OP = Class.new(RailsOps::Operation::Model::Create) do
13
+ model Mainboard do
14
+ validates :name, presence: true
15
+ end
16
+
17
+ nest_model_op :cpu, CPU_CREATION_OP
18
+ end
19
+
20
+ COMPUTER_CREATION_OP = Class.new(RailsOps::Operation::Model::Create) do
21
+ model Computer do
22
+ validates :name, presence: true
23
+ end
24
+
25
+ nest_model_op :mainboard, MAINBOARD_CREATION_OP
26
+ end
27
+
28
+ def test_create_cpu
29
+ assert_nothing_raised do
30
+ CPU_CREATION_OP.run!(cpu: { name: 'CPU' })
31
+ end
32
+ end
33
+
34
+ def test_create_mainboard
35
+ assert_nothing_raised do
36
+ MAINBOARD_CREATION_OP.run!(
37
+ mainboard: {
38
+ name: 'Mainboard',
39
+ cpu_attributes: {
40
+ name: 'CPU'
41
+ }
42
+ }
43
+ )
44
+ end
45
+ end
46
+
47
+ def test_create_computer_success
48
+ model = assert_nothing_raised do
49
+ COMPUTER_CREATION_OP.run!(
50
+ computer: {
51
+ name: 'Computer',
52
+
53
+ mainboard_attributes: {
54
+ name: 'Mainboard',
55
+
56
+ cpu_attributes: {
57
+ name: 'CPU'
58
+ }
59
+ }
60
+ }
61
+ ).model
62
+ end
63
+
64
+ assert 'Computer', model.persisted?
65
+ assert 'Mainboard', model.mainboard.persisted?
66
+ assert 'CPU', model.mainboard.cpu.persisted?
67
+
68
+ assert_equal 'Computer', model.name
69
+ assert_equal 'Mainboard', model.mainboard.name
70
+ assert_equal 'CPU', model.mainboard.cpu.name
71
+ end
72
+
73
+ def test_create_computer_level_1_validation_error
74
+ op = COMPUTER_CREATION_OP.new(
75
+ computer: {
76
+ mainboard_attributes: {
77
+ name: 'Mainboard',
78
+
79
+ cpu_attributes: {
80
+ name: 'CPU'
81
+ }
82
+ }
83
+ }
84
+ )
85
+
86
+ assert_raises_with_message ActiveRecord::RecordInvalid, /Name can't be blank/ do
87
+ op.run!
88
+ end
89
+
90
+ assert_equal ["Name can't be blank"], op.model.errors.full_messages
91
+ refute op.model.persisted?
92
+ end
93
+
94
+ def test_create_computer_level_2_validation_error
95
+ op = COMPUTER_CREATION_OP.new(
96
+ computer: {
97
+ name: 'Computer',
98
+
99
+ mainboard_attributes: {
100
+ cpu_attributes: {
101
+ name: 'CPU'
102
+ }
103
+ }
104
+ }
105
+ )
106
+
107
+ assert_raises_with_message ActiveRecord::RecordInvalid, /Mainboard is invalid/ do
108
+ op.run!
109
+ end
110
+
111
+ assert_equal ["Mainboard is invalid"], op.model.errors.full_messages
112
+ refute op.model.persisted?
113
+
114
+ assert_equal ["Name can't be blank"], op.model.mainboard.errors.full_messages
115
+ refute op.model.mainboard.persisted?
116
+ end
117
+
118
+ def test_create_computer_level_3_validation_error
119
+ op = COMPUTER_CREATION_OP.new(
120
+ computer: {
121
+ name: 'Computer',
122
+
123
+ mainboard_attributes: {
124
+ name: 'Mainboard',
125
+
126
+ cpu_attributes: {}
127
+ }
128
+ }
129
+ )
130
+
131
+ assert_raises_with_message ActiveRecord::RecordInvalid, /Mainboard is invalid/ do
132
+ op.run!
133
+ end
134
+
135
+ assert_equal ["Mainboard is invalid"], op.model.errors.full_messages
136
+ refute op.model.persisted?
137
+
138
+ assert_equal ["Cpu is invalid"], op.model.mainboard.errors.full_messages
139
+ refute op.model.mainboard.persisted?
140
+
141
+ assert_equal ["Name can't be blank"], op.model.mainboard.cpu.errors.full_messages
142
+ refute op.model.mainboard.cpu.persisted?
143
+ end
144
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_ops
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sitrox
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-04 00:00:00.000000000 Z
11
+ date: 2023-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -212,8 +212,8 @@ dependencies:
212
212
  - - "<="
213
213
  - !ruby/object:Gem::Version
214
214
  version: '3.1'
215
- description:
216
- email:
215
+ description:
216
+ email:
217
217
  executables: []
218
218
  extensions: []
219
219
  extra_rdoc_files: []
@@ -307,10 +307,13 @@ files:
307
307
  - test/dummy/app/models/application_record.rb
308
308
  - test/dummy/app/models/bird.rb
309
309
  - test/dummy/app/models/cat.rb
310
+ - test/dummy/app/models/computer.rb
310
311
  - test/dummy/app/models/concerns/.keep
312
+ - test/dummy/app/models/cpu.rb
311
313
  - test/dummy/app/models/dog.rb
312
314
  - test/dummy/app/models/flower.rb
313
315
  - test/dummy/app/models/group.rb
316
+ - test/dummy/app/models/mainboard.rb
314
317
  - test/dummy/app/models/nightingale.rb
315
318
  - test/dummy/app/models/phoenix.rb
316
319
  - test/dummy/app/models/user.rb
@@ -359,7 +362,7 @@ files:
359
362
  - test/dummy/tmp/.keep
360
363
  - test/test_helper.rb
361
364
  - test/unit/rails_ops/generators/operation_generator_test.rb
362
- - test/unit/rails_ops/mixins/model/nesting.rb
365
+ - test/unit/rails_ops/mixins/model/deep_nesting_test.rb
363
366
  - test/unit/rails_ops/mixins/param_authorization_test.rb
364
367
  - test/unit/rails_ops/mixins/policies_test.rb
365
368
  - test/unit/rails_ops/operation/model/create_test.rb
@@ -370,10 +373,10 @@ files:
370
373
  - test/unit/rails_ops/operation/update_auth_test.rb
371
374
  - test/unit/rails_ops/operation/update_lazy_auth_test.rb
372
375
  - test/unit/rails_ops/operation_test.rb
373
- homepage:
376
+ homepage:
374
377
  licenses: []
375
378
  metadata: {}
376
- post_install_message:
379
+ post_install_message:
377
380
  rdoc_options: []
378
381
  require_paths:
379
382
  - lib
@@ -388,8 +391,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
388
391
  - !ruby/object:Gem::Version
389
392
  version: '0'
390
393
  requirements: []
391
- rubygems_version: 3.3.11
392
- signing_key:
394
+ rubygems_version: 3.0.3.1
395
+ signing_key:
393
396
  specification_version: 4
394
397
  summary: An operations service layer for rails projects.
395
398
  test_files:
@@ -413,10 +416,13 @@ test_files:
413
416
  - test/dummy/app/models/application_record.rb
414
417
  - test/dummy/app/models/bird.rb
415
418
  - test/dummy/app/models/cat.rb
419
+ - test/dummy/app/models/computer.rb
416
420
  - test/dummy/app/models/concerns/.keep
421
+ - test/dummy/app/models/cpu.rb
417
422
  - test/dummy/app/models/dog.rb
418
423
  - test/dummy/app/models/flower.rb
419
424
  - test/dummy/app/models/group.rb
425
+ - test/dummy/app/models/mainboard.rb
420
426
  - test/dummy/app/models/nightingale.rb
421
427
  - test/dummy/app/models/phoenix.rb
422
428
  - test/dummy/app/models/user.rb
@@ -465,7 +471,7 @@ test_files:
465
471
  - test/dummy/tmp/.keep
466
472
  - test/test_helper.rb
467
473
  - test/unit/rails_ops/generators/operation_generator_test.rb
468
- - test/unit/rails_ops/mixins/model/nesting.rb
474
+ - test/unit/rails_ops/mixins/model/deep_nesting_test.rb
469
475
  - test/unit/rails_ops/mixins/param_authorization_test.rb
470
476
  - test/unit/rails_ops/mixins/policies_test.rb
471
477
  - test/unit/rails_ops/operation/model/create_test.rb
@@ -1,60 +0,0 @@
1
- require 'test_helper'
2
-
3
- class RailsOps::Mixins::Model::NestingTest < ActiveSupport::TestCase
4
- include TestHelper
5
-
6
- GROUP_CREATION_OP = Class.new RailsOps::Operation::Model::Create do
7
- model Group do
8
- validates :name, presence: true
9
- end
10
- end
11
-
12
- BASIC_OP = Class.new RailsOps::Operation::Model::Create do
13
- model User do
14
- end
15
- nest_model_op :group, GROUP_CREATION_OP
16
- end
17
-
18
- def test_has_many_basic
19
- BASIC_OP.run!(
20
- user: {
21
- name: 'test',
22
- group_attributes: {
23
- name: 'g1',
24
- color: 'blue'
25
- }
26
- }
27
- )
28
-
29
- assert_equal 1, User.count
30
- assert_equal 1, Group.count
31
- assert_equal 'test', User.first.name
32
- assert_equal 'g1', Group.first.name
33
- assert_equal Group.first, User.first.group
34
- assert_equal [User.first], Group.first.users
35
- end
36
-
37
- def test_has_many_validation
38
- op = BASIC_OP.new(
39
- user: {
40
- name: 'test',
41
- group_attributes: {
42
- color: 'blue'
43
- }
44
- }
45
- )
46
-
47
- assert_raises ActiveRecord::RecordInvalid do
48
- op.run!
49
- end
50
-
51
- refute op.model.persisted?
52
- refute op.model.group.persisted?
53
-
54
- assert_equal BASIC_OP.model, op.model.class
55
- assert_equal GROUP_CREATION_OP.model, op.model.group.class
56
-
57
- refute op.model.group.valid?
58
- refute op.model.valid?
59
- end
60
- end