Development database doesn't reset (not null) - ruby-on-rails

In seeds.rb I have a single record for my Messages model:
Message.create!(email: "example#example.com",
name: "Example User",
content: "This is my message")
If I run rake db:seed I get the error message:
rake aborted!
ActiveRecord::RecordInvalid: Validation failed: Email has already been taken, Username has already been taken
/usr/local/rvm/gems/ruby-2.1.5/gems/activerecord-4.2.1/lib/active_record/validations.rb:79:in `raise_record_invalid'
...
If I run bundle exec rake db:reset I get the error:
-- initialize_schema_migrations_table()
-> 0.0734s
rake aborted!
ActiveRecord::StatementInvalid: SQLite3::ConstraintException: NOT NULL constraint failed: messages.name: INSERT INTO "messages" ("created_at", "updated_at") VALUES (?, ?)
/usr/local/rvm/gems/ruby-2.1.5/gems/sqlite3-1.3.10/lib/sqlite3/statement.rb:108:in `step'
...
Email in the Message model is indeed required. But still when I reset the db, I don't see how this record could be invalid. And email does not need to be unique, so why does the seed command give such an error?
The model file for messages:
attr_accessor :name, :email, :content
validates :name, presence: true,
length: { maximum: 255 }
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 }
validates :content, presence: true,
length: { maximum: 600 }
Messages migration file:
def change
create_table :messages do |t|
t.string :name, null: false, limit: 255
t.string :email, null: false, limit: 255
t.string :content, null: false, limit: 600
t.timestamps null: false
end
end
I'm not sure what is causing this problem...
Update: I'm lost, I now also get an error message when seeding even without the Message.create! lines in the seeds file. The error says rake aborted! ActiveRecord::RecordInvalid: Validation failed: Email has already been taken, Username has already been taken. But how can this be since I first run bundle exec rake db:reset? Doesn't this remove all the data from the db and wouldn't this by definition mean they can't already be taken?
My seeds file is:
User.create!(fullname: "Example User",
username: "fakename0",
email: "example#railstutorial.org",
admin: true,
activated: true,
activated_at: Time.zone.now,
password: "foobar",
password_confirmation: "foobar")
User.create!(fullname: "Example User 2",
username: "fawwkename0",
email: "exaaample#railstutorial.org",
admin: false,
activated: true,
activated_at: Time.zone.now,
organization: "organization",
password: "foobar",
password_confirmation: "foobar")
99.times do |n|
username = "fakename#{n+1}"
email = "example-#{n+1}#railstutorial.org"
password = "password"
User.create!(username: username,
email: email,
password: password,
password_confirmation: password,
activated: true,
activated_at: Time.zone.now)
Update 2: I found out that running rake db:reset already seeds the db (or at least the db wasn't empty after this command). Still this doesn't explain why I can't seed it with
Message.create!(email: "example#example.com",
name: "Example User",
content: "This is my message")
Seeding this data generates the error: rake aborted!
ActiveRecord::StatementInvalid: SQLite3::ConstraintException: NOT NULL constraint failed: messages.name: INSERT INTO "messages" ("created_at", "updated_at") VALUES (?, ?) /usr/local/rvm/gems/ruby-2.1.5/gems/sqlite3-1.3.10/lib/sqlite3/statement.rb:108:in 'step' ...

Removing attr_accessor :name, :email, :content from the model file solved it. Don't really know why. I added this line because it is included in the tutorial: http://matharvard.ca/posts/2014/jan/11/contact-form-in-rails-4/ But also without that line the messages form still seems to be working.

Related

Rspec presence: true check fails even though it works as intended

I have the following Rspec test with the following output for my User model in a Rails API I'm building:
RSpec.describe User, type: :model do
let(:michael) { User.new(email: "michael#email.com", password: "Password1", password_confirmation: "Password1") }
it 'is not valid without a password' do
michael.password = ''
expect(michael).not_to be_valid, "Expect User to have a Password"
end
end
1) User basic checks is not valid without a password
Failure/Error: expect(michael).not_to be_valid, "Expect User to have a Password"
Expect User to have a Password
# ./spec/models/user_spec.rb:19:in `block (3 levels) in <main>'
However, for some reason this test just fails, even with the following on my User model
class User < ApplicationRecord
has_secure_password
validates :email, presence: true, uniqueness: true
validates :password, presence: true
validates :password,
format: { with: /\A(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).{8,}\Z/, message: "Password must be at least 8 characters long, contain at least 1 uppercase and 1 lowercase letter and 1 number" },
confirmation: true,
on: :create
end
The above validation works fine, as you can see here:
➜ rails c
Running via Spring preloader in process 2774
Loading development environment (Rails 6.0.3.1)
irb(main):001:0> new = User.new
irb(main):002:0> new.email = "testing#testing.com"
irb(main):003:0> new.save
(0.2ms) BEGIN
User Exists? (0.6ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "testing#testing.com"], ["LIMIT", 1]]
(0.2ms) ROLLBACK
=> false
irb(main):004:0> new.errors
=> #<ActiveModel::Errors:0x00007f743848dfb0 #base=#<User id: nil, email: "testing#testing.com", password_digest: nil, created_at: nil, updated_at: nil, admin: false>, #messages={:password=>["can't be blank", "can't be blank", "Password must be at least 8 characters long, contain at least 1 uppercase and 1 lowercase letter and 1 number"]}, #details={:password=>[{:error=>:blank}, {:error=>:blank}, {:error=>:invalid, :value=>nil}]}>
What exactly am I doing wrong here for this test to fail? It's a painfully simple one, and all the other ones work as expected except for the password test.
First, in your tests password = '' is a valid one because for Ruby, '' is something. You have to add this to your validation:
validates :password, presence: true, allow_blank: false
Also, take a look, your password validation is for on: :create and in your spec you are not creating it.

How can allow_nil let an empty string pass the validation

I am reading Michael Hartl's Ruby On Rails Tutorial (3rd). In chapter 9, there's an example showing us how to update the user info. I got confused by the allow_nil attached here. I simplified the code as below:
class User < ActiveRecord::Base
has_secure_password
validates :password, presence: true, length: { minimum: 6 }, allow_nil: true
end
myuser=User.new(name: "Foo_bar",email: "test#example.com", password: "123456", password_confirmation: "123456")
myuser.save
myuser=User.find(myuser.id)
myuser.update_attributes(name: "Bar_Foo",email: "test#example.com", password: "", password_confirmation: "") # It will succeed! But WHY?
I understand the allow_nil: true skips the validation when the value being validated is nil. Nevertheless obviously, password: "" is not a nil value. How can allow_nil: true allows an empty string?
This behaviour is due to has_secure_password magic. In short, it check whether given password is blank or not and does not assign anything to #password if it is. Hence:
user = User.new
user.password = '' # This is not an assignment, but invocation of `password=` method.
user.password #=> nil
You can see the source code behind password= method here: https://github.com/rails/rails/blob/869a90512f36b04914d73cbf58317d953caea7c5/activemodel/lib/active_model/secure_password.rb#L122
Also note, that has_secure_password already defines default password validation, so if you want to create your own, you need to call it with has_secure_password validation: false
You can try this in irb:
user = User.new
user.password = '123'
user.password_confirmation = '123'
user.password_digest.nil? => false
user = User.new
user.password = ''
user.password_confirmation = ''
user.password_digest.nil? => true

No validation errors on sign in, present on sign up with Devise/Rails

Using Devise with Rails, but validating myself in the model to provide custom error messages:
validates :email,
:uniqueness => {:message => :unique_email},
:presence => {:message => :email_missing}
YML:
unique_email: "Email address needs to be unique"
email_missing: "Email address can't be blank"
View:
=#user.errors.messages.inspect
yields nothing, an empty object! Yet this all works fine on sign up...
Any ideas?
EDIT:
Ok, it's putting the login errors in like so:
- flash.each do |name, msg|
.standalone_form--message= msg
So how can I customise these messages (ie. from a yml file)? Like I've done with the #user.errors.messages?
You should put your messages using locales as Rails guides recommends:
# config/locales/en.yml
en:
activerecord:
attributes:
user:
email: "Email address"
errors:
models:
user:
attributes:
email:
blank: "can't be blank"
unique: "should be unique"
Note: Do not use the following, it's only to show the YAML issue
That said, about your error, this should work:
validates :email,
:uniqueness => {:message => "Email address should be unique"}
The problem is that you should load the YAML file properly:
Create a file named config/error_messages.yaml:
unique_email: "Email address needs to be unique"
email_missing: "Email address can't be blank"
Add a Ruby file config/initializers/load_error_messages.rb:
ERROR_MESSAGES = YAML.load_file(Rails.root.join("config", "initializers", "config.yml"))
Then use it on the validation like this:
validates :email,
:uniqueness => {:message => ERROR_MESSAGES['unique_email']}
( Source: RailsCast #85)

Nested attributes in rake task

I'm trying to create a rake task to populate my DB. I need to to create 1 user with a specifc set of deatails and 99 other randomly genraterated . The details that are required are for two Models at the same time, similar to a form with nested attribues. My model uses an after_create call back to create and link a users to a team. The team name by default is the users name
the current code that I have used it producing errors
sample_data.rake
namespace :db do
desc "Fill database with sample data"
task populate: :environment do
user = User.create!(:profile_attributes => { name: Forgery::Name.full_name },
email: "test#example.com",
password: "123qwe",
password_confirmation: "123qwe")
99.times do |n|
:profile_attributes => { name: Forgery::Name.full_name },
email = Forgery::Internet.email_address
password = "password"
user = User.create!(email: email,
password: password,
password_confirmation: password)
end
end
end
Model that relys on the nested attibute.
class User < ActiveRecord::Base
after_create :set_user_on_team
private
def set_user_on_team
self.create_owned_team(:name => self.profile.name ).users << self
end
end
error message
rake aborted!
/lib/tasks/sample_date.rake:9: syntax error, unexpected tASSOC, expecting keyword_end
:profile_attributes => { name: Forgery::Name.full_name },
^
/lib/tasks/sample_date.rake:9: syntax error, unexpected ',', expecting keyword_end
I noticed some syntax errors in the 99.times block. You could try it like this:
99.times do |n|
profile_attributes = { name: Forgery::Name.full_name }
email = Forgery::Internet.email_address
password = "password"
user = User.create!(profile_attributes: profile_attributes, #my assumption
email: email,
password: password,
password_confirmation: password)
end

Rails is not inputting user data to postgresql

I am having an issue with Rails not inputting values to postgresql. The database itself is connected. When I run db:create:all (snippet from database.yml)
development:
adapter: postgresql
encoding: unicode
database: website_development
username: postgres
password: *******
host: 127.0.0.1
port: 9435
(test: is the same but with database: website_test instead of website_development) all the databases are created for test and development. When I run my db:migration the user table is also created e.g. snippet from migration file "date"_create_user.rb
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :username
t.string :email
t.timestamps
end
end
def self.down
drop_table :users
end
end
(I have checked in pgAdmin and found the tables that where created)But when I try to insert data from the console e.g.(this was run in sandbox)
irb(main):001:0> User.create!(:username => "John", :email => "john#example.com)
=> #<User id: 1, username: nil, email: nil, created_at: "2011-04-26 22:00:28", u
pdated_at: "2011-04-26 22:00:28">
here is the sql produced on a different create! I had run
[1m[35mSQL (2.0ms)[0m INSERT INTO "users" ("username", "email", "created_at", "updated_at") VALUES (NULL, NULL, '2011-04-26 20:53:43.363908', '2011-04-26 20:53:43.363908') RETURNING "id"
Any help as to why rails is creating the databases and tables fine but can't find the proper username and email to enter into sql.
P.S. I am running Rspec for my tests and have made several tests regarding the values of username and email not being nil to which all succeed.
......................
Finished in 1.62 seconds
22 examples, 0 failures
Notification failed: 201 - The destination server was not reachable
Notification failed: 201 - The destination server was not reachable
As you can see all Rspec tests are green but it to is having trouble connecting to the postgres server
Thank you in advance for any advice.
Update: added user model snippet
class User < ActiveRecord::Base
attr_accessor :username, :email
email_regex = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
username_regex = /\A[\w\d]+\z/i
validates :username, :presence => true,
:format => { :with => username_regex },
:length => { :maximum => 30},
:uniqueness => { :case_sensitive => false }
validates :email, :presence => true,
:format => { :with => email_regex },
:uniqueness => { :case_sensitive => false }
end
==Answer==
These were my mistakes:
Part 1: By changing attr_accessor to attr_accessible all my tests worked properly, and everything that needed to went to red, this also allowed me to add :email details but not :username details which leads to part 2.
Part 2: For some reason rails didn't like the fact that my table was named :user and my column was named :username. So I tried changing :username to :loginname which fixed the problem entirely.
Thank you everyone for all your help.
To isolate this you may want to construct a unit test to replicate the problem, then repair it as required. At first I suspected it would be a case of protected attributes, but it appears you have made them accessible, which is the correct thing to do.
Calling create! directly is somewhat hazardous as you are not easily able to capture the object that is half-created in the event of an exception. This is because although the exception contains a reference to a model, it is not clear if the User model or some other model caused the exception in the first place without additional digging.
A more reliable approach is this:
def test_create_example
user = User.new(:username => "John", :email => "john#example.com")
assert_equal 'John', user.username
assert_equal 'john#example.com', email
user.save
assert_equal [ ], user.errors.full_messages
assert_equal false, user.new_record?
end
If an error occurs in the validation stream you will see the error listed alongside what should be an empty array. It also checks that the record has been saved by testing that it is no longer a new record as records can be valid but fail to save if a before_save or before_create filter returns false, something that happens by accident quite often.
If you call new and then save you have an opportunity to inspect the newly prepared object before it is saved, as well as after.

Resources