I am trying to insert a new record into a SQLiteDB through my Rails console. Simply using User.create().
The row does not appear in my database.The message implies that a user exists, but calling User.first returns null and checking the database shows an empty table. What am I missing?
Input:
console > User.create(name: 'don', email: 'don#gmaill.com', password: 'test', password_confirmation: 'test')
Output:
(0.1ms) begin transaction
User Exists (0.1ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'don#gmaill.com' LIMIT 1
(0.0ms) rollback transaction
=> #<User id: nil, name: "don", email: "don#gmaill.com", created_at: nil, updated_at: nil, password_digest: "$2a$10$3EK3L932ryjrJPFIc4E0/uzavrpkWylDRzx4Wkdwzx8d...">
User Class:
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_sen,sitive: false }
has_secure_password
validates :password, length: { minimum: 6 }
end
It's not persisting the User (you can tell by the rollback statement). Looks like it's failing a uniqueness validation on the email. You can look at the errors by calling errors.full_messages on the User you tried to create, or by using create! instead of create
You are most likely validating uniqueness of email field. Hence ActiveRecord is issuing a select first to check if a record exist with the same email address, and finding one. Hence Create is not saving the new record to database.
But create returns the object anyway.
You can try this to verify this. Instead of create, try new followed by save!
console > u = User.new(name: 'don', email: 'don#gmaill.com', password: 'test', password_confirmation: 'test')
console > u.save!
To get rid of this error, first delete the record that exists in the DB
Related
I have a User model with the following attributes:
id: integer
username: string
email: string
password_hash: string
password_salt: string
account_type: string
...
My goal is to validate a user's password on create and update.
When a user with account_type: 'a' gets created or updated I want to run validates :password, :password_confirmation, presence: true.
When a user with account_type: 'b' gets updated I want to validate the password and password_confirmation presence as true, but NOT when the user gets created.
If more code or a clearer explanation would help, please let me know. Thanks in advance.
validates :password, :password_confirmation, presence: true, unless: -> { |user| user.account_type == 'b' && user.new_record? }
In a Rails 6 backend API, I have a typical User model, with email, fullname, username and so on, and also an index on the email column (however, I do not think it has anything to do with my error). I also have a sessions controller, which until now, only responds to post requests, which basically create a log in session for the user and return a JWT to the client.
It works fine, but when it comes to testing (an integration test for the sessions controller), the following error keeps occuring randomly (like in 75% of the cases):
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate
key value violates unique constraint "users_pkey" DETAIL: Key
(id)=(732175191) already exists.
Sometimes, this error does not occur and tests work fine, but that's in the minority of the cases.
This is the integration tests file for the session controller:
class SessionsTest < ActionDispatch::IntegrationTest
def setup
#alex1 = User.new(full_name: "Alex Robert", email: "rob#example.com", date_of_birth: "2000-02-02", city: 'Cluj', country: 'Romania', username: 'alex', password: User.get_digest('alex1234'))
end
test "log in attempt with invalid parameters respond with status 401" do
post sessions_path, params: {
user: {
email: " ",
password: " "
}
}
json_response = JSON.parse(response.body)
assert_equal 401, json_response["status"]
end
test "log in attempt with invalid password respond with status 401" do
post sessions_path, params: {
user: {
email: #alex1.email,
password: "alabala"
}
}
json_response = JSON.parse(response.body)
assert_equal 401, json_response["status"]
end
end
This is the User model:
class User < ApplicationRecord
attr_accessor :remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
before_save { self.email = email.downcase }
validates :full_name, presence: true, length: { maximum: 255 }
validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
validates_uniqueness_of :email, :case_sensitive => false
validates :date_of_birth, presence: true
validates :country, presence: true
validates :city, presence: true
validates :username, presence: true, length: { maximum: 50 }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true, length: { minimum: 6 }
has_secure_password
def self.get_digest(string)
cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
BCrypt::Password.create(string, cost: cost)
end
def self.encode_jwt(payload)
JWT.encode(payload, 'secret')
end
def self.decode_jwt(jwt)
JWT.decode(jwt, 'secret', true, algorithm: 'HS256')
end
end
I have looked up my issue on at least 10 Stack Overflow threads, but the suggestions did not work out for me. Some suggested to reset the db (drop and recreate it) or reset the sequence id, with the following task:
namespace :database do desc "Correction of sequences id"
task correction_seq_id: :environment do.
ActiveRecord::Base.connection.tables.each do |t|.
ActiveRecord::Base.connection.reset_pk_sequence!(t)
end
end
end
However, I found that most people were having a slightly different error, that was connected to the uniqueness of the email. My error seems a more weird one, because it's about the duplication the primary key constraint. As seen in the error message I posted above, the test runner complains that: (id)=(732175191) already exists.
I am using the railstutorial.org book.
I tried updating the user attributes as written in Chapter 7 of the book, but the email became nil. I have tried updating to no avail. This produces a NoMethodError in UsersController#show: undefined method `downcase' for nil:NilClass.
Here is the show.html.erb
<% provide(:title, #user.name) %>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
Users helper
module UsersHelper
# Returns the Gravatar of the given user.
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
User Controller
class UsersController < ApplicationController
def new
end
def show
#user = User.find(params[:id])
end
end
User model
class User < ActiveRecord::Base
before_save { email.downcase! }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[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, presence: true, length: { minimum: 6 }
end
Please I need help to fix this. Thanks.
I'm also following this tutorial, so I don't pretend to be a Rails expert.
That said, I just went back and reviewed the tutorial material surrounding the first introduction of the
before_save { email.downcase! }
syntax, and I see this at the end of Chapter 6 (listing 6.42).
I'm pretty sure this isn't working for you because your UsersController is missing a definition of the "New" method:
def new
#user = User.new
end
I'm wiling to bet that your #user object is Nil because you haven't create an instance of it yet. BTW, at this point in the tutorial, you should have also defined a Create method in UsersController.
EDIT: If your problems are limited to what is happening in the Rails console, I agree with the comments that you need to provide a complete transcript of your console session in order for folks to provide a complete answer.
Here's an example Rails console session from within my Rails Tutorial project:
Invoke the console and make it aware of my User model:
$rails console
Loading development environment (Rails 4.2.2)
require './app/models/user'
=> true
Create a User instance named "spong"
**spong = User.new**
=> <User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: nil, activation_digest: nil, activated: false, activated_at: nil>
(Note: My User model has more attributes because I am toward the end of the Tutorial.)
Populate values for name and e-mail:
spong.name = "Yo Dawg!"
=> "Yo Dawg!"
spong.email = "YoDaWG#dawg.COM"
=> "YoDaWG#dawg.COM"
Note that my initial e-mail address is mixed case.
Invoke the downcase method:
spong.email.downcase
=> "yodawg#dawg.com"
This is working for me in the console. Now let's try the update_attributes method:
spong.update_attributes(name: "The Dude", email: "dude#AbideS.org")
This is straight out of the tutorial, but it doesn't work for me, because at this point in my journey, I have implemented features that prevent this kind of update:
(6.5ms) begin transaction
User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('dude#AbideS.org') LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('dude#AbideS.org') LIMIT 1
(0.1ms) rollback transaction
=> false
As Hartl says:
Note that if any of the validations fail, such as when a password is required to save a record (as implemented in Section 6.3), the call to update_attributes will fail.
So let me try the singular version of this command:
spong.update_attribute( :email, "dude#AbideS.org")
(3.7ms) begin transaction
SQL (4.0ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "activation_digest") VALUES (?, ?, ?, ?, ?) [["name", "The Dude"], ["email", "dude#abides.org"], ... ]
(1.2ms) commit transaction
==> true
spong.email
=> "dude#abides.org"
Not that the e-mail address is already converted to lower case in the INSERT command--exactly as expected, thanks to that
before_save { email.downcase! }
we have in our User model.
But what's with all the DB activity? This is because update_attributes updates a single attribute and saves the record without going through the normal validation procedure (which is why I am able to do this). While research this, I found this excellent discussion about update_attribute and update_attributes. Great stuff!
OK, so what happens if we try to call update_attribute when the (existing) e-mail address is blank? Let's see:
newUser = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: nil, activation_digest: nil, activated: false, activated_at: nil>
Everything in newUser is nil. Let's try to update the e-mail address:
newUser.update_attribute(:email, "cOnFuSed#MixecCase.com")**
(1.2ms) begin transaction
SQL (3.9ms) INSERT INTO "users" ("email", "created_at", "updated_at", "activation_digest") VALUES (?, ?, ?, ?) [["email", "confused#mixeccase.com"], ...]
(0.9ms) commit transaction
=> true
Again, because of the behavior of update_attribute/update_attributes, my database is updated; somewhat counterintuitively, a record is inserted during this "update" process, but this is because I had not yet saved this (or the first) record to the DB.
I hope all this helps. At a minimum, I have demonstrated that this DOES work via the console--even with previously 'nil' values (and I learned a ton while doing the research to attempt an answer).
Say I wish to create a user from console with an email which already exists. If I do User.create(...)
Because of model validations (uniqueness in this case). create fails and the output in rails console will say: rollback transaction (user is not saved)
For the purpose of testing. Is their a way I can get the explicit error which triggered the rollback? In this case it would say something like: "ROLLBACK: email is not unique".
You can also do:
User.create!
The 'bang' will force it to show you the errors without additional steps.
You could do the following in Rails console:
>> user = User.new(...)
>> user.save
>> user.errors.messages
That way, you know what errors caused save to fail.
If you mean by using "rails console", I hope and this small example is useful for you:
Model Student (student.rb):
class Student < ApplicationRecord
validates :name, presence: true, length: {minimum: 5, maximum: 50}
end
And at Rails console ($ rails console) do something like this:
> student = Student.create(name:"alba")
(0.1ms) begin transaction
(0.1ms) rollback transaction
=> #<Student id: nil, name: "alba">
> student.errors.any?
=> true
> student.errors.full_messages
=> ["Name is too short (minimum is 5 characters)"]
Hope this helps.
I'm new to Rails (Rails 4.0.0) and I'm facing a problem when creating records to the database (sqlite3).
It always returns 'nil'.
User model (validations)
attr_accessor :name, :email
validates :name, presence: { message: 'name field can not be blank'},
length: { maximum: 30 }
validates :email, presence: { message: 'email can not be blank'},
format: { with: /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i },
uniqueness: { case_sensitive: false, message: 'User already exist'}
Rails console (development environment )
> user = User.create!(name: "user", email: "user#gmail.com")
=><#User id: 4, name: nil, email: nil, created_at: "2013-07-29 09:27:22", updated_at: "2013-07-29 09:27:22">
When I ask for the user's name and email I get valid data, and not nil.
> user.name
=> "user"
> user.email
=> "user#gmail.com"
Then I get nil again in the view.
<%= #user.name %>
<%= #user.email %>
Any idea why I get valid data in the console (env=development) and not in the views ?
The problem seems to be that you create attr_accessor for name and email which overwrites the setter and getter methods provided by ActiveRecord to set and get database values. Remove this line from your code and it should work again:
attr_accessor :name, :email
When yo use the stters and getters provided by your attr_accessor's you can set and return the values but they arent saved to the database so they are lost when you overwerite the object or reload it from the database.