From a4407865c8d70e829169fa66304f47c7846f505b Mon Sep 17 00:00:00 2001 From: Arkadiy Zabazhanov Date: Tue, 10 Dec 2024 10:58:11 +0700 Subject: [PATCH] Allow params checks in preconditions --- .github/workflows/ci.yml | 2 ++ Appraisals | 2 +- CHANGELOG.md | 6 ++++-- README.md | 4 ++-- lib/operations/command.rb | 2 +- lib/operations/components/preconditions.rb | 3 ++- operations.gemspec | 2 +- spec/operations/components/preconditions_spec.rb | 9 ++++----- 8 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 254b467..ffc670f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,8 @@ jobs: - { ruby: '3.0', rails: '6.1' } - { ruby: '3.1', rails: '7.0' } - { ruby: '3.2', rails: '7.1' } + - { ruby: '3.3', rails: '7.2' } + - { ruby: '3.4', rails: '8.0' } runs-on: ubuntu-latest env: BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails.${{ matrix.rails }}.gemfile diff --git a/Appraisals b/Appraisals index 6464102..9e6b76b 100644 --- a/Appraisals +++ b/Appraisals @@ -1,6 +1,6 @@ # frozen_string_literal: true -%w[5.2 6.0 6.1 7.0 7.1].each do |version| +%w[5.2 6.0 6.1 7.0 7.1 7.2 8.0].each do |version| appraise "rails.#{version}" do gem "activerecord", "~> #{version}.0" gem "activesupport", "~> #{version}.0" diff --git a/CHANGELOG.md b/CHANGELOG.md index 09b9cdb..afa45a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,13 @@ ## [main](https://github.com/BookingSync/operations/tree/main) -### Changes -- Changed `Operations::Command::OperationFailed#message` to include detailed error messages +### Added + +- Allow receiving params in preconditions. ### Changes +- Changed `Operations::Command::OperationFailed#message` to include detailed error messages - Rename Operations::Form#model_name parameter to param_key and make it public preserving backwards compatibility. [\#52](https://github.com/BookingSync/operations/pull/52) ([pyromaniac](https://github.com/pyromaniac)) ## [0.7.2](https://github.com/BookingSync/operations/tree/v0.7.2) diff --git a/README.md b/README.md index e2ac5de..464daed 100644 --- a/README.md +++ b/README.md @@ -377,7 +377,7 @@ When we need to check against the application state, preconditions are coming to There are many potential scenarios when it can be handy. For example, we might need to render a button only when the subject entity satisfies preconditions for a particular operation. Or we want to return a list of possible operations from an API we have. -**Important:** a rule of thumb here is that preconditions don't depend on the user input, they only check the existing state of the application and they are supposed to access only the operation context for this purpose, not params. +**Important:** a rule of thumb here is that preconditions always depend on application/entities state. If a check depends only on params, then it is rather a Contract validation. ```ruby class Post::Publish @@ -425,7 +425,7 @@ class Post::Publish::NotPublishedPrecondition include Dry::Monads[:result] def call(post:, **) - return Failure(error: :already_published, tokens: { published_at: post.published_at }) if post.published? + return Failure(error: :already_published, path: [:post_id], tokens: { published_at: post.published_at }) if post.published? Success() end diff --git a/lib/operations/command.rb b/lib/operations/command.rb index f548b49..b2abfca 100644 --- a/lib/operations/command.rb +++ b/lib/operations/command.rb @@ -140,7 +140,7 @@ class OperationFailed < StandardError def initialize(operation_result) @operation_result = operation_result - operation_class_name = operation_result.operation&.operation&.class&.name + operation_class_name = operation_result.operation.operation.class.name if operation_result.operation super("#{operation_class_name} failed on #{operation_result.component}") end diff --git a/lib/operations/components/preconditions.rb b/lib/operations/components/preconditions.rb index 7c20d16..9b79c27 100644 --- a/lib/operations/components/preconditions.rb +++ b/lib/operations/components/preconditions.rb @@ -19,7 +19,8 @@ class Operations::Components::Preconditions < Operations::Components::Prechecks def call(params, context) failures = callable.flat_map do |entry| - results = Array.wrap(entry.call(**context)) + arg_names = call_args(entry, types: %i[req opt]) + results = Array.wrap(arg_names.one? ? entry.call(params, **context) : entry.call(**context)) results.filter_map { |result| result_failure(result) } end diff --git a/operations.gemspec b/operations.gemspec index a3c3336..8ec16c9 100644 --- a/operations.gemspec +++ b/operations.gemspec @@ -29,7 +29,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency "appraisal" spec.add_development_dependency "database_cleaner-active_record" - spec.add_development_dependency "sqlite3", "~> 1.4" + spec.add_development_dependency "sqlite3", ">= 1.4" spec.add_dependency "activerecord", ">= 5.2.0" spec.add_dependency "activesupport", ">= 5.2.0" diff --git a/spec/operations/components/preconditions_spec.rb b/spec/operations/components/preconditions_spec.rb index 448a126..a7e5993 100644 --- a/spec/operations/components/preconditions_spec.rb +++ b/spec/operations/components/preconditions_spec.rb @@ -47,13 +47,12 @@ { text: "Failure 4", path: [:name, 1], code: :foobar } ] }, - ->(**) { { error: "Failure", foo: 42, path: [nil] } }, + ->(params, **) { { error: "Failure", path: [nil], **params } }, ->(**) {} ] end it "aggregates failures" do - pp call.errors.to_h expect(call) .to be_failure .and have_attributes( @@ -67,7 +66,7 @@ { text: "Failure 1", code: :failure1 }, { text: "Failure 1", code: :failure1 }, "failure3", - { text: "Failure", foo: 42 } + { text: "Failure", name: "Batman" } ], name: [["failure2"], { 1 => [{ text: "Failure 4", code: :foobar }] }] } @@ -81,7 +80,7 @@ { text: "Failure 1", code: :failure1 }, { text: "Failure 1", code: :failure1 }, "failure3", - { text: "Failure", foo: 42 } + { text: "Failure", name: "Batman" } ], name: [["name failure2"], { 1 => [{ code: :foobar, text: "1 Failure 4" }] }] ) @@ -90,7 +89,7 @@ { text: "Échec 1", code: :failure1 }, { text: "Échec 1", code: :failure1 }, "failure3", - { text: "Failure", foo: 42 } + { text: "Failure", name: "Batman" } ], name: [["failure2"], { 1 => [{ code: :foobar, text: "Failure 4" }] }] )