NoMethodError: undefined method `call_action' for nil:NilClass
jmonegro opened this issue · 12 comments
Hi, I'm getting this error when trying to fire an event:
NoMethodError: undefined method `call_action' for nil:NilClass
from /Users/jmonegro/.rvm/gems/ruby-1.9.3-p194/gems/transitions-0.1.0/lib/transitions/machine.rb:47:in `fire_event'
from /Users/jmonegro/.rvm/gems/ruby-1.9.3-p194/gems/transitions-0.1.0/lib/transitions/event.rb:31:in `block in initialize'
from (irb):1
from /Users/jmonegro/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.7/lib/rails/commands/console.rb:47:in `start'
from /Users/jmonegro/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.7/lib/rails/commands/console.rb:8:in `start'
from /Users/jmonegro/.rvm/gems/ruby-1.9.3-p194/gems/railties-3.2.7/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Here's my code:
class Order < ActiveRecord::Base
include ActiveModel::Transitions
state_machine do
state "Order Received"
state "Order Shipped"
event :ship, success: :notify_customer do
transitions :to => "Order Shipped", :from => "Order Received"
end
end
private
def notify_customer
true
end
end
And trying to do order.ship!
Any pointers?
Thanks!
Thanks for the report - I edited your submission to make it look nicer using GH's markdown
```Ruby
# your_code
```
Now, to the problem: Yes, you're right, this is a problem in the gem that went unnoticed because apparently you are the first person ever to use strings with whitespace in it as state names..:)
Quickfix: Use symbols only:
class Order < ActiveRecord::Base
include ActiveModel::Transitions
state_machine do
state :received
state :shipped
event :ship do
transitions :to => :shipped, :from => :received
end
end
end
I will look into this problem asap.
In a nutshell: Don't use strings but symbols. Right now the gem expects symbols, nothing else.
I could update the gem so that it works with strings as well but this would mean a LOT of ugly code calling "to_sym" and type checks all over the place (even with using HashWithIndifferentAccess from ActiveSupport).
In addition, whitespace would never work since transitions
possibly generates methods e.g.
def received?
which means that whitespace is prohibited anyway.
If you want to use a different display name for states than the state name itself you need to set up a mapping from state_name to display_name for yourself (there is a display_name functionality in the gem but it looks like it is broken).
I will make this clearer in the documenation, thanks for reporting this -> closed.
Addendum:
This means that you will need to rewrite your example to:
state_machine do
state :order_shipped
state :order_received
event :ship, success: :notify_customer do
transitions :to => :order_shipped, :from => :order_received
end
end
Got it. I resorted to using "string symbols" (i.e. :'String Status') which
works for my purposes and implementation.
Thanks!
On Mon, Jul 30, 2012 at 9:12 AM, Timo Rößner <
reply@reply.github.com
wrote:
In a nutshell: Don't use strings but symbols. Right now the gem expects
symbols, nothing else.I could update the gem so that it works with strings as well but this
would mean a LOT of ugly code calling "to_sym" and type checks all over the
place (even with using HashWithIndifferentAccess from ActiveSupport).In addition, whitespace would never work since
transitions
possibly
generates methods e.g.def received?which means that whitespace is prohibited anyway.
If you want to use a different display name for states than the state name
itself you need to set up a mapping from state_name to display_name for
yourself (there is a display_name functionality in the gem but it looks
like it is broken).I will make this clearer in the documenation, thanks for reporting this ->
closed.
Reply to this email directly or view it on GitHub:
#60 (comment)
- Joel
I just wanted to mention that this error can also occur in another scenario even if you are using symbols. I was writing some tests and decided to change the state machine state names, but I forgot that my test scaffold was still creating a mock record with the old state name. When it came time to transition the object's state, this same error is thrown.
@homanchou - Would you be able to give a glimpse into the before/after of the specific test you were working with that use the state machine?
I have a worker model that has a state machine:
state_machine :auto_scopes => true do
state :running # initial state
state :completed #success
state :aborted #errored out
event :complete do
transitions :from => [:running], :to => :completed
end
event :abort do
transitions :from => [:running], :to => :aborted, :on_transition => [:send_admin_email]
end
end
But in the test I forgot that I renamed state 'in_progress' to 'running', so my test was doing:
worker = Sweeper.create(name:'remove_files', state:'in_progress')
worker.complete!
I would see an error like: "undefined method `call_action' for nil:NilClass"
That was kind of confusing for me. Probably a more helpful error might be "Invalid transition state 'in_progress' is not a defined state"
@troessner Might be able to give some more insight/options on the type of error that could be thrown. It is a tad confusing like you said.
This specific error does remind me of a different (but has some crossover) issue ( #120) . In the other issue, there was invalid data within the database (invalid state). The same type of thing was exposed via your testing. Your test just happened to have invalid data this time! :)
Yup, it was my own fault for having bad data in the DB. I just noticed this in the README: "The explicitly specified state must be one of the states listed in the state definition below, otherwise transitions
will raise a rather unhelpful exception like "NoMethodError: undefined method `call_action' for nil:NilClass" (there's a ticket to fix this already: #112)" , I remember reading that when I first started using the gem but didn't know what that was about. Now I do, I was totally bitten by it! :)
Actually, that reminds me. I think I helped reword that part of the README in PR, but back then I thought it was only regarding the explicitly defined INITIAL state had to be one of the states defined. But actually that goes for states that are in the DB as well.
@homanchou you're absolutely right, the error message IS absolutely confusing.
That was kind of confusing for me. Probably a more helpful error might be "Invalid transition state 'in_progress' is not a defined state"
I agree. Pull request welcome.:)
If you're not up to it, can you please open up a corresponding issue? I'll look into it once I find some time on my hands.
I encountered the same error when I typoed the name of the target state in an event. If I get the chance in the next week or so I'll do a fix.
I just ran into the same issue like @homanchou. A proper error message would be really nice.