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..d0607a0 100644 --- a/Appraisals +++ b/Appraisals @@ -1,8 +1,9 @@ # 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" + gem "sqlite3", version > "7.0" ? "~> 2.1" : "~> 1.4" end end 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/gemfiles/rails.5.2.gemfile b/gemfiles/rails.5.2.gemfile index f709f59..644c6b6 100644 --- a/gemfiles/rails.5.2.gemfile +++ b/gemfiles/rails.5.2.gemfile @@ -10,5 +10,6 @@ gem "rubocop-rails", require: false gem "rubocop-rspec", require: false gem "activerecord", "~> 5.2.0" gem "activesupport", "~> 5.2.0" +gem "sqlite3", "~> 1.4" gemspec path: "../" diff --git a/gemfiles/rails.6.0.gemfile b/gemfiles/rails.6.0.gemfile index 1b85233..be371f5 100644 --- a/gemfiles/rails.6.0.gemfile +++ b/gemfiles/rails.6.0.gemfile @@ -10,5 +10,6 @@ gem "rubocop-rails", require: false gem "rubocop-rspec", require: false gem "activerecord", "~> 6.0.0" gem "activesupport", "~> 6.0.0" +gem "sqlite3", "~> 1.4" gemspec path: "../" diff --git a/gemfiles/rails.6.1.gemfile b/gemfiles/rails.6.1.gemfile index c4b03f6..70dfe7b 100644 --- a/gemfiles/rails.6.1.gemfile +++ b/gemfiles/rails.6.1.gemfile @@ -10,5 +10,6 @@ gem "rubocop-rails", require: false gem "rubocop-rspec", require: false gem "activerecord", "~> 6.1.0" gem "activesupport", "~> 6.1.0" +gem "sqlite3", "~> 1.4" gemspec path: "../" diff --git a/gemfiles/rails.7.0.gemfile b/gemfiles/rails.7.0.gemfile index ba8d46b..299c385 100644 --- a/gemfiles/rails.7.0.gemfile +++ b/gemfiles/rails.7.0.gemfile @@ -10,5 +10,6 @@ gem "rubocop-rails", require: false gem "rubocop-rspec", require: false gem "activerecord", "~> 7.0.0" gem "activesupport", "~> 7.0.0" +gem "sqlite3", "~> 1.4" gemspec path: "../" diff --git a/gemfiles/rails.7.1.gemfile b/gemfiles/rails.7.1.gemfile index b181c1e..7068233 100644 --- a/gemfiles/rails.7.1.gemfile +++ b/gemfiles/rails.7.1.gemfile @@ -10,5 +10,6 @@ gem "rubocop-rails", require: false gem "rubocop-rspec", require: false gem "activerecord", "~> 7.1.0" gem "activesupport", "~> 7.1.0" +gem "sqlite3", "~> 2.1" gemspec path: "../" diff --git a/gemfiles/rails.7.2.gemfile b/gemfiles/rails.7.2.gemfile new file mode 100644 index 0000000..3cf13b3 --- /dev/null +++ b/gemfiles/rails.7.2.gemfile @@ -0,0 +1,15 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "bookingsync-rubocop", require: false, github: "BookingSync/bookingsync-rubocop", branch: "main" +gem "rspec" +gem "rubocop", require: false +gem "rubocop-performance", require: false +gem "rubocop-rails", require: false +gem "rubocop-rspec", require: false +gem "activerecord", "~> 7.2.0" +gem "activesupport", "~> 7.2.0" +gem "sqlite3", "~> 2.1" + +gemspec path: "../" diff --git a/gemfiles/rails.8.0.gemfile b/gemfiles/rails.8.0.gemfile new file mode 100644 index 0000000..4bc1eac --- /dev/null +++ b/gemfiles/rails.8.0.gemfile @@ -0,0 +1,15 @@ +# This file was generated by Appraisal + +source "https://rubygems.org" + +gem "bookingsync-rubocop", require: false, github: "BookingSync/bookingsync-rubocop", branch: "main" +gem "rspec" +gem "rubocop", require: false +gem "rubocop-performance", require: false +gem "rubocop-rails", require: false +gem "rubocop-rspec", require: false +gem "activerecord", "~> 8.0.0" +gem "activesupport", "~> 8.0.0" +gem "sqlite3", "~> 2.1" + +gemspec path: "../" 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" }] }] )