Skip to content

Commit

Permalink
fix error if uses transition callback without transitions map
Browse files Browse the repository at this point in the history
  • Loading branch information
ermolaev committed Oct 11, 2024
1 parent d2cfbae commit 4352d34
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 7 deletions.
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ You can visualize transitions map with [enum_machine-contrib](https://github.com
- namespaced (via attr) by default: `order.state.to_collected`
- [aliases](Aliases)
- guarantees of existing transitions
- simple run transitions with callbacks `order.update(state: "collected")` or `order.to_collected`
- simple run transitions with callbacks `order.update(state: "collected")` or `order.state.to_collected`
- `aasm` / `state_machines` **event driven**, `enum_machine` **state driven**

```ruby
Expand Down Expand Up @@ -103,8 +103,9 @@ product.state.forming? # => true
class Product < ActiveRecord::Base
enum_machine :color, %w[red green blue]
enum_machine :state, %w[created approved cancelled activated] do
# transitions(any => any) - allow all transitions
transitions(
nil => "red",
nil => "created",
"created" => [nil, "approved"],
%w[cancelled approved] => "activated",
"activated" => %w[created cancelled],
Expand Down Expand Up @@ -133,6 +134,24 @@ product.state.to_activated! # => EnumMachine::Error: transition "created" => "ac
product.state.to_approved! # => true; equal to `product.update!(state: "approve")`
```

#### Skip transitions
```ruby
product = Product.new(state: "created")
product.skip_state_transitions { product.save }
```

method generated as `skip_#{enum_name}_transitions`

#### Skip in factories
```ruby
FactoryBot.define do
factory :product do
name { Faker::Commerce.product_name }
to_create { |product| product.skip_state_transitions { product.save! } }
end
end
```

### I18n

**ru.yml**
Expand Down
8 changes: 6 additions & 2 deletions lib/enum_machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ class InvalidTransition < Error
def initialize(machine, from, to)
@from = from
@to = to
@enum_const = machine.base_klass.const_get(machine.enum_const_name)
super("Transition #{from.inspect} => #{to.inspect} not defined in enum_machine #{enum_const.name}")
@enum_const =
begin
machine.base_klass.const_get(machine.enum_const_name)
rescue NameError # rubocop:disable Lint/SuppressedException

This comment has been minimized.

Copy link
@xronos-i-am

xronos-i-am Oct 14, 2024

Collaborator

не понял, что за кейс и почему просто погасили ошибку?

This comment has been minimized.

Copy link
@ermolaev

ermolaev Oct 14, 2024

Author Contributor

проблема возникает когда ошибка происходит во время "компиляции" транзишенов, так как константу мы определяем в последнюю очередь

ошибка возникает тут https://github.com/corp-gp/enum_machine/blob/master/lib/enum_machine/driver_active_record.rb#L13

а константу присваиваем здесь https://github.com/corp-gp/enum_machine/blob/master/lib/enum_machine/driver_active_record.rb#L113

тут не получилось быстро отрефакторить так как код зависимый, а ошибка будет гаситься только в момент загрузки класса с enum_machine

end
super("Transition #{from.inspect} => #{to.inspect} not defined in enum_machine :#{machine.attr_name}")
end

end
Expand Down
2 changes: 1 addition & 1 deletion lib/enum_machine/driver_active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def enum_machine(attr, enum_values, i18n_scope: nil, &block)
i18n_scope ||= "#{klass.base_class.to_s.underscore}.#{attr}"

enum_const_name = attr.to_s.upcase
machine = Machine.new(enum_values, klass, enum_const_name)
machine = Machine.new(enum_values, klass, enum_const_name, attr)
machine.instance_eval(&block) if block

enum_klass = BuildClass.call(enum_values: enum_values, i18n_scope: i18n_scope, machine: machine)
Expand Down
5 changes: 3 additions & 2 deletions lib/enum_machine/machine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
module EnumMachine
class Machine

attr_reader :enum_values, :base_klass, :enum_const_name
attr_reader :enum_values, :base_klass, :enum_const_name, :attr_name

def initialize(enum_values, base_klass = nil, enum_const_name = nil) # rubocop:disable Gp/OptArgParameters
def initialize(enum_values, base_klass = nil, enum_const_name = nil, attr_name = nil) # rubocop:disable Gp/OptArgParameters
@enum_values = enum_values
@base_klass = base_klass
@enum_const_name = enum_const_name
@attr_name = attr_name

This comment has been minimized.

Copy link
@xronos-i-am

xronos-i-am Oct 14, 2024

Collaborator

тут тоже не понял, что фиксили

This comment has been minimized.

Copy link
@ermolaev

ermolaev Oct 14, 2024

Author Contributor

чтобы сообщение об ошибке было вида
Transition nil => "picked" not defined in enum_machine :state (грепать удобнее)
ранее было
Transition nil => "picked" not defined in enum_machine STATE

4352d34#diff-d34f19aae993e479fd25aaefd1d9c99ce4f9412efb00c6fba30e5ac653318c58L23

@transitions = {}
@before_transition = {}
@after_transition = {}
Expand Down
13 changes: 13 additions & 0 deletions spec/enum_machine/active_record_machine_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,19 @@ def a
expect { m.update!(color: "green") }.to change(m, :message).to "green => green"
end

it "check error when empty transition" do
expect {
Class.new(TestModel) do
enum_machine :state, %w[picked completed] do
after_transition(nil => "picked") { 1 }
end
end
}.to raise_error(EnumMachine::InvalidTransition) { |e|
expect(e.from).to be_nil
expect(e.message).to include('Transition nil => "picked" not defined in enum_machine')
}
end

it "dup AR object not linked with original" do
m = model.create(state: "created", color: "green")
m.state # init parent
Expand Down

0 comments on commit 4352d34

Please sign in to comment.