Fixed. There was a bug in Rails. See https://github.com/rails/rails/issues/2333
I have a problem with Factory Girl Rails and Rails 3.1.0.rc5
When I do more than once user = FactoryGirl.create(:user) I have an error.
Failure/Error: user = FactoryGirl.create(:user)
NameError:
uninitialized constant User::User
# ./app/models/user.rb:17:in `generate_token'
# ./app/models/user.rb:4:in `block in <class:User>'
# ./spec/requests/users_spec.rb:20:in `block (3 levels) in <top (required)>'
I can create as many user as I want using Factory but only in rails console.
Tests:
require 'spec_helper'
describe "Users" do
describe "signin" do
it "should sign in a user" do
visit root_path
user = FactoryGirl.create(:user)
within("div#sign_in_form") do
fill_in "Name", with: user.name
fill_in "Password", with: user.password
end
click_button "Sign in"
current_path.should eq(user_path(user))
page.should have_content("signed in")
end
it "should not show new user form on /" do
user = FactoryGirl.create(:user)
visit root_path
page.should_not have_css("div#new_user_form")
end
end
end
factories.rb
FactoryGirl.define do
factory :user do |f|
f.sequence(:name) { |n| "john#{n}" }
f.fullname 'Doe'
f.sequence(:email) { |n| "test#{n}#example.com" }
f.password 'foobar'
end
end
model/user.rb
class User < ActiveRecord::Base
has_secure_password
attr_accessible :name, :fullname, :email, :password
before_create { generate_token(:auth_token) }
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, presence: true, length: { maximum: 20 },
uniqueness: { case_sensitive: false }
validates :fullname, presence: true, length: { maximum: 30 }
validates :email, format: { with: email_regex },
uniqueness: { case_sensitive: false }, length: { maximum: 30 }
validates :password, length: { in: 5..25 }
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while User.exists?(column => self[column])
end
end
User.exists?(column => self[column]) causes the problem.
Somehow the class is not properly looked up, and I am not sure how this is happenning but could you try accessing it differently:
def generate_token(column)
begin
self[column] = SecureRandom.urlsafe_base64
end while self.class.exists?(column => self[column])
end
You've got an extra line i your factories.rb, it should read like this:
FactoryGirl.define :user do |f|
f.sequence(:name) { |n| "john#{n}" }
f.fullname 'Doe'
f.sequence(:email) { |n| "test#{n}#example.com" }
f.password 'foobar'
end
This should work:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "john#{n}" }
fullname 'Doe'
sequence(:email) { |n| "test#{n}#example.com" }
password 'foobar'
end
end
Related
I have a problem with my testing in rails with rspec. All in all I have a structure between 4 models, but for the moment I try to solve my testing for two of them. I'm using faker and FactoryGirl and have the following factories:
require 'faker'
FactoryGirl.define do
factory :user do |f|
f.name { Faker::Name}
f.email { Faker::Internet.email}
f.password {Faker::Internet.password}
f.role {"Kindergarten"}
end
end
require 'faker'
FactoryGirl.define do
factory :child do |f|
f.name { Faker::Name}
f.city { Faker::Address.city}
f.postalcode {Faker::Number.between(30000,35000)}
f.streed {Faker::Address.street_name}
f.add_number {Faker::Address.secondary_address}
f.disability { Faker::Boolean.boolean}
f.halal { Faker::Boolean.boolean}
f.koscha {Faker::Boolean.boolean}
f.vegetarian {Faker::Boolean.boolean}
f.vegan {Faker::Boolean.boolean}
f.allday { Faker::Boolean.boolean}
f.gender { Faker::Number.between(0,1)}
f.user_id {Faker::Number.between(1,10)}
end
end
and my controller test looks like that
require 'rails_helper'
require 'factory_girl_rails'
describe UsersController do
before do
3.times { FactoryGirl.create(:child)}
end
describe "GET #show" do
let(:user) { FactoryGirl.create(:user) }
before { get :show, id: user.id}
it "assigns the requested user to #user" do
assigns(:user).should eq user
end
it "renders the :show template"
end
describe "GET #new" do
let(:user) { FactoryGirl.create(:user) }
it "assigns a new User to #user" do
get :new, id: user.id
assigns(:user).should be_a_new(User)
end
it "renders the :new template"
end
end
When I try to run the test, I got this error message
UsersController GET #new assigns a new User to #user
Failure/Error: 3.times { FactoryGirl.create(:child)}
ActiveRecord::RecordInvalid:
Validation failed: User can't be blank
My relations and validations in the models are as follow
class Child < ApplicationRecord
has_many :relations, :dependent => :destroy
accepts_nested_attributes_for :relations
belongs_to :user
validates :user, presence: true
validates :name, presence: true, length: { maximum: 50 }
validates :city, presence: true, :on => :create
validates :postalcode, presence: true, numericality: true
validates :streed, presence: true
validates :add_number, presence: true
validates :disability, inclusion: { in: [true, false] }
validates :halal, inclusion: { in: [true, false] }
validates :koscha, inclusion: { in: [true, false] }
validates :vegetarian, inclusion: { in: [true, false] }
validates :vegan, inclusion: { in: [true, false] }
validates :allday, inclusion: { in: [true, false] }
validates :gender, presence: true
end
class User < ApplicationRecord
attr_accessor :remember_token, :activation_token, :reset_token
has_many :children, dependent: :destroy
has_many :kindergartens, dependent: :destroy
has_many :relations, dependent: :destroy
before_save :downcase_email
before_create :create_activation_digest
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
validates :role, presence: true
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
end
My problem is, that I'm not sure if there is a fault in my rspec code or if I have made a mistake in my validations and relations in my normal models. Can someone help me?
I think that it would be better to post the whole factory for you. And I think you don't need to require faker if you have it in Gemfile.
FactoryGirl.define do
factory :child do
name { Faker::Name}
city { Faker::Address.city}
postalcode {Faker::Number.between(30000,35000)}
streed {Faker::Address.street_name}
add_number {Faker::Address.secondary_address}
disability { Faker::Boolean.boolean}
halal { Faker::Boolean.boolean}
koscha {Faker::Boolean.boolean}
vegetarian {Faker::Boolean.boolean}
vegan {Faker::Boolean.boolean}
allday { Faker::Boolean.boolean}
gender { Faker::Number.between(0,1)}
user
end
end
Inside specs when you need to create a child for the particular user:
let(:current_user) { create :user }
let(:child) { create :child, user: current_user }
Try to change your controller spec:
describe UsersController do
let(:user) { create(:user) }
describe "GET #show" do
before { get :show, params: { id: user.id } }
it "assigns the requested user to #user" do
assigns(:user).should eq user
end
it "renders the :show template"
it { expect(response).to have_http_status 200 }
end
describe "GET #new" do
before { get :new }
it "assigns a new User to #user" do
assigns(:user).should be_a_new(User)
end
it "renders the :new template"
end
end
i have been even trying pending on this but it still gives error.
Userfactory
FactoryGirl.define do
sequence :email do |n|
"email#{n}#evercam.io"
end
factory :user, class: :EvercamUser do
sequence(:firstname) { |n| "firstname#{n}" }
sequence(:lastname) { |n| "lastname#{n}" }
sequence(:username) { |n| "username#{n}" }
sequence(:password) { |n| "password#{n}" }
email
sequence(:api_id) {|n| SecureRandom.hex(10)}
sequence(:api_key) {|n| SecureRandom.hex(16)}
# is_admin false
country do
country = Country.where(iso3166_a2: 'ie').first
country || create(:ireland)
end
end
end
UserSpec
require 'rails_helper'
RSpec.describe User, type: :model do
describe 'validations' do
it { should validate_presence_of :email }
it { should validate_presence_of :firstname }
it { should validate_presence_of :lastname }
it { should validate_presence_of :username }
it { should validate_presence_of :encrypted_password }
describe 'email uniqueness' do
before { create :user, email: 'foo#bar.com' }
let(:user) { build :user, email: 'foo#bar.com' }
it do
user.valid?
expect(user.errors[:email]).to be == ['has already been taken']
end
end
end
describe 'associations' do
it { should belong_to(:country) }
# it { should have_many(:camera_shares) }
end
it 'has a valid factory' do
expect(build(:user)).to be_valid
end
end
and here is my UserModel which is Devise
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
belongs_to :country
validates :firstname, presence: true
validates :lastname, presence: true
validates :username, presence: true
validates :encrypted_password, presence: true
def fullname
"#{firstname} #{lastname}"
end
def self.created_months_ago(number)
given_date = number.months.ago
User.where(created_at: given_date.beginning_of_month..given_date.end_of_month)
end
end
I have even tried to give "pending" to all blocks but it still giving me error i dont know where i am wrong on this
Any help will be appreciated thanks
it { should validate_presence_of :email }
If it fails on the line above, it is because the model does not in fact have a validation for :email:
validates :firstname, presence: true
validates :lastname, presence: true
validates :username, presence: true
validates :encrypted_password, presence: true
# validates :email, presence: true # <---- missing in action
i have a little problem with sorcery
this is my test :
def setup
#user = users(:anouar)
end
test "should be valid" do
assert #user.valid?
end
and this is my fixture :
anouar:
email: anouar#gmail.com
salt: <%= salt = "asdasdastr4325234324sdfds" %>
crypted_password: <%= Sorcery::CryptoProviders::BCrypt.encrypt("secret", salt) %>
and my model :
class User < ActiveRecord::Base
authenticates_with_sorcery!
validates :email, presence: true, length: { maximum: 255 },
email_format: { message: 'has invalid format' },
uniqueness: { case_sensitive: false }
end
until here when i run bundle exec rake test the test is green
but when i add the validation of the password
validates :password, presence: true, confirmation: true, length: { minimum: 3}
the test "should be valid" is fail
please help?
Did you try to provide directly a password in your fixture ?
I'm doing the ruby on rails tutorial book and I have come to an error. I checked everything he wrote and I still get the error. It tells me authenticate is an undefined method for nil:NILclass. I don't know what to do.
user.rb:
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
attr_accessor :password, :password_confirmation
has_secure password
before_save { |user| user.email = email.downcase }
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, presence: true, length:{ minimum: 6 }
validates :password_confirmation, presence: true
end
and (some of) my user_spec.rb
before do
#user = User.new(name: "Example User", email: "User#example", password: "foobar", password_confirmation:"foobar")
end
subject { #user }
it { should respond_to(:password_digest) }
it { should respond_to(:password) }
it { should respond_to(:password_confirmation) }
it { should respond_to(:authenticate) }
it { should be_valid }
# USER.PASSWORD
describe "when password is not present" do
before { #user.password = #user.password_confirmation = " "}
it {should_not be_valid}
end
describe "when password is not present" do
before { #user.password_confirmation = "mismatch" }
it { should_not be_valid }
describe "when password is nil" do
before { #user.password_confirmation = nil }
it {should_not be_valid}
end
describe "with a password that's too short" do
before { #user.password = #user.password_confirmation = "a" * 5 }
it { should be_valid }
end
describe "return value of authenticate method" do
before { #user.save }
let(:found_user) { User.find_by_email(#user.email) }
describe "with valid password" do
it { should == found_user.authenticate(#user.password) }
end
describe "with invalid password" do
let(:user_for_invalid_password) { found_user.authenticate("invalid") }
it {should_not == user_for_invalid_password}
specify { user_for_invalid_password.should be_false}
end
end
end
Thanks alot for all that can help.
I am new in ruby on rails.I just pass this tutorials. when I doing I found errors same you.
I hope my solved can help you.
in your user.rb
remove line: attr_accessor and edit has_secure password to has_secure_password (add underscore)
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
enter code here
before_save { |user| user.email = email.downcase }
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, presence: true, length:{ minimum: 6 }
validates :password_confirmation, presence: true
end
in your user.spec.rb
1) you missed 'end' tag in describe "when password is not present"
2) Change test describe 'with a password that's too short'
from it { should be_valid} to it { should be_invalid } I think it should be invalid if password less than 5.
3) finally if you want to test pass authenticate you should change your email end with .com or any that matches with VALID_EMAIL_REGEX in user.rb like:
before do
#user = User.new(name: "Example User", email: "User#example.com",
password: "foobar", password_confirmation:"foobar")
end
I wish this help you.
sorry for my bad english.
Here's my Model code:
class User < ActiveRecord::Base
validates :email, :presence => true,
:uniqueness => true,
:format => {
:with => %r{^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])*#([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$},
:message => "You must enter a valid email address."
}
validates :password, :presence => true,
:confirmation => true,
:length => { :in => 6..20 }
validates :password_confirmation, :presence => true
validates :firstname, :presence => true
validates :lastname, :presence => true
end
And my test:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "user email must not be empty" do
user = User.new
assert user.invalid?
assert user.errors[:email].any?
end
test "user password must be between 6 and 20 characters" do
user = User.new(:email => "stapia.gutierrez#gmail.com",
:firstname => "sergio",
:lastname => "tapia")
user.password = "123"
assert user.invalid?
user.password = ""
assert user.invalid?
#6 characters.
user.password = "123456"
assert user.valid?
#20 characters.
user.password = "12345678901234567890"
assert user.valid?
#21 characters.
user.password = "123456789012345678901"
assert user.invalid?
end
end
And the result of the tests:
sergio#sergio-VirtualBox:~/code/ManjarDeOro$ rake test:units
Run options:
# Running tests:
.F
Finished tests in 0.105599s, 18.9395 tests/s, 47.3488 assertions/s.
1) Failure:
test_user_password_must_be_between_6_and_20_characters(UserTest) [/home/sergio/code/ManjarDeOro/test/unit/user_test.rb:24]:
Failed assertion, no message given.
2 tests, 5 assertions, 1 failures, 0 errors, 0 skips
So the assertion fails on this bit:
#6 characters.
user.password = "123456"
assert user.valid?
So what is going on? Is my conditional for the assertion incorrect? I thought a 6 character password would turn my "user" object to .valid.
I'm new to Rails.
Your user wasn't validated because you missed the password_confirmation part of the user.
user.password = "123456"
user.password_confirmation = "123456"
assert user.valid?