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.
Related
Ruby 2.2.0 on Rails 4.2.2
I'm attempting to write a custom date validator (that is going to be expanded to handle some other cases once I get this part working), but right now it's failing to appropriately validate (and return false) on strings - it doesn't even run. It seems that rails is completely ignoring the date_ended value when it's set to a string. When I try the same test except with an integer it correctly validates and fails that validation. If I don't allow nil values, the validator correctly prevents record creation on a string value, but only because it rejects the nil value. Any and all suggestions are appreciated.
The same exact problem exists for date_started.
Edit: I've confirmed that the validation is failing on the second expectation and not the first validation by double-checking that CommitteeMember.count is 0 before the first expectation.
CommitteeMember:
class CommitteeMember < ActiveRecord::Base
belongs_to :committee
belongs_to :member
validates :committee_id, presence: true
validates :member_id, uniqueness: { scope: :committee_id }, presence: true
validates :date_started, date: true, allow_nil: true
validates :date_ended, date: true, allow_nil: true
end
schema.rb relevant lines:
create_table "committee_members", force: :cascade do |t|
t.integer "committee_id", null: false
t.integer "member_id", null: false
t.date "date_started"
t.date "date_ended"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
DateValidator (custom validator):
(note the printed value in the middle)
class DateValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
puts "Validating #{value}"
unless value.kind_of?(Date)
record.errors[attribute] << "must be of type date"
end
end
end
CommiteeMember relevant spec:
(note the printed value in the middle)
it 'should fail with a string for date_ended' do
expect(CommitteeMember.count).to eq(0)
CommitteeMember.create!(member_id: 1, committee_id: 1, date_ended: "S")
ap CommitteeMember.first
expect(CommitteeMember.count).to eq(0)
end
Spec Output:
$ rspec spec/models/committee_member_spec.rb
......#<CommitteeMember:0x00000007d1f888> {
:id => 1,
:committee_id => 1,
:member_id => 1,
:date_started => nil,
:date_ended => nil,
:created_at => Tue, 11 Aug 2015 19:22:51 UTC +00:00,
:updated_at => Tue, 11 Aug 2015 19:22:51 UTC +00:00
}
F
Failures:
1) CommitteeMember validations should fail with a string for date_ended
Failure/Error: expect(CommitteeMember.count).to eq(0)
expected: 0
got: 1
(compared using ==)
# ./spec/models/committee_member_spec.rb:52:in `block (3 levels) in <top (required)>'
Finished in 0.54864 seconds (files took 2.43 seconds to load)
7 examples, 1 failure
Failed examples:
rspec ./spec/models/committee_member_spec.rb:48 # CommitteeMember validations should fail with a string for date_ended
Since the attributes are date attributes, Rails automatically parses any values that you attempt to assign. If it cannot parse as a date, it will leave the value as nil, e.g. in the console:
c = CommitteeMember.new
c.date_started = 'S'
=> "S"
c.date_started
=> nil
In fact, Rails will actually parse a string into a Date:
c.date_started = '2016-1-1'
=> "2016-1-1"
c.date_started
=> Fri, 01 Jan 2016
c.date_started.class
=> Date
This means that you don't need to validate that your date fields are dates at all, because Rails won't store them otherwise. Instead, just validate that they exist:
validates_presence_of :date_started, :date_ended
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.
I got two fixture files for Locales and Translations.
Locales are loaded fine, but Translations are broken:
Fixture
translation_05064:
id: 5064
key: control.base_search_users.panel.title
value: Поиск пользователей
interpolations:
locale: ru
locale_id: 16
is_proc: false
Becomes the record:
#<Translation id: 5064,
key: "control.base_search_users.panel.title",
value: "Поиск пользователей",
interpolations: nil,
locale: nil,
locale_id: 1019186233,
is_proc: false>
For some reason locale instead of 'ru' becomes nil, while locale_ib instead of 16 becomes 1019186233 for every fixture in a file.
I load fixtures such way:
require 'active_record/fixtures'
ActiveRecord::Fixtures.reset_cache
fixtures_folder = File.join(Rails.root, 'test', 'fixtures')
fixtures = Dir[File.join(fixtures_folder, '*.yml')].map {|f| File.basename(f, '.yml') }
ActiveRecord::Fixtures.create_fixtures(fixtures_folder, fixtures)
Translation model
class Translation < ActiveRecord::Base
validates :key, :uniqueness => {:scope => :locale_id}
validates :key, :locale, :locale_id, :value, :presence => true
belongs_to :locale
attr_accessible :key, :value, :locale_id, :locale
end
The migration
class CreateTranslations < ActiveRecord::Migration
def change
create_table :translations do |t|
t.string :key
t.text :value
t.text :interpolations
t.string :locale
t.integer :locale_id
t.boolean :is_proc, :default => false
end
add_index :translations, [:key, :locale]
end
end
I see in a test.log that inserts to DB contain broken data. When I load the fixture file in rails concole with YAML.load_file 'test/fixtures/translations.yml' I get correct Hash data.
Why that happens? How to fix that?
Rails-2.3.8, PostgreSql-8.4
UPDATE:
Tried named fixtures. In locales.yml:
locale_00016:
id: 16
code: ru
name: Русский
and in translations.yml all locale key values set to locale_00016
translation_05064:
id: 5064
key: control.base_search_users.panel.title
value: Поиск пользователей
locale: locale_00016
is_proc: false
YES, that works!
Translation id referred to existing and correct Locale record, but locale was still nil, to fix it I ran Locale.find_by_code('ru').translations.update_all(:locale => 'ru')
If locale_id is set, it seems ok; locale will be filled by Rails when you need it (the first time you will request it). 1019186233 is the id generated by rais when the fixtures are created.
Most of the time, you do not need to specify ids in fixtures, rails generate them for you, so fixtures like below should be fine (you should not define both localeand locale_id in the Translation fixture):
locales.yml:
ru:
what_ever_attr: value
...
translations.yml:
ru_title_translation:
key: control.base_search_users.panel.title
value: Поиск пользователей
interpolations:
locale: ru
is_proc: false
I want to create one user (admin) and I want to use console (without user registration model). I use solution from RailsCasts (http://railscasts.com/episodes/270-authentication-in-rails-3-1).
But I have one problem: when I do User.create(..., :password => "pass") in console my password stored in database without encription (like "pass"). And I can't login with my data.
How can I create user from console? :)
Straight from the Rails API
# Schema: User(name:string, password_digest:string)
class User < ActiveRecord::Base
has_secure_password
end
user = User.new(:name => "david", :password => "", :password_confirmation => "nomatch")
user.save # => false, password required
user.password = "mUc3m00RsqyRe"
user.save # => false, confirmation doesn't match
user.password_confirmation = "mUc3m00RsqyRe"
user.save # => true
user.authenticate("notright") # => false
user.authenticate("mUc3m00RsqyRe") # => user
You need to include :password_confirmation => "pass in your hash!
Right, so taking a look at has_secure_password you want to perform BCrypt::Password.create(unencrypted_password) to obtain it. You'll need the bcrypt-ruby gem to do the above.
I'm in the process of learning Ruby on Rails, so treat me like a total neophyte, because I am.
I've got a User model with some associated RSpec tests, and the following test fails:
require 'spec_helper'
describe User do
it 'should require a password' do
User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''}).should_not be_valid
end
end
The relevant part of the User model looks like this:
class User < ActiveRecord::Base
...
validates :password, :presence => true,
:confirmation => true,
:length => { :minimum => 6 }
...
end
Here's the catch: if I run User.new(...).valid? from a Rails console using the arguments above, it returns false as expected and shows the correct errors (password is blank).
I was using spork/autotest and I restarted both to no avail, but this test also fails even running it directly with rspec. What am I doing wrong here?
EDIT
I tried a few more things with the test. This fails:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.should_not be_valid
So does this:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.valid?
u.errors.should_not be_empty
This passes, confirming that :password is indeed blank:
u = User.new({:email => 'valid_email#example.com', :password => '', :password_confirmation => ''})
u.password.should == ''
So, it's actually spork that is causing the problem. You can turn caching off, so that it won't need restarting every time :
http://ablogaboutcode.com/2011/05/09/spork-testing-tip-caching-classes
I think this is what happens :
ruby-1.9.2-p180 :020 > u = User.new
=> #<User id: nil, email: ...
ruby-1.9.2-p180 :021 > u.errors
=> {}
ruby-1.9.2-p180 :022 > u.save
=> false
ruby-1.9.2-p180 :023 > u.errors
=> {:email=>["can't be blank", "can't be blank"], ...}
In short, if you change new to create, it will work :) I think that this happens because the matcher be_valid checks on the model validation errors. There can be a deeper explanation, but i think that if you use create instead of new, it will work.
EDIT : I have a be_valid_verbose version that might help. Just create a 'be_valid_verbose.rb' file in your rspec/custom_matchers folder, and inside it write :
RSpec::Matchers.define :be_valid_verbose do
match do |model|
model.valid?
end
failure_message_for_should do |model|
"#{model.class} expected to be valid but had errors:n #{model.errors.full_messages.join("n ")}"
end
failure_message_for_should_not do |model|
"#{model.class} expected to have errors, but it did not"
end
description do
"be valid"
end
end
Now check against be_valid_verbose instead of be_valid. It will hopefully present you with some more information on what is happening in your case.
As I feared, the answer was stupidity. This was a spork problem. I thought I had killed the existing process and was running rspec independently, but I later found the spork process still running in a different shell, and rspec had been connecting to it all along. Restarting spork (or killing it entirely) and re-running the tests fixed the problem.
I found this particularly deceptive in that rspec continually updated the test output to reflect the fact that it was aware of my test changes, so it appeared to me that it was running against up-to-date code. Now I'm left to wonder what the real utility of spork is, since apparently I can't trust that it's actually running the right tests correctly.