Doing the Ruby on Rails Tutorial and I'm getting strange error message when running the test.
My user_test.rb:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com", password: "wordpass", password_confirmation: "wordpass")
end
test "should be valid" do
assert #user.valid?
end
test "name should be present" do
#user.name=" "
assert_not #user.valid?
end
test "email should be present" do
#user.email= " "
assert_not #user.valid?
end
test "name should not be too long" do
#user.name= "a" * 51
assert_not #user.valid?
end
test "email should not be too long" do
#user.email= "a" * 256
assert_not #user.valid?
end
test "email validation should accept valid addresses" do
valid_addresses = %w[user#example.com USER#foo.COM A_US-ER#foo.bar.org
first.last#foo.jp alice+bob#baz.cn]
valid_addresses.each do |valid_address|
#user.email = valid_address
assert #user.valid? , "#{valid_address.inspect} should be valid"
end
end
test "email validation should reject invalid addresses" do
invalid_addresses = %w[user#example,com user_at_foo.org user.name#example.
foo#bar_baz.com foo#bar+baz.com]
invalid_addresses.each do |invalid_address|
#user.email = invalid_address
assert_not #user.valid?, "#{invalid_address.inspect} should be invalid"
end
end
test "email addresses should be unique" do
duplicate_user = #user.dup
duplicate_user.email = #user.email.upcase
#user.save
assert_not duplicate_user.valid?
end
test "password should be a minimum length" do
#user.password = #user.password_confirmation = "a" * 5
assert_not #user.valid?
end
end
The user.rb :
class User < ActiveRecord::Base
attr_accessor :name, :email , :password, :password_confirmation
before_save { self.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 }
has_secure_password
validates :password, length: { minimum: 6 }
end
One of the errors seems to be from the user definition, but I cannot find the source of error. Is it something due related to "validates" in user.rb file ? Any help will be much appreciated !!
FAIL["test_email_validation_should_accept_valid_addresses", UserTest, 0.061796445]
test_email_validation_should_accept_valid_addresses#UserTest (0.06s)
"user#example.com" should be valid
test/models/user_test.rb:34:in `block (2 levels) in <class:UserTest>'
test/models/user_test.rb:32:in `each'
test/models/user_test.rb:32:in `block in <class:UserTest>'
FAIL["test_should_be_valid", UserTest, 0.080466737]
test_should_be_valid#UserTest (0.08s)
Failed assertion, no message given.
test/models/user_test.rb:8:in `block in <class:UserTest>'
Thanks in advance for your help !
You are right, one of the errors is due to #user being invalid in the first test. Do the following in rails console, this should print out errors on user model:
#user = User.new(name: "Example User", email: "user#example.com", password: "wordpass", password_confirmation: "wordpass")
#user.valid?
pp #user.errors
Try different regex in user.rb
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
well everything looks fine. just run the command
rake db:test:prepare
and if this doesnt work either then
$rake db:delete
rake db:create
rake db:migrate
first one worked for me
Related
Followed the instructions in chapter 6, tutorial test should be GREEN(no failures/errors), but I'm receiving the below error
Expecting the test results to pass. From the error, I understand there's a missing an arg, but unsure what to change
user_test.rb
test "email validation should accept valid addresses" do
valid_addresses = %w[user#example.com USER#foo.COM A_US-ER#foo.bar.org
first.last#foo.jp alice+bob#baz.cn]
valid_addresses.each do |valid_address|
#user.email = valid_address
assert #user.valid?, "#{valid_address.inspect} should be valid"
end
end
test "email validation should reject invalid addresses" do
invalid_addresses = %w[user#example,com user_at_foo.org user.name#example. foo#bar_baz.com foo#bar+baz.com]
invalid_addresses.each do |invalid_address|
#user.email = invalid_address
assert_not #user.valid?, "#{invalid_address.inspect} should be invalid"
end
end
#user.rb
class User < ApplicationRecord
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 }
end
ERROR["test_email_validation_should_accept_valid_addresses", UserTest, 0.41518251600001577]
test_email_validation_should_accept_valid_addresses#UserTest (0.42s)
ArgumentError: ArgumentError: wrong number of arguments (given 1, expected 2)
test/models/user_test.rb:41:in test'
test/models/user_test.rb:41:inblock in '
I have now managed to get this working. Appears the indentation on the tests was causing AWS cloud9 to throw an error asking for an expected keyword_end. I believe adding an extra end was creating the above error message. Solution: indented code correctly using the keyword_end in the correct places fixed my problem.
My tests had been running green up until I hit 6.17. Can anyone help me see what is wrong?
Here is the error and fail:
ERROR["test_layout_links", SiteLayoutTest, 0.011797307059168816]
test_layout_links#SiteLayoutTest (0.01s)
ArgumentError: ArgumentError: Range unspecified. Specify the :in,
:within, :maximum, :minimum, or :is option.
app/models/user.rb:3:in `<class:User>'
app/models/user.rb:1:in `<top (required)>'
FAIL["test_email_should_not_be_too_long", UserTest, 0.04466394800692797]
test_email_should_not_be_too_long#UserTest (0.04s)
Expected true to be nil or false
test/models/user_test.rb:29:in `block in <class:UserTest>'
12/12: [=============================================================] 100%
Time: 00:00:00, Time: 00:00:00
Finished in 0.62805s
12 tests, 15 assertions, 1 failures, 1 errors, 0 skips
Here is my user.rb file:
class User < ApplicationRecord
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true, length: { maxmium: 255 }
end
Here is my user_test.rb file:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(name: "Example User", email: "user#example.com")
end
test "should be valid" do
assert #user.valid?
end
test "name should be present" do
#user.name = " "
assert_not #user.valid?
end
test "email should be present" do
#user.email = " "
assert_not #user.valid?
end
test "name should not be too long" do
#user.name = "a" * 51
assert_not #user.valid?
end
test "email should not be too long" do
#user.email = "a" * 244 + "#example.com"
assert_not #user.valid?
end
end
And here is my site_layout_test.rb file since it is somehow involved:
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
test "layout links" do
get root_path
assert_template 'static_pages/home'
assert_select "a[href=?]", root_path, count: 2
assert_select "a[href=?]", help_path
assert_select "a[href=?]", about_path
assert_select "a[href=?]", contact_path
get contact_path
assert_select "title", full_title("Contact")
get signup_path
assert_select "title", full_title("Sign Up")
end
end
I've combed these files for typos and can't seem to find what is going on. Thanks for any help you can provide.
Have a spell check on maximum the user.rb file.
You have mispelled maximum for maxmium
The code should be like
class User < ApplicationRecord
validates :name, presence: true, length: { maximum: 50 }
validates :email, presence: true, length: { maximum: 255 }
end
I wanted to do a simple regex-based email validation:
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
unless value =~ /\A([\S]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || 'is not an email')
end
end
end
Which is mentioned in rails documentation.
I have checked it in rubular and everythings works fine, but in rails, emails with dot in local address fails validation for some reason (john.doe#example.com). What's weird is that it accepts any other non-whitespace characters (e.g &^%#!*() excluding # of course).
class User < ApplicationRecord
validates :email, presence: true, length: { maximum: 64 },
uniqueness: { case_sensitive: false }, email: true
validates :password, presence: true, length: { in: 8..64 }
validates :first_name, length: { in: 2..16 }, allow_blank: true
validates :last_name, length: { in: 2..32 }, allow_blank: true
validates :student_id, length: { in: 5..6 }, allow_blank: true,
numericality: true
end
And failing test:
test 'should validate email with special characters in local address' do
#user.email = 'john.doe#domain.com'
assert #user.valid?
end
Whole user_test.rb
class UserTest < ActiveSupport::TestCase
def setup
#user = User.new(email: 'johndoe#domain.com', password: 'password12',
first_name: 'John', last_name: 'Doe',
student_id: '112233')
end
# Presence validation
test 'user validate user' do
assert #user.valid?
end
test 'should not validate empty email' do
#user.email = ''
assert_not #user.valid?
end
test 'should not validate blank password' do
#user.password = ' '
assert_not #user.valid?
end
test 'should validate blank first name' do
#user.first_name = ''
assert #user.valid?
end
test 'should validate blank last name' do
#user.last_name = ''
assert #user.valid?
end
test 'should validate blank student id' do
#user.student_id = ''
assert #user.valid?
end
# Length validation
test 'should not validate too long email' do
#user.password = 'a' * 65
assert_not #user.valid?
end
test 'should not validate too long password' do
#user.password = 'a' * 65
assert_not #user.valid?
end
test 'should not validate too short password' do
#user.password = 'a' * 7
assert_not #user.valid?
end
test 'should not validate too long first name' do
#user.first_name = 'a' * 17
assert_not #user.valid?
end
test 'should not validate too short first name' do
#user.first_name = 'a'
assert_not #user.valid?
end
test 'should not validate too long last name' do
#user.last_name = 'a' * 33
assert_not #user.valid?
end
test 'should not validate too short last name' do
#user.last_name = 'a'
assert_not #user.valid?
end
test 'should not validate too long student id' do
#user.student_id = '1234567'
assert_not #user.valid?
end
test 'should not validate too short student id' do
#user.student_id = '1234'
assert_not #user.valid?
end
# Email format validation
test 'should not validate email with wrong format' do
#user.email = 'john.doe#domain'
assert_not #user.valid?
end
test 'should validate email with special characters in local address' do
#user.email = 'john.doe#domain.com'
assert #user.valid?
end
test 'should not validate email with special characters in domain' do
#user.email = 'john.doe#dom_ain.com'
assert_not #user.valid?
end
# Numeric-only validation
test 'should not validate student id with non-numeric characters' do
#user.student_id = 'ab123c'
assert_not #user.valid?
end
# Uniqueness validation
test 'should not validate duplicated email' do
#copycat_user = #user.dup
#user.save
assert_not #copycat_user.valid?
end
end
Any idea what could be the reason for that weird behaviour?
I've got the resolution.
I had fixture with same parameters as
#user = User.new(email: 'johndoe#domain.com', password: 'password12',
first_name: 'John', last_name: 'Doe',
student_id: '112233')
Since email must be unique, it gave me an error that email has already been taken.
I looked on stack overflow for an answer and found a few people who posted on similar problems but the solutions didn't help. From what I can tell my code is exactly right.
I am following the tutorial on:
http://ruby.railstutorial.org/chapters/modeling-users#code-validates_uniqueness_of_email_case_insensitive_test
require 'spec_helper'
describe User do
before { #user = User.new(name: "Example User", email: "user#example.com") }
subject { #user }
it { should respond_to(:name) }
it { should respond_to(:email) }
it { should be_valid }
describe "when name is not present" do
before { #user.name = " " }
it { should_not be_valid }
end
describe "when email is not present" do
before { #user.email = " " }
it { should_not be_valid }
end
describe "when name is too long" do
before { #user.name = "a" * 51 }
it { should_not be_valid }
end
describe "when email format is invalid" do
it "should be invalid" do
addresses = %w[user#foo,com user_at_foo.org example.user#foo. foo#bar_baz.com foo#bar+baz.com]
addresses.each do | invalid_address |
#user.email = invalid_address
expect(#user).not_to be_valid
end
end
end
describe "when email format is valid" do
it "should be valid" do
addresses = %w[user#foo.COM A_US-ER#f.b.org frst.lst#foo.jp a+b#baz.cn]
addresses.each do | valid_address |
#user.email = valid_address
expect(#user).to be_valid
end
end
end
describe "when email address is already taken" do
before do
user_with_same_email = #user.dup
user_with_same_email.email = #user.email.upcase
user_with_same_email.save
end
#it "should not be valid" do
# expect(#user).not_to be_valid
#end
it { should_not be_valid }
end
end
The last specification is failing.
My User validation is as such:
class User < ActiveRecord::Base
before_save { self.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_sensative: false }
end
I followed the tutorial perfectly and yet I can't seem to get this validation to work properly. I know this tutorial is a bit old and I may be using a few newer gems. I also know this isn't the best way to do this type of validation but the tutorial is just making it really simple at first. What is going on here?
Thank you!
EDIT:
There is no error. The validation is giving a failure when it should be success.
Failures:
1) User when email address is already taken should not be valid
Failure/Error: it { should_not be_valid }
expected #<User id: nil, name: "Example User", email: "user#example.com", created_at: nil, updated_at: nil> not to be valid
# ./spec/models/user_spec.rb:58:in `block (3 levels in <top (required)>'
Finished in 0.09887 seconds
1 example, 1 failure
Edit again. user_spec.rb has been completely pasted in quest. Sorry I am really new at ruby and didn't realize what might be needed to help troubleshoot.
If you continue reading the tutorial you realise that the author says that the test is still not completed to be passed. That's because the current validation is still case sensitive.
Adding uniqueness: { case_sensitive: false } makes the test passed as expected
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
I think it just solved itself. Maybe someone can explain what just happened. I decided to just continue with the tutorial and added gem 'bcrypt-ruby', '3.1.2' to the gemfile. Then I ran bundle install.
Then I tried to run rspec spec/ and it returned an error:
Migrations are pending; run 'bin/rake db:migrate RAILS_ENV=development' to resolve this issue.
But when I ran rake db:migrate nothing happened. SO I googled and found this SO post which had a solution.
I ran:
rake test:prepare
rake db:migrate
and then all tests passed.
Perhaps my test environment went crazy on me? I still don't know what just happened.
You can add user_with_same_email.valid? before .save and provide its output, but I believe it will be true, because:
you haven't changed the id of #user
you just change the case of email, but it is as also valid, so "A#A.COM", and "a#a.com" are the same, and valid.
#valid returns true since :email is present, have good Regexp, and still unique.
Well I've searched all over the place and it seems that nobody else has the issue with this 'encrypt' method causing their tests to fail, though it seems plenty others have had some difficulty with chapter 7. Without further adieu,
Here's the link to Hartl's Chapter 7
My code in the user model file, and the corresponding spec file, appear to be completely exact to what he has written and I still cannot get the tests to pass. The errors?
Failures:
1) User should create a new instance given valid attributes
Failure/Error: User.Create!(#attr)
NoMethodError: undefined method 'encrypt' for #<User:asdf>
#./app/models/user.rb:22:in 'has_password?'
#./app/models/user.rb:28:in 'encrypt_password'
#./spec/models/user_spec.rb:15:in 'block (2 levels) in <top (required)>'
2) User should not allow duplicate email addresses
Failure/Error: User.Create!(#attr)
NoMethodError: undefined method 'encrypt' for #<User:asdf>
#./app/models/user.rb:22:in 'has_password?'
#./app/models/user.rb:28:in 'encrypt_password'
#./spec/models/user_spec.rb:15:in 'block (2 levels) in <top (required)>'
3) User should reject email addresses identical up to case
Failure/Error: User.Create!(#attr)
NoMethodError: undefined method 'encrypt' for #<User:asdf>
#./app/models/user.rb:22:in 'has_password?'
#./app/models/user.rb:28:in 'encrypt_password'
#./spec/models/user_spec.rb:15:in 'block (2 levels) in <top (required)>'
...
7) User has_password? method should be false if passwords do not match
Failure/Error: User.Create!(#attr)
NoMethodError: undefined method 'encrypt' for #<User:asdf>
#./app/models/user.rb:22:in 'has_password?'
#./app/models/user.rb:28:in 'encrypt_password'
#./spec/models/user_spec.rb:15:in 'block (3 levels) in <top (required)>'
so i'm getting the same error messages for each test and I am going nuts trying to find out why!
Here's my user.rb:
require 'digest'
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :name, :email, :password, :password_confirmation
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, :presence => true,
:length => { :maximum => 50 }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
#automatically create the virtual attribute for 'password_confirmation'
validates :password, :presence => true,
:confirmation => true,
:length => { :within => 6..40 }
before_save :encrypt_password
#returns true if the users password matches the submitted one
def has_password?(submitted_password)
encrypted_password == encrypt(submitted_password)
end
private
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
def encrypt_string
secure_hash("#{salt}--#{string}")
end
def make_salt
secure_hash("#{Time.now.utc}--#{password}")
end
def secure_hash(string)
Digest::SHA2.hexdigest(string)
end
end
and my user_spec.rb file:
require 'spec_helper'
require 'digest'
describe User do
before(:each) do
#attr = {
:name => "User Name",
:email => "example#email.com",
:password => "password",
:password_confirmation => "password"
}
end
it "should create a new instance given valid attributes" do
User.create!(#attr)
end
it "should require a name" do
no_name_user = User.new(#attr.merge(:name => ""))
no_name_user.should_not be_valid
end
it "should require an email" do
no_email_user = User.new(#attr.merge(:email => ""))
no_email_user.should_not be_valid
end
it "should reject names that are too long" do
long_name = "a" * 51
long_name_user = User.new(#attr.merge(:name => long_name))
long_name_user.should_not be_valid
end
it "should accept valid email addresses" do
addresses = %w[user#foo.com THE_USER#foo.bar.org first.last#foo.jp]
addresses.each do |address|
valid_email_user = User.new(#attr.merge(:email => address))
valid_email_user.should be_valid
end
end
it "should reject invalid email addresses" do
addresses = %w[user#foo,com user_at_foo.org example.user#foo.]
addresses.each do |address|
invalid_email_user = User.new(#attr.merge(:email => address))
invalid_email_user.should_not be_valid
end
end
it "should not allow duplicate email addresses" do
User.create!(#attr)
user_with_duplicate_email = User.new(#attr)
user_with_duplicate_email.should_not be_valid
end
it "should reject email addresses identical up to case" do
upcased_email = #attr[:email].upcase
User.create!(#attr.merge(:email => upcased_email))
user_with_duplicate_email = User.new(#attr)
user_with_duplicate_email.should_not be_valid
end
describe "password validations" do
it "should require a password" do
User.new(#attr.merge(:password => "", :password_confirmation => ""))
should_not be_valid
end
it "should require password to match the password confirmation" do
User.new(#attr.merge(:password_confirmation => "invalid"))
should_not be_valid
end
it "should reject short passwords" do
short = "a" * 5
hash = #attr.merge(:password => short, :password_confirmation => short)
User.new(hash).should_not be_valid
end
it "should reject long passwords" do
long = "a" * 41
hash = #attr.merge(:password => long, :password_confirmation => long)
User.new(hash).should_not be_valid
end
end
describe "password encryption" do
before(:each) do
#user = User.create!(#attr)
end
it "should have an encrypted password attribute" do
#user.should respond_to(:encrypted_password)
end
it "should not allow a blank encrypted password" do
#user.encrypted_password.should_not be_blank
end
end
describe "has_password? method" do
before(:each) do
#attr = User.create!(#attr)
end
it "should be true if the passwords match" do
#user.has_password?(#attr[:password]).should be_true
end
it "should be false if the passwords don't match" do
#user.has_password?("invalid").should be_false
end
end
end
Any help would be greatly appreciated. I've poured over other's problems, my code, and changed various aspects to try and get the tests to work, all to no avail. I hope it's not something really stupid I'm still not seeing.
Your error is here:
def encrypt_string
secure_hash("#{salt}--#{string}")
end
You are calling encrypt in the following encrypt_password method but your method above is named encrypt_string:
def encrypt_password
self.salt = make_salt unless has_password?(password)
self.encrypted_password = encrypt(password)
end
Just change encrypt_string to encrypt in the method definition and you should be good to go.