Validation issue when upgrading to state_machines gem - ruby-on-rails

I wanted to change from state_machine to state_machines. As I started to do this I encountered that the state was no longer changing from the initial state.
reviewed some stackoverflow and other guides: -
https://teamtreehouse.com/community/statemachines-usage
state-machines/state_machines-activerecord#33
Validation before persistance on state_machine gem
So changes i have made:
using state-machines-activerecord gem
add def initialize...
(see below)
I am now getting a rake setup error on my data. it
seems to have an issue with the validation the Contact ( a related
model that gets created first). Regardless of state, the Contact is
always created first. This ran fine before changing the gem.
any ideas? i think i have included all relevant code.
gem-file:
ruby "2.2.2"
gem "rails", "4.2.1"
gem "pg", "0.17.1" # postgresql database
gem "state_machines-activerecord"
gem-lock file
state_machines (0.4.0)
state_machines-activemodel (0.3.0)
activemodel (~> 4.1)
state_machines (>= 0.4.0)
state_machines-activerecord (0.3.0)
activerecord (~> 4.1)
state_machines-activemodel (>= 0.3.0)`
lead.rb (model) is:
`class Lead < ActiveRecord::Base
belongs_to :created_by_user, class_name: "User", inverse_of: :leads_created
belongs_to :contact
belongs_to :user
accepts_nested_attributes_for :contact
validates :contact, presence: true
state_machine :state, initial: :new_lead do
state :claimed
state :referred
state :broadcast
state :unclaimed`
`event :claim! do
transition all => :claimed
end
event :unclaim! do
transition claimed: :unclaimed
end
event :refer! do
transition new_lead: :referred
end
event :broadcast! do
transition all => :broadcast
end`
`def initialize(*)
super() # NOTE: This *must* be called, otherwise states won't get
initialized
end`
CONTROLLER
def lead_attributes
params.require(:lead).permit( :claimed,
:contact_id,
:status,
:state,
:user_id
setup_acceptance.rake
def create_contact(options={})
user = User.find_by(last_name: "Smith")
contact_attributes = { created_by_user: user, user: user }
attributes = contact_attributes.merge options
contact = Contact.create! attributes
contact.save!
contact
end
def create_lead(options={})
user = User.find_by(last_name: "Smith")
client_attributes = { user: user, created_by_user: user }
attributes = client_attributes.merge options
Lead.create! attributes ****(LINE 1311 where error message occurs)****
end
rake.setup
Lead.transaction do #(NOTE: THIS IS LINE 435)
create_lead( #(NOTE: THIS IS LINE 436)
user: User.find_by(last_name: "Smith"),
contact: Contact.find_by(last_name: "Lozar"),
status: 0,
state: "claimed"
}
]
)
error:
rake aborted!
ActiveRecord::RecordInvalid: Validation failed: Contact Please enter a value
/Users/workspace/ab/lib/tasks/setup_acceptance.rake:1311:in `create_lead'
/Users/workspace/ab/lib/tasks/setup.rake:436:in `block (2 levels) in <top (required)>
/Users/workspace/ab/lib/tasks/setup.rake:435:in `block in <top (required)>'
Tasks: TOP => setup_sample_data
(See full trace by running task with --trace)

with great thanks #avdi
The solution was to change:
super()
...which discards all the initialization arguments
to:
super
...which retains them implicitly.

Related

Testing a variable scope association

I'm trying to make my tests robust and really solid, and I've been breaking down some complex queries and associations into smaller ones, or refactoring and moving the data into scopes.
Given the following classes:
class Item < ActiveRecord::Base
belongs_to :location
scope :in_location, ->(location) { where(location: location) }
scope :findable, ->(location, not_ids) {
in_location(location).where.not(id: not_ids)
}
end
class Container < ActiveRecord::Base
belongs_to :location
# THIS IS WHAT I WANT TO TEST
has_many :findable_items, ->(container) {
findable(container.location, container.not_findable_ids)
}, class_name: 'Item'
end
How would you test a variable has_many relationship like this without hitting the database to a significant degree? I know I can test the Item.findable method on it's own; what I'm interested in is the container.findable_items method.
Note: the actual association being tested is more complex than this, and would require pretty extensive set-up; it's running through a few other nested associations and scopes. I'd like to avoid this setup if possible, and just test that the scope is called with the correct values.
Relevant parts of my Gemfile:
rails (4.2.3)
shoulda-matchers (2.6.2)
factory_girl (4.5.0)
factory_girl_rails (4.5.0)
rspec-core (3.3.2)
rspec-expectations (3.3.1)
rspec-its (1.2.0)
rspec-mocks (3.3.2)
rspec-rails (3.3.3)
I have shoulda-matchers in my project, so I can do the basic sanity test:
it { should have_many(:findable_items).class_name('Item') }
but this fails:
describe 'findable_line_items' do
let(:container) { #container } # where container is a valid but unsaved Container
let(:location) { #container.location }
it 'gets items that are in the location and not excluded' do
container.not_findable_ids = [1,2]
# so it doesn't hit the database
expect(Item).to receive(:findable).with(location, container.not_findable_ids)
container.findable_items
end
end
This spec fails with the following error:
1) Container findable_line_items gets items that are in the location and not excluded
Failure/Error: container.findable_items
NoMethodError:
undefined method `except' for nil:NilClass
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:158:in `block (2 levels) in add_constraints'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:154:in `each'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:154:in `block in add_constraints'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `each'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `each_with_index'
# /[redacted]/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:141:in `add_constraints'
# /[redacted]/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:39:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association_scope.rb:5:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association.rb:97:in `association_scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/association.rb:86:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_association.rb:423:in `scope'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_proxy.rb:37:in `initialize'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:106:in `new'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/relation/delegation.rb:106:in `create'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/collection_association.rb:39:in `reader'
# /[redacted]/gems/activerecord-4.2.3/lib/active_record/associations/builder/association.rb:115:in `pickable_items'
# ./spec/models/container_spec.rb:25:in `block (3 levels) in <top (required)>'
How would you get this spec to pass, without actually setting up an Item that meets all the requirements?
I ended up going with a solution like this:
describe 'findable_line_items' do
let(:container) { #container } # where container is a valid but unsaved Container
let(:location) { #container.location }
it 'gets items that are in the location and not excluded' do
# so it doesn't hit the database
expect(Item).to receive(:findable).with(location, container.not_findable_ids).and_call_original
expect(container).to receive(:location).and_call_original
expect(container).to receive(:not_findable_ids).and_call_original
container.findable_items
end
end
The error that was occurring was somewhere in the ActiveRecord association setup; it was trying to instantiate an ActiveRecord array on a nil object which was being returned from my Item stub. Adding .and_call_original solved that error.
I don't really care to test that the correct objects are being returned from this association, since that scope is being tested elsewhere, just that the scope is being used. It still hits the database in this scenario, but not the 15 times that would be required to set up a full test.

What changed in Ruby?

The following spec passes fine in Ruby 2.1.5 but fails in 2.2.0 and I can't tell what that's all about:
# job.rb
class Job < ActiveRecord::Base
validates :link, :url => true
end
# job_spec.rb
require 'rails_helper'
describe Job do
describe "#create" do
["blah", "http://", " "].each do |bad_link|
it {
should_not allow_value(bad_link).for(:link)
}
end
end
end
fail log looks like this:
1) Job#create should not allow link to be set to "http://"
Failure/Error: should_not allow_value(bad_link).for(:link)
Expected errors when link is set to "http://",
got no errors
# ./spec/models/job_spec.rb:14:in `block (4 levels) in <top (required)>'
I find the only way to for that spec to pass with Ruby 2.2.0 is to include the validates_url gem in my project!!
Does anyone know this is about?
Maybe my solution isn't ideal, but it works.
Replace validates_url gem by validates gem. It has UrlValidator (written by me), which is well tested.
gem 'validates' # in Gemfile
validates :link, :url => true # you needn't to change something. Just remove validates_url from your Gemfile
P.S. It's a strange way - to test functionality of gem. Functionality should be tested in gem already.
P.P.S. I'm strongly recommend you to move to ruby 2.2.1 (or 2.2.2) instead of 2.2.0, because of 2.2.0 has a lot of bugs

Friendly ID not working as of Rails 4.2?

I recently upgraded to rails 4.2 and I found that friendly ID stopped working. Not sure if this a bug or if I am literally just failing at using friendly id.
After the update my tests started failing, for example I have the following test:
context "Fiendly ID" do
it "should find by name" do
permission = FactoryGirl.create(:can_read)
Xaaron::Permission.find(permission.permission_name.parameterize).should_not eql nil
end
end
This test never use to fail but now its spitting out:
Failure/Error: Xaaron::Permission.find(permission.permission_name.parameterize).should_not eql nil
ActiveRecord::RecordNotFound:
Couldn't find Xaaron::Permission with 'id'=can_read2
# ./.bundle/gems/gems/activerecord-4.2.0/lib/active_record/core.rb:154:in `find'
# ./spec/models/xaaron/permission_spec.rb:21:in `block (3 levels) in <top (required)>'
With that in mind here is my model:
module Xaaron
class Permission < ActiveRecord::Base
extend FriendlyId
friendly_id :permission_name, use: [:slugged, :finders, :history]
has_many :roles_permissions
has_many :roles, :through => :roles_permissions
validates :permission_name, presence: true, uniqueness: true
def should_generate_new_friendly_id?
permission_name_changed?
end
end
end
notice the :finders. I am running 5.0.3 for Friendly ID. Is this something new with active record or have I failed at using Friendly ID?
The finders module is compatible with Rails 4.2. only in the 5.1. version (not yet released). You can of course already test the version but keep in mind that it's still in beta.
gem "friendly_id", "5.1.0.beta.1"

RSpec hates Rails scope named :public when stubbing object

Is it just me or is it a global RSpec behavior that when I name my rails model scope :public, initialize object from this model, and stub this object Rspec fails
class DocumentName < ActiveRecord::Base
scope :public, lambda{where( public: true) } #line 3
end
nothing special, Rails application works
DocumentName.public # => [ #DN, #DN, #DN... ]
# SELECT `document_names`.* FROM `document_names` WHERE `document_names`.`public` = 1
however RSpec fails
describe DocumentName do
let(:resource){DocumentName.new}
it do
resource.stub(:name).and_return('foo') #line 16
resource.save.should be true
end
end
Failure/Error: resource.stub(:name).and_return('foo')
ArgumentError:
wrong number of arguments (1 for 0)
# ./app/models/document_name.rb:3:in `block in <class:DocumentName>'
# ./spec/models/document_name_spec.rb:16:in `block (2 levels) in <top (required)>'
...and funniest thing, I'm not doing anything with that scope in this scenario.
However if I name this scope something else than :public e.g: :are_public:
class DocumentName < ActiveRecord::Base
scope :are_public, lambda{where( public: true) }
end
...everything pass O_O
Rails 3.2.11 (but same thing on any 3.2.x)
Ruby ruby-2.0.0-rc1 ( but same for any ruby-1.9.3)
rspec-core (2.12.2)
rspec-expectations (2.12.1)
rspec-mocks (2.12.1)
rspec-rails (2.12.2)
private and public are Ruby's access modifiers:
class User
private
def some_private_method
end
public
def some_public_method
end
end
While they may seem like keywords, they are actually method calls. It's not really a good idea to overwrite them.

Rails Gem::LoadError in UsersController#new

New to Ruby on Rails and having a problem when following Michael Hartl's tutorial.I'm using Rails 3.2.2 with Ruby 1.9.3. The issue looks very similar to another question that was raised but was unanswered:
Rails Error NoMethodError in UsersController#show error
I get the following error when attempting to add a new user via /signup
Gem::LoadError in UsersController#new
bcrypt-ruby is not part of the bundle. Add it to Gemfile.
Reloading the page gives the error:
NoMethodError in UsersController#new
undefined method `key?' for nil:NilClass
The problem seems to be related to the inclusion of the bcrypt-ruby gem, and the usage of the has_secure_password method in user.rb . Removing the call to has_secure_password in user.rb gets rid of the error and it goes to the signup page successfully.
user.rb:
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string(255)
# email :string(255)
# created_at :datetime not null
# updated_at :datetime not null
# password_digest :string(255)
#
class User < ActiveRecord::Base
attr_accessible :name, :email, :password, :password_confirmation
has_secure_password
validates :name, presence: true, length: { maximum: 50 }
valid_email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true,
format: { with: valid_email_regex },
uniqueness: { case_sensitive: false }
validates :password, length: { minimum: 6}
end
users_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(params[:user])
if #user.save
flash[:success] = "Welcome!"
redirect_to #user
else
render 'new'
end
end
end
However, I cant find anything wrong with the inclusion of the bcrypt-ruby gem. In the Gemfile I have:
gem 'bcrypt-ruby', '3.0.1'
and the gem has also been generated in Gemfile.lock :
DEPENDENCIES
annotate (~> 2.4.1.beta)
bcrypt-ruby (= 3.0.1)
I've also added password_digest to the database via migration:
class AddPasswordDigestToUsers < ActiveRecord::Migration
def change
add_column :users, :password_digest, :string
end
end
Any ideas ?
I'm going through the same tutorial and encountered the exact same problem.
My solution was to restart the web server. After installing the gem, I think the web server needs to be restarted so it is loaded.
Justin
Did you tried the 'bundle update' command, usually the bundler will take care of gems if you specified in the Gemfile. If you want to check the gem dependency please check http://rubygems.org/gems.
And if you are using windows(I know its strange- but some of our app works in windows only) there is some tricks to install bcrypt
Steps to install bcrypt.
1 Download Devkit and extract
you can download it from here http://rubyinstaller.org/downloads/
2 Place devkit it your jruby folder (in my case C:\applications\jruby\devkit)
3 You need to install ruby as well either 1.8.7 or 1.9(some times needs a system restart)
4 CD into devkit directory
5 Run ruby dk.rb init
6 Open config.yml and make sure that both your jruby installtion is listed. If not, ADD them. Save and close config.yml after you're done.
example:- C:/applications/jruby
7 Run ruby dk.rb install
8 jruby -S gem install bcrypt-ruby
Restarting the web server fixed it for me (had spork running in the background to speed up the running of the tests)

Resources