I have a model "User" that up until now didn't have any issues. I added some validations and noticed that I no longer could add any new Users - the record would be rolled back. So I removed the validations, but my records were still being rolled back. So I eliminated literally all the code from my model file so all it contains is this:
class User < ActiveRecord::Base
end
but I'm still getting the same error.
In my rails console:
> User.create(name: "test")
(0.6ms) BEGIN
(2.3ms) ROLLBACK
#=> #<User id: nil, name: "test", (et cetera)>
I don't even know how to start figuring out what's wrong. How can I even debug this? All my other models work normally.
This is what I added before this started:
blacklist = ['home'].freeze
validates :name, exclusion: {in: blacklist}
SOLVED:
I integrated Devise with this model, so there were some validations in place that weren't in my Devise.rb file. I had to run #user.errors to get back the errors that were preventing the record from being saved.
Try this:
user = User.new(name: "test")
user.save
user.errors # This should contain the errors that prevented your object from being saved.
Related
In my Rails app, I am trying to save MAC addresses for devices belonging to different users. Each MAC address must be unique, so I included the uniqueness validation.
The validation itself seems to be working, since duplicate records were rejected when I tried using the Rails Console (ActiveRecord::RecordNotUnique). However, my test to check that only unique records can be saved is failing.
So my questions are:
Why is my test failing and how can I fix it?
I read elsewhere that the uniqueness validation alone is not a reliable way to assure uniqueness. Should I use other methods, such as before_save callbacks?
This is the error message I'm getting for the test:
Expected #<MacAddress id: nil, user_id: nil, address: "MACADD123", created_at: nil, updated_at: nil> to be nil or false
Setup in my model files:
# app/models/mac_address.rb
class MacAddress < ApplicationRecord
validates :address, uniqueness: true
belongs_to :user
end
# app/models/user.rb
class User < ApplicationRecord
has_many :mac_addresses, dependent: :destroy
end
Test to check for uniqueness:
class MacAddressTest < ActiveSupport::TestCase
test 'mac address must be unique' do
new_mac = 'MACADD123'
assert MacAddress.create(user: User.first, address: new_mac)
assert MacAddress.all.pluck(:address).include?(new_mac)
# The 'assert_not' below is failing.
assert_not MacAddress.create(user: User.second, address: new_mac)
end
end
Thanks for any help in advance.
As per the documentation on create:
Notice there's no id for that record. It hasn't been persisted. Check for errors with .errors.full_messages to see the uniqueness validation failure.
The resulting object is returned whether the object was saved successfully to the database or not.
You should assert that it's saved, like:
mac_address = MacAddress.create(...)
assert !mac_address.new_record?
Where that tells you if it's been saved or not. Alternatively you can use create! which will raise ActiveRecord::RecordInvalid if it failed.
For future reference and for anyone viewing this question - I rewrote my test with save instead of create like below:
test 'mac address must be unique' do
test_address = 'MACADD123'
original_mac = MacAddress.new(user: User.first, address: test_address)
duplicate_mac = MacAddress.new(user: User.second, address: test_address)
assert original_mac.save
assert MacAddress.pluck(:address).include?(test_address)
assert_not duplicate_mac.save
duplicate_mac.errors.messages[:address].include?('has already been taken')
end
I have the following User model:
class User < ActiveRecord::Base
validates :email, presence:true
end
When I do:
#user = User.find_or_create_by(:email => params[:email])
I was doing #user.nil? In order to see if the user is there, but it is not acting as I thought:
puts #user.inspect
--> #<User id: nil, email: "", created_at: nil, updated_at: nil>
Why is a user gets created, even though not saved in the DB? How can I make sure that the #user is "nil"? #user.id.nil?
Thanks
The User record was not saved because it has a blank email (""), so the presence validation fails. You can check the error messages with #user.errors.full_messages.
With Active record calling .create (or one of its derivatives) will return a new record if the save operation fails (including validations). If you want an Error to be raised when the User record is invalid you can use .create!, with a bang(!). I would suggest this newer syntax which is compatible with Rails 4:
# Raises an Error if no matching record is found and the new record fails to save.
#user = User.where(:email => params[:email]).first_or_create!
# Does not raise an error if new record fails to save. The returned object will be a new record with post-validation error states.
#user = User.where(:email => params[:email]).first_or_create
Which method you choose depends on how you want your application to behave.
You can ask if it is a new record via:
#user.new_record?
class User < ActiveRecord::Base
attr_accessible :email, :name
validates :name,:presence=>true,
:length=>{:maximum=>15}
validates :email,:presence=>true,
:length=>{:maximum=>15}
end
I am new to rails and the simplest of the validators are not working. I think I may be making a very silly mistake . I have a User model with 2 attributes only and when I create a new user in ruby console with wrong validations like no name or a longer name than 15 characters it gets added happily Please suggest.I am using rails version:3.2.13 and ruby version:1.9.3
If you are on rails console, be sure to type reload! after making changes to models. In this way, all changes will be reloaded in the console instance.
Moreover, are you sure you are saving these models? You should try something like this:
user = User.new(email: "john.doe#gmail.com")
user.save
If the result of the last line is false, you can view the validation errors with
p user.errors
I am going though the tutorial (which I must say is a excellent resource) and I don't quite understand the following:
In section 6.3.1 we create a password_digest column in the db via the creating and running a migration script via :
rails generate migration add_password_digest_to_users password_digest:string
bundle exec rake db:migrate
bundle exec rake db:test:prepare
bundle exec rspec spec/
Then on the rails console I am able to instantiate a user model object and set password_digest on it :
irb(main):007:0> #user = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>
irb(main):008:0> #user.password_digest = "zzzz" => "zzzz"
irb(main):009:0> #user.password_digest => "zzzz"
However I can not see a password_digest property on the User model class definition :
class User < ActiveRecord::Base
attr_accessible :email, :name
before_save { |user| user.email = email.downcase}
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, presence: true, length: {maximum: 50}
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX}, uniqueness: {case_sensitive: false}
end
I imagine Rails is doing some magic under the covers, would someone mind explaining exactly what it's doing?
Thanks!
You are right - what's actually going on here is rails magic behind the scenes.
Whenever you have a descendant of ActiveRecord::Base ActiveRecord will look at the database table for that class and automatically create accessors for you - they won't show up in the class definition. This seems crazy if you're coming from a language like C# where you had to do this kind of stuff manually before.
What ActiveRecord is doing (this is a very watered down explanation, the actual thing it does much more complicated) is kind of sticking the following code in your class:
class User < ActiveRecord::Base
def password_digest
#password_digest
end
def password_digest=(val)
#password_digest = val
end
end
The other thing to note is that it doesn't just do the creation of an attribute getter and setter for you - it mixes in some type casting based on the type of the column. Check out this question for more info and some possible gotchas.
The net result of this is actually kind of a bonus, and one of the reasons I like rails: you define the column once in your database, and you get it put into your model class for free.
This pattern is common to Rails though, and you'll see it often. If you are still learning Ruby or the Rails framework and you aren't 100% sure where something comes from, don't be afraid to look more closely - so-called Rails 'magic' occurs frequently and it takes some time to not be surprised. I had this experience when I first moved to Rails from other languages.
Here are a couple of ways that a class can have a member variable that you cannot see in the class definition:
class ActiveRecord
def password_digest=(val)
#x = val
end
def password_digest
#x
end
end
class User < ActiveRecord
end
me = User.new
me.password_digest = "hello"
puts me.password_digest #=> "hello"
Created dynamically at run time:
class User
end
User.class_eval do
attr_accessor :password_digest
end
me = User.new
me.password_digest = "hello"
puts me.password_digest #=> "hello"
The problem I found with the rails tutorial is that:
1) It is extremely boring.
2) Because all you do is copy code.
Congratulations on getting to Chapter 6!
So first I had this class:
class User < ActiveRecord::Base
attr_accessible :email, :name
end
and was able to create and save users in ruby sandbox.
Then I added validation like this:
validates(:name, presence: true)
saved my changes, went back to console, and said this:
>> user = User.new(name: "", email: "mhartl#example.com")
>> user.save
It should return FALSE because name is blank. But it returned true. Why?
Maybe I should restart the sandbox console?
Try doing:
reload!
in the console.
This will reload your models and should pick up the new validation. This makes it unnecessary to restart the console. I use this like a bajillion times a day. :D
Yes never mind. I restarted the sandbox console and now validation is working correctly.