rails 3 ruby 2 conditional validations not working as expected - ruby-on-rails-3

I want to validate the note field only if the user_id field is blank?
I tried without a lambda:
validates_presence_of :note, :unless => user_id?
I tried through a method:
validates_presence_of :note, :unless => user_is_present?
def user_is_present?
self.user_id.present?
end
I tried a lambda:
validates_presence_of :note, :unless => lambda { self.user_id.present? }
I tried a Proc
validates_presence_of :note, :unless => Proc.new { |x| x.user_id.present? }
All result in:
"Called id for nil, which would mistakenly be 8 -- if you really wanted the id of nil, use object_id"
Trial & Error confirms is the nil value is the user_id...which is NOT validated and should not be failing.
first question is are there any errors in my attempts?
second question is how can I accomplish this?

I would try
validates :note, presence: true, unless: 'user_id'
You don't need to define any methods...

Related

Rails validators discrepancy between presence and format

I have a model that takes an email address, but I do not want to require it for instance creation. I tried the following:
validates :email, :presence => false, :format => { :with => email_regex }
But this fails my test suite, the format regex apparently makes the presence of the email attribute required.
I thought it might be possible with a before_save method: is it possible to reject saving the object in a before_save method? Is there a better, "Rails way" of doing this?
You can use :allow_blank (or :allow_nil):
validates :email, :allow_blank => true, :format => { :with => email_regex }

Rails validation error email is too short, email is invalid

In attempting to seed my database I ran into a validation error on my User model's email attribute. The error:
Validation failed: Email is too short (minimum is 5 characters), Email is invalid
The thing is, my email is xxxxxxxx#gmail.com. I have five characters. Sorry for the beginner question but I don't know what is going on. I recently followed Railscasts to reset a User's password, and enable CanCan. I'm not sure if CanCan would affect anything, but prior to exploring that new functionality I've been able to fully seed my database without problems. I've pasted in some of my code below. I'm running Rails 3.0.5 and Ruby 1.9.2.
An example of how I create a User in my seed file:
me = User.create(:email => 'me#gmail.com', :password => 'test', :profile => my_profile)
User.rb model:
class User < ActiveRecord::Base
attr_accessor :password
attr_accessible :password, :password_confirmation
before_save :encrypt_new_password
before_create { generate_token(:auth_token) }
before_validation :downcase_email
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
validates :email, :uniqueness => true,
:length => { :within => 5..50 },
:format => { :with => /^[^#][\w.-]+#[\w.-]+[.][a-z]{2,4}$/i }
validates :password, :confirmation => true,
:length => { :within => 4..20 },
:presence => true,
:if => :password_required?
Add :email to attr_accessible to allow mass assignment on it. Without that the email field will not even be set so validation will fail.

How to do conditional statement of validation from controller name in model

Example:
account_controller: do not validate a password
password_controller: validate a password
my idea is...
class User
include Mongoid::Document
...
validates :username,
:presence => true
validates :password,
:presence => { :if => :passord? }
...
def password?
# self.controller.to_s == 'password'
end
end
First of all, my idea is wrong?
Anyone have another good idea?
You can add virtual attribute to your model and conditional validation:
class User
attr_accessor :skip_password_validation
validates :password, :unless => :skip_password_validation
end
And put something like this into controller:
user.skip_password_validation = true

Why is user.save true but email shows as nil?

I'm using a nested model form for sign-up and am working through the kinks as a beginner. One issue that popped up in particular though that I don't really get is user.email is returning as nil.
Before I started playing around with the nested model form, I could create records in the console wihtout a problem. Now, however I can't create records and some of the latest records created have nil as their email. (I'm not sure if it has anything to do with the nested model at all, but that's my reference point for when it started going haywire.)
If I go into rails console to create a new User/Profile, I follow this process:
user = User.new
user.email = ""
user.password = ""
user.profile = Profile.new
user.profile.first_name = ""
...
user.profile.save
user.save
Everything goes well until user.save, which gives me the NameError: undefined local variable or method 'params' for #<User:>. In rails console it pinpoints to user.rb:25 in create_profile
So here is my User model:
class User < ActiveRecord::Base
attr_accessor :password, :email
has_one :profile, :dependent => :destroy
accepts_nested_attributes_for :profile
validates :email, :uniqueness => true,
:length => { :within => 5..50 },
:format => { :with => /^[^#][\w.-]+#[\w.-]+[.][a-z]{2,4}$/i }
validates :password, :confirmation => true,
:length => { :within 4..20 },
:presence => true,
:if => :password_required?
before_save :encrypt_new_password
after_save :create_profile
def self.authenticate(email, password)
user = find_by_email(email)
return user if user && user.authenticated?(password)
end
def authenticated?(password)
self.hashed_password == encrypt(password
end
protected
def encrypt_new_password
return if password.blank?
self.hashed_password = encrypt(password)
end
def password_required?
hashed_password.blank? || password.present?
end
def encrypt(string)
Digest::SHA1.hexdigest(string)
end
end
Can anyone help me figure out what's going on?
UPDATE: I tried changing my regex but I'm still seeing nil for email. Though a prior SO post said not to blindly copy regex without testing, so maybe I just didn't test it correctly. Good news though: I no longer get the error.
attr_accessor simply defines a "property" on the object and has no relation to the attributes of a ActiveRecord model (attributes is a Hash of the fields and values obtained from a table).
ActiveRecord does not save such "properties" as defined by the attr_accessor. (Essentially, attr_accessor defines a attr_reader and attr_writer (i.e. "getter" and "setter") at the same time)

Rails 3: validates :presence => true vs validates_presence_of

What is the difference between validates :presence and validates_presence_of? Looking through ActiveModel it looks like they setup the validation the same way. However, given the following model definition:
class Account < ActiveRecord::Base
has_one :owner_permission, :class_name => 'AccountPermission', :conditions => { :owner => true, :admin => true }
has_one :owner, :class_name => 'User', :through => :owner_permission, :source => :user
validate :owner, :presence => true
validates_associated :owner
end
Calling save on an instance of Account does not validate the presence of owner. Though, if I use validates_presence_of it will.
All those validates_whatever_of :attr macros do is call validates :attr, :whatever => true.
The problem is you are using validate and not validates.
In Rails 3.x and 4.x - it is now encouraged to use the following syntax:
validates :email, presence: true
validates :password, presence: true
Instead of the 2.x way:
validates_presence_of :email
validates_presence_of :password
In fact validates and validates_presence_of is not entirely equal !
validates_presence_of is allowing you to also lazily check by example of the value in the field is included in another table.
Like that:
validates_presence_of :pay_type, :inclusion => PaymentType.names
Which is something you can't do as easily with something like that
validates :pay_type, presence, :inclusion => PaymentType.names
Cause the inclusion is only evaluated the first time (not in a lazy way)
I would have thought that it is appropriate to use validates :foo presence: true when you want to include other validations of :foo such as length or uniqueness. But if you know the only validation you'll need for an attribute is presence, then validates_presence_of appears to be more efficient.
So:
validates :foo, length: {maximum: 50}, uniqueness: true,
format: {with: /bar/},
presence: true # lots of validations needed
But:
validates_presence_of :foo # only presence validation needed