Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialMatt Young
6,348 PointsState_Machine(s) Usage
It seems like there is a fork of state_machine that is now being maintained. It's state_machines (plural): https://github.com/state-machines/state_machines
However, it doesn't seem to work in quite the same way as state_machine did. At least, the code provided in the treehouse tutorial doesn't work.
Has anyone got it working?
My code is:
state_machine :state, :initial => :submitted do
event :approve do
transition :submitted => :approved
end
event :reject do
transition :submitted => :rejected
end
end
I suspect the syntax used for the first line may have changed, but I haven't been able to get it to work.
6 Answers
Jason Seifer
Treehouse Guest TeacherMatt Young This one took me a bit of time to figure out because there were a couple of problems here that were dependent on each other. The problem was that the Gemfile.lock
had an old version of the state_machines-activerecord
gem specified. In the end, you need to do the following:
bundle update state_machines-activerecord
I figured this out the following way:
- In the
time_entries_controller
, thetime_entry
wasn't being created but it also wasn't telling me why. I added the following code so I had an error message I could debug:
class TimeEntriesController < ApplicationController
def create
e = Employee.find(params[:employee_id])
time_entry = e.time_entries.build(params.require(:time_entry).permit(:time, :account_id))
if !time_entry.save
logger.error time_entry.errors.full_messages
end
redirect_to employee_path(e)
end
end
That told me that it wasn't being saved because I didn't have an account_id
column. I created some accounts and customers but it still wasn't working.
I loaded the
time_entry.rb
model and took a look at why validation might not be passing. Line 4 had a typo: "greter_then" rather than "greater_than".I tried again and it was silently failing. I double checked the documentation and everything appeared to be correct.
I checked GitHub issues for the gem and found no closed issues that mirrored the problem.
I double checked the version of the gem and it was "0.0.0" installed and "0.3.0" was the latest. I updated the gem using the bundle update command above and tried it again and it worked.
Hope that helps!
Elkin Arriero
15,160 PointsMy solution:
As Jason said, I run bundle update state_machines-activerecord, but it did not work, so what I did was:
- In Gemfile I deleted: gem 'state_machines'.
- Added this gem: gem 'state_machines-activerecord'
- And then execute: $ bundle
- Run the server again.
And it worked like a charm...
Hope it helps :)
Elkin Arriero
15,160 PointsOppsss... My bad, in Gemfile you should keep: gem 'state_machines', and just follow from step no. 2.
Geoffrey Emerson
18,726 PointsI replaced gem 'state_machine'
from the video with gem 'state_machines-activerecord'
.
bundle install
showed three new gems loaded:
Installing state_machines 0.4.0
Installing state_machines-activemodel 0.3.0
Installing state_machines-activerecord 0.3.0
Restart your rails server, of course.
Everything worked after that.
Jason Seifer
Treehouse Guest TeacherHey Matt Young! Any chance you can paste the rest of your code as well as the error you're getting?
Matt Young
6,348 PointsHere's what I've done so far for this lesson.
- Add: gem 'state_machines' to Gemfile, and then run bundle.
- Add new column (state) in account_entries table.
- Modify account_entry.rb as follows:
class AccountEntry < ActiveRecord::Base
belongs_to :account
validates :account_id, presence: true
validates_associated :account
after_save :update_account_balance!
state_machine :state, :initial => :submitted do
event :approve do
transition :submitted => :approved
end
event :reject do
transition :submitted => :rejected
end
end
def update_account_balance!
account.update_balance!
end
end
Following along with the lesson, I then fire up the server, visit http://localhost:3000/employees/2 and create a new time entry. A time entry is added, but it doesn't enter anything in the account_entries table for 'state'.
If I remove the state_machine code from account_entry.rb then the entries in the 'state' column will display. Otherwise they do not.
Is that all the code you require?
Jason Seifer
Treehouse Guest TeacherMatt Young Try adding gem 'state_machines-activerecord'
to your Gemfile
and give it another shot. That contains the code to make it work with ActiveRecord models. It should work after that. If not, please reply to this thread and tag me again! Thanks!
Matt Young
6,348 PointsHi Jason Seifer,
First up, how do I 'tag' you?
I'm now using state_machines-activerecord in my Gemfile, instead of 'state_machines', which I removed.
And now, when I access http://localhost:3000/employees/2 I get:
NoMethodError in Employees#show
Showing C:/Users/Matt/Websites/RubyOnRails/TestApp/biller2/app/views/employees/show.html.erb where line #4 raised:
undefined method `state_machine' for #<Class:0x876fd68>
Rails.root: C:/Users/Matt/Websites/RubyOnRails/TestApp/biller2 Application Trace | Framework Trace | Full Trace
app/models/account_entry.rb:9:in <class:AccountEntry>'
app/models/account_entry.rb:1:in
<top (required)>'
app/models/time_entry.rb:1:in <top (required)>'
app/views/employees/show.html.erb:4:in
app_views_employees_show_html_erb__507868244_71086140'
Here's my code for the relevant files:
account_entry.rb
class AccountEntry < ActiveRecord::Base
belongs_to :account
validates :account_id, presence: true
validates_associated :account
after_save :update_account_balance!
state_machine :state, :initial => :submitted do
event :approve do
transition :submitted => :approved
end
event :reject do
transition :submitted => :rejected
end
end
def update_account_balance!
account.update_balance!
end
end
time_entry.rb
class TimeEntry < AccountEntry
belongs_to :employee
validates :time, numericality: {greter_than: 0, less_than: 24}
before_create :calculate_amount!
def self.per_hour
100
end
def calculate_amount!
self.amount = TimeEntry.per_hour * self.time
end
end
show.html.erb
<h1><%= @employee.name %></h1>
<h3>Submit time form</h3>
<%= form_for [@employee, TimeEntry.new] do |f| %>
<%= f.label :customer %>
<%= f.collection_select(:account_id, Customer.premier.all, :id, :name) %>
<%= f.label :time %>
<%= f.text_field :time, :value => 1.0 %>
<%= f.submit %>
<% end %>
<h3>Time Entries</h3>
<% @employee.time_entries.each do |entry| %>
<div class="entry">
<strong><%= entry.state %></strong>
<%= entry.time %>
<%= entry.account.name %>
<%= entry.created_at %>
</div>
<% end %>
Jason Seifer
Treehouse Guest TeacherHi Matt Young I'm sorry for all the trouble here. At this point it looks like the state machine gem isn't even being recognized. Is there any way you could zip up your whole project and paste a link to that here so I can download it and take a look? There are a lot of parts here that I need to look at and it may be quicker than going back and forth on this thread.
Matt Young
6,348 PointsThanks Jason. Here's my project zipped up: https://dl.dropboxusercontent.com/u/30757113/biller2.zip
Matt Young
6,348 PointsHi @jasonseifer,
My project can be downloaded here: https://dl.dropboxusercontent.com/u/30757113/biller2.zip
David Chapman
22,023 PointsElkin's steps solved the issue for me.
I did not need to add gem 'state_machine' to my gem file, only gem 'state_machines-activerecord'.
Thanks!
Matt Young
6,348 PointsMatt Young
6,348 PointsYay. Thanks Jason Seifer. That's got everything working just as it should.