A few classmates and I are having some trouble in our Rails app for class. Whenever we try to user the User.create for a RoR app on the rails console, we get a rollback transaction after we complete the necessary form.
Any way to fix this? Here is the error:
rails console
Loading development environment (Rails 3.2.13)
irb(main):001:0> User.count
(0.0ms) SELECT COUNT(*) FROM "users"
=> 0
irb(main):002:0> User.create(name: "Mr Rush", email: "rush#example.com", password: "fubar", password_confirmation: "fubar")
(0.0ms) begin transaction
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('rush#example.com') LIMIT 1
(0.0ms) rollback transaction
=> #<User id: nil, name: "Mr Rush", email: "rush#example.com", created_at: nil, updated_at: nil, password_digest: "$2a$10$quwMA.4fcrBpg2sRy00qEOWrjHduAN0OZFvcXiCmNjUR...">
irb(main):003:0>
User.rb file
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = user.email.downcase }
validates :name, presence: true, length: {maximum: 30}
VALID_EMAIL_REGEX = /\A[\w+\-\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 5 }
validates :password_confirmation, presence: true
end
Your user is failing to create because the email is failing the format validation.
It's interesting though that it reports this error as if the uniqueness is the thing causing the problem. You have shown your user table to be empty so no way it can fail a uniqueness constraint.
A couple of things to try:
1) in the console try this:
user = User.new(name: "Mr Rush", email: "rush#example.com", password: "fubar", password_confirmation: "fubar")
user.valid? <--- should give you false
user.errors <--- should tell you the format of the email is incorrect
When I combine presence with anything else in a validator I always allow the value to be blank in the following validations; there is no point in validating the format or uniquessness of something if it is mandatory but missing. i.e.
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX, allow_blank: true}, uniqueness: { case_sensitive: false, allow_blank: true }
Doing this may or may not change what it thinks the real validation failure is.
2) fix the regex for email validation. Validating email address by regex is a bit controversial, but you should find something like this will work:
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
You can always try out the regex validation using a website like Rubular.
User.create(name: "Mr Rush", email: "rush#example.com", password: "fubar", password_confirmation: "fubar")
When running into this while doing Michael Hartls Rails Tutorial this example will fail because the password fubar is too short, as set to minimum: 6 in Listing 6.39. The console is really less than verbose here.
Related
I'm working on a modified version of Michael Hartl's Learn Rails Tutorial. I'm on chapter 6, modeling users. For some reason, my users aren't creating correctly on ActiveRecord and aren't saving at all.
I placed these users in my seeds.rb file
user_1 = User.create(id: 1, name: 'Han Solo', email: 'han#example.com')
user_2 = User.create(id: 2, name: 'Luke Skywalker', email: 'luke#example.com')
Then I run rails db:seed, but if I go to my rails console, it appears like no users have been created:
Running via Spring preloader in process 24358
Loading development environment (Rails 5.0.0.1)
2.2.2 :001 > User.delete_all
SQL (1.1ms) DELETE FROM "users"
=> 0
2.2.2 :002 >
user.rb User Model
class User < ApplicationRecord
#Ensure Email Uniqueness by Downcasing the Email Attribute
before_save {self.email = email.downcase }
#validates name, presence, and length
validates :name, presence: true, length: { maximum: 100 }
#Validate presence, length, format, and uniqueness (ignoring case)
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: {maximum: 250}, format: {with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
#Adds ability to save securely hashed password_digest attribute to database
#Adds a pair of virtual attributes (password and password_confirmation)
#including presence validations upon object creation and a validation
#requiring that they match
#adds authenticate method that returns the user when the password is correct (and false otherwise)
has_secure_password
PASSWORD_FORMAT = /\A
(?=.{8,}) # Must contain 8 or more characters
(?=.*\d) # Must contain a digit
(?=.*[a-z]) # Must contain a lower case character
(?=.*[A-Z]) # Must contain an upper case character
(?=.*[[:^alnum:]]) # Must contain a symbol
/x
validates :password, presence: true, length: {minimum: 8}, format: {with: PASSWORD_FORMAT}
end
schema.rb
ActiveRecord::Schema.define(version: 20161020211218) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "users", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
end
end
Anyone have any idea what might be going on?
Ok, I figured it out.
I took out id from the seeds.rb. When I took out the id attribute, it started throwing me the error of the user not having a valid password. I then added a password and password confirmation to conform to password standards set in my user model.
Updated my model and added a password confirmation.
Here's my updated user.rb
class User < ApplicationRecord
#Ensure Email Uniqueness by Downcasing the Email Attribute
before_save {self.email = email.downcase }
#validates name, presence, and length
validates :name, presence: true, length: { maximum: 100 }
#Validate presence, length, format, and uniqueness (ignoring case)
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, length: {maximum: 250}, format: {with: VALID_EMAIL_REGEX }, uniqueness: {case_sensitive: false}
#Adds ability to save securely hashed password_digest attribute to database
#Adds a pair of virtual attributes (password and password_confirmation)
#including presence validations upon object creation and a validation
#requiring that they match
#adds authenticate method that returns the user when the password is correct (and false otherwise)
has_secure_password
PASSWORD_FORMAT = /\A
(?=.{8,}) # Must contain 8 or more characters
(?=.*\d) # Must contain a digit
(?=.*[a-z]) # Must contain a lower case character
(?=.*[A-Z]) # Must contain an upper case character
(?=.*[[:^alnum:]]) # Must contain a symbol
/x
validates :password, presence: true, length: {minimum: 8}, format: {with: PASSWORD_FORMAT}
validates :password_confirmation, presence: true
end
And seeds.rb
user_1 = User.create!(name: 'Han Solo', email: 'han#example.com', password: 'Password123!', password_confirmation: 'Password123!')
user_2 = User.create!(name: 'Luke Skywalker', email: 'luke#example.com', password: 'Password123!', password_confirmation: 'Password123!')
I tested that the user is being created properly by opening up the rails console, running User.delete_all , and seeing them wiped off the SQL record.
I'm having a weird problem with getting my user registration to work in Rails. When I create a user, it will show all its fields but the password_digest being nil, but when I type something like "u.email", the email will show up. However, it doesn't want to save the user, I assume because it thinks it doesn't meet all the validation requirements.
Some rails console fiddling:
irb(main):003:0> u = User.new({username: "askddkasd", email: "a#a.a",
password: "meowmeowmeow", password_confirmation: "meowmeowmeow"})
=> #<User id: nil, username: nil, email: nil, password_digest:
"$2a$10$eWhQdOCLXfmcGrrRdigSFeENUeAEaQ6xJ7U08k7g3gZ...", salt: nil>
irb(main):002:0> u.save
(0.2ms) BEGIN
User Exists (0.3ms) SELECT 1 AS one FROM `users` WHERE `users`.`username` = BINARY 'askddkasd' LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'a#a.a' LIMIT 1
(0.1ms) ROLLBACK
=> false
irb(main):022:0> u.username
=> "askddkasd"
irb(main):023:0> u.email
=> "a#a.a"
As you can see, the fields appear nil, but I can access their values.
Here is my user model:
class User < ApplicationRecord
has_secure_password
attr_accessor :username, :email, :password, :password_confirmation
validates :username, :presence => true, :uniqueness => true, :length => { :in => 3..20 }
validates :email, :presence => true, :uniqueness => true
validates :password, :confirmation => true #password_confirmation attr
validates_length_of :password, :in => 6..20, :on => :create
after_save :clear_password
def password=(password)
self.password_digest = BCrypt::Password.create(password)
end
def is_password?(password)
BCrypt::Password.new(self.password_digest) == password
end
def clear_password
self.password = nil
end
def self.authenticate(username_or_email="", login_password="")
if username_or_email.include? '#'
user = User.find_by_email(username_or_email)
else
user = User.find_by_username(username_or_email)
end
if user && user.is_password?(login_password)
return user
end
return false
end
end
Has anyone had this problem before? If so, how did you resolve it?
Update: Could it be because I have username and email as accessors? So those values don't actually get to the username/email fields to be stored in the database?
The fact that it rolls back after this statement in the log
User Exists (0.2ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = BINARY 'a#a.a' LIMIT 1
makes me think that there is already a user in the database with this email address. You can figure out for sure what the issue is by calling u.valid? and then u.errors.
I created a users model in a rails 4.1.8 application with the attributes email and password. I fired up rails console, user = User.new(email: "user#example.com" , password: "example") work but user.save saves the password and omits the email. below is the model, migrated database file and rails console log.
USER MODEL
class User < ActiveRecord::Base
before_save {self.email = email.downcase! }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true, length: { maximum: 255 },
format:{with: VALID_EMAIL_REGEX},
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
end
DATABASE FILE (For the User)
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :email, unique: true
t.string :password_digest
t.timestamps null: false
end
end
end
RAILS CONSOLE LOG
<r.new(email: "user#example.com" , password: "example")
=> #<User id: nil, email: "user#example.com", password_digest: "$2a$10$jxwd/oriT
z2HklHK4b4nf.P.DWb6s35YTO.EbYwup0I...", created_at: nil, updated_at: nil>
irb(main):008:0> user.save
(1.0ms) BEGIN
User Exists (1.0ms) SELECT 1 AS one FROM `users` WHERE `users`.`email` = 'user#example.com' LIMIT 1
SQL (46.0ms) INSERT INTO `users` (`created_at`, `password_digest`, `updated_at`) VALUES ('2015-07-20 20:54:35', '$2a$10$jxwd/oriTz2HklHK4b4nf.P.DWb6s35YTO.Eb
Ywup0I.gMTOLSNKa', '2015-07-20 20:54:35')
(89.1ms) COMMIT
=> true
USERS CONTROLLER
class UsersController < ApplicationController
def new
end
private
def user_params
params.require(:user).permit(:email)
end
end
Looking at the log the email parameter was not inserted into; please, any help with this is appreciated.
Try the following in your User model:
before_save {self.email = email.downcase } # no "!"
downcase! edits the variable on which it is called and does not return the downcased string unless there is something to downcase (i.e., if you use it on an all lower-case email, it returns nil and based on your console output, this is what is happening). downcase alone should be fine.
downcase! on the API
I'm following along with this tutorial and at one point, it tells me to
... add password and password_confirmation attributes to the User model [...] Unlike the other attributes we’ve seen so far, the password attributes will be virtual—they will only exist temporarily in memory, and will not be persisted to the database.
And
As we’ll see in Section 6.3.4, these virtual attributes are implemented automatically by has_secure_password.
My model looks like this:
class User < ActiveRecord::Base
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
has_secure_password
attr_accessible :email, :is_admin, :name, :password, :password_confirmation
validates :name, presence: true, uniqueness: true
validates :password_digest, presence: true
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX}, uniqueness: true
end
So now when I try to create a new user;
User.create(name: "Foo Bar", email: "foo#bar.net", password: "foobar", password_confirmation: "foobar")
I get the following error:
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: password, password_confirmation
Why?!
The issues seemed as though the password and password_confirmation columns were missing in the database.
As per the comment, re-migrating and restarting the server would fix this problem.
I'm new to rails and I'm having some trouble in the console. I'd like to add records to my Users table and test some functions. However, everytime i perform a User.create or similar function, it completes successfully and then immediately gets rolled back. How do I prevent the immediate rollback?
I am not in sandbox mode.
Below is the output I get in the console when trying to create a user. It says the user exists, then immediately rolls back the transaction. I then run a User.all just to show that the transaction did indeed get rolled back.
>>> User.create(first_name: "derek", last_name: "harrington", email: "derek#gmail.com")
(0.1ms) begin transaction
User Exists (0.2ms) SELECT 1 FROM "users" WHERE "users"."email" = 'derek#gmail.com' LIMIT 1
(0.1ms) rollback transaction
=> #<User id: nil, first_name: "derek", last_name: "harrington", email: "derek#gmail.com", password_digest: nil, credit_card_id: nil, address_id: nil, created_at: nil, updated_at: nil>
>>> User.all
User Load (0.3ms) SELECT "users".* FROM "users"
=> []
How do I make these changes permanent and prevent the rollback?
Edit:
Here is the contents of my User model
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name, :email, :password, :password_confirmation
has_secure_password
validates :first_name, presence: true, length: { maximum: 50 }
validates :last_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: true
validates :password, confirmation: true, length: { minimum: 6, maximum: 50 }
validates :password_confirmation, presence: true
end
So it looks like you weren't providing the password confirmation and that's why it wasn't saving.
That's odd.
Did you add some configuration option? If so, better review them.
You can also try very simple rails app to verify the behavior.