validates syntax in rails 3 - ruby-on-rails-3

This is my model:
class User < ActiveRecord::Base
attr_accessible :email, :name
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: true
end
The author of Rails Tutorial Example said "Curly braces are optional when passing hashes as the final argument in a method", but here the presence validation is not final argument, but it can be used without curly braces and is valid code. The format validation of email attribute also works.
Anybody can explain me why?

:name, :presence: true, length: { maximum: 50 } is the last argument passed to validates, so you don't need curly braces for it.
A case where you would need curly braces would be if you were passing arguments after that hash:
validates { :name, presence: true, length: { maximum: 50 } }, some_other_argument
Where some_other_argument here is some hypothetical argument that comes after the hash. To process this correctly you would need the curly braces around the hash.

Related

Rails 4 creating relational record

I am having some issues creating a record from a relational record. This code creates a new user perfectly however it seems that it skips over creating the user's profile all together. It also throws no errors.
any help would be great.
Model
class User < ActiveRecord::Base
has_one :profile
def self.find_for_facebook_oauth(auth)
if user = User.find_by_email(auth.info.email)
user
else
user = User.create( provider: auth.provider,
uid: auth.uid,
email: auth.info.email,
password: Devise.friendly_token[0,20] )
user.build_profile( username: auth.extra.raw_info.username,
first_name: auth.info.first_name,
last_name: auth.info.last_name,
gender: auth.extra.raw_info.gender,
country: auth.extra.raw_info.locale,
image: auth.info.image )
user
end
end
end
Try user.create_profile instead.http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
I forgot that in my Profile class I had a validation for username
model
class Profile < ActiveRecord::Base
# Use friendly_id
extend FriendlyId
friendly_id :username, use: :slugged
belongs_to :users
mount_uploader :image, ProfileImageUploader
validates :username, presence: true, length: {maximum: 16} # <~~
validates :first_name, presence: true, length: {maximum: 255}
validates :last_name, presence: true, length: {maximum: 255}
validates :gender, presence: true, inclusion: %w(male female)
end
My OmniAuth was not giving the username therefore it was rolling back the commit.

How to validate text isn't blank in Rails

if I do
validates :body, :presence => true, :length => {:maximum => 30000, :message => ' is a bit long...'}
validates :body, :length => {:minimum => 10, :message => ' is a bit short...'}
I still have a possibility of having a text which includes only spaces and /r or /n - non visible chars, which while the text isn't blank by definition, it is blank by looking at it
How can I validate that the text had a min and max length listed above and is also visible (not 10 spaces)
Rails adds the handy method blank? which checks for false, nil and empty strings as described here.
Rails also adds the handy validator allow_blank: false.
So in your case it should be:
validates :body, presence: true, allow_blank: false
Edit (original answer above):
As stated in the answer below, allow_blank: false is not needed as that's the default behaviour of presence: true.
presence: true already does that according to
http://guides.rubyonrails.org/active_record_validations.html#presence
This helper validates that the specified attributes are not empty. It uses the blank? method to check if the value is either nil or a blank string, that is, a string that is either empty or consists of whitespace.
What if you try adding something like this:
validates_format_of :body, :with => /\A[[:graph:]]\Z/i
Notes:
validates_format_of lets you validate with regex
[[:graph:]] lets you check a string for printable characters (see "Character Classes")

Rails 3: Apply the same validation rules to multiple table fields

I have created a model with several fields that should accept the same data format (strings, but can be anything, FWIW). I'd like to apply the same validation rule to all those fields. Of course, I can just go ahead and copy/paste stuff, but that would be against DRY principle, and common sense too...
I guess this one is pretty easy, but I'm a Rails newcomer/hipster, so excuse-moi for a trivial question. =)
So if you had say three fields to validate:
:first_name
:last_name
:age
And you wanted them all to be validated? So something like this:
validates_presence_of :first_name, :last_name, :age
Edit: There are numerous different validation methods in Rails )and they're wonderfully flexible). For the format of the field you can use validates_format_of, and then use a Regular Expression to match against it. Here's an example of matching an email:
validates_format_of :email, :with => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
I'd check out the Active Record Validations and Callbacks guide; it provides comprehensive insight about a lot of the features Active Record provides in terms of validation. You can also check out the documentation here.
If you are using any of the built-in validations (presence, length_of) you can apply a single validation to multiple attributes like this:
validates_presence_of :name, :email
If you have custom logic you can create a validator object to house the code and apply it individually
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << (options[:message] || "is not an email") unless
value =~ /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
end
end
def Person
validates :home_email, :email => true
validates :work_email, :email => true
end
see: http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/
In Rails 4 you can apply the same validation to multiple columns by using a loop:
[:beds, :baths].each do |column|
validates column, allow_blank: true, length: { maximum: 25 }
end
Both beds and baths are validated using the same validations.
Edit:
In Rails 4.2 you can do this same thing by putting multiple symbols after the validates function call. Example:
validates :beds, :baths, allow_blank: true
Use Themis for this:
# Describe common validation in module
module CommonValidation
extend Themis::Validation
validates_presence_of :foo
validates_length_of :bar, :maximum => 255
end
class ModelA < ActiveRecord::Base
# import validations
include CommonValidation
end
class ModelB < ActiveRecord::Base
# import validations
include CommonValidation
end
Or you can use "with_options", for example:
with_options presence: true do |video|
REQUIRED_COLUMNS.map do |attr|
video.validates attr
end
end

has_secure_password: how to require minimum length

How do I require that a password has a minimum length when using has_secure_password in Rails 3.1? I tried to do:
class User < ActiveRecord::Base
...
validates :password, presence: { on: create }, length { minimum: 8 }
...
end
but then the validation fails with password "too short" on update when password is not provided in form params. For other attributes length is only validated if the value for the field is provided. Is this a bug in the has_secure_password implementation or am I doing something wrong?
You should do something like:
validates :password, presence: { on: create }, length { minimum: 8 }, :if => :password_changed?
Use this:
validates :password, length: { minimum: 8 }, if: :password_digest_changed?
Now this validation will run on any attempt to update the password, and it wont break otherwise, #apneaddiving's answer was good but it had some small sintax issues and would only run on creation, so any update on password wouldn't be validated.

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