Right shape of validation rules (Rails 3) - ruby

I use these rules in my model:
validates_presence_of :email, :message => "E-mail must be filled!"
validates_format_of :email, :with => /\A[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]+\z/, :message => "This is not email address!"
validates_uniqueness_of :email, :message => "This email is already taken!"
validates_confirmation_of :password, :message => "Password must be the same!"
validates_presence_of :password_confirmation, :length => { :minimum => 6, :maximum => 40 }, :message => "Your password must have at least 6 characters!"
If I send an empty form, so as the output will be displayed all of those 5 lines above. What I have to do to display only the 1st and 5th rules?

Here's one solution.
Essentially the advice is to use the :allow_blank option on all validations except the presence validations. This makes Rails skip the validations if the field is blank. That way, you only see the error messages related to missing values when submitting an empty form.

Related

ActiveRecord format validation not firing

I'm trying to apply a format validation to a model, but when I create the model it isn't coming back as invalid. I added a length validation and it works just fine. What am I doing wrong?
require 'rubygems'
require 'active_record'
class User < ActiveRecord::Base
validates :username, :format => { :with => /[A-Za-z]+/, :message => "Only letters a-z are allowed" }
validates :username, :length => { :maximum => 20, :too_long => "%{count} letters is too many"}
end
ActiveRecord::Base.establish_connection( ... )
user = User.create!(:username => 'johnsmith1234', :signupdate => '2010-11-12')
puts user.valid?
The output is always true unless I have a length of over 20 characters, then I get an error on the length. So why doesn't the format validation fire?
/[A-Za-z]/ checks for one or more alphabets in given string. If you want only alphabets you need to specify ^ and $. (i.e) /^[A-Za-Z]$/
validates :username, :format => { :with => /^[A-Za-z]+$/, :message => "Only letters a-z are allowed" }
One more thing use new to create new user. Because create or create! will throw error if your validation fails.
user = User.new(:name => "john123")
if user.valid?
#do something
else
#do something `user.errors.full_messages` will have your validation messages if it has error
end

Not null fields for ActiveAttr

I'm having issues enforcing a field to not be nil within ActiveAttr::Model.
Is there an elegant way of enforcing this constraint within the model instead of defining it in the controller? Or am I testing incorrectly for the scenario?
Model:
class Message
include ActiveAttr::Model
attribute :name, :presence => true, :allow_nil => false, :allow_blank => false
attribute :email, :presence => true
attribute :content, :presence => true
validates_format_of :email, :with => /^[-a-z0-9_+\.]+\#([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i
validates_length_of :content, :maximum => 500
end
RSpec:
module MessageSpecHelper
def valid_message_attributes
{
:name => "Walter White",
:email => "walter#hailtheking.com",
:content => "I am the one who knocks"
}
end
end
it "should have error on name (alternate with nil)" do
#message.attributes = valid_message_attributes.except(:name => nil)
#message.should have(1).error_on(:name)
end

undefined method `password_hash' error with datamapper

I'm trying to build [Ryan Bates' "authenticaion from scratch"][1] using sinatra but authentication does not work. I get a "undefined method password_hash" error.
Everything else is working. I checked datamapper documentation, especially for lazy loading, but couldn't find anything useful. The code is below. What mistake am I doing?
main.rb (only relevant part)
post "/login" do
user = User.authenticate params[:email], params[:password]
if user
session[:user_id] = user.id
redirect "/"
else
session[:errors] = "No such user or bad password."
redirect "/login"
end
end
user.rb
require 'data_mapper'
require 'dm-validations'
require 'bcrypt'
module Kimsin
DataMapper.setup :default, 'sqlite3:///home/barerd/RProjects/kimsin/users.db'
class User
attr_accessor :password, :confirm_password
include DataMapper::Resource
property :id, Serial
property :email, String, :required => true, :unique => true, :format => :email_address,
:messages => { :presence => "We need your email address.", :is_unique => "We already have that email.", :format => "Doesn't look like an email adress.."}
property :password_salt, String
property :password_hash, String, :length => 80
validates_presence_of :password, :confirm_password, :messages => { :presence => "You have to type a password and confirm it." }
validates_format_of :password, :confirm_password, :with => /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])([\x20-\x7E]){8,40}$/, :messages => { :format => "The password should be 8 to 40 characters long and contain at least one digit, one lowercase and one uppercase letter and one special character." }
before :save, :encrypt_password
def self.authenticate email, password
user = User.all :email.like => email
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password != nil
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret password, password_salt
end
end
end
DataMapper.finalize
end
Adding a attr_reader :password_hash solved it.

Rails Active Record Validation condition base

class Material < ActiveRecord::Base
belongs_to :material_type
belongs_to :product_review
validates :url, :presence => true, :if => :url_presence?
validates :video, :presence => true, :if => :video_presence?
def url_presence?
if !self.title.blank? and self.material_type.title.eql? :url
true
end
end
def video_presence?
if !self.title.blank? and self.material_type.title.eql? :video
true
end
end
has_attached_file :video,
:url => "/system/video/:id/:attachment/:style/:basename.:extension",
:path => ":rails_root/public/system/video/:id/:attachment/:style/:basename.:extension",
:default_url => "/image/video.png"
end
I assumption if its finds Title fields fill and material_type is url than it perform validation for url field presence validation check, but it not helpful
I think you need to compare strings, not symbols.
validates :url, :presence => true, :if => :url_present?
validates :video, :presence => true, :if => :video_present?
def url_present?
self.title.present? and self.material_type.title == "url"
end
def video_present?
self.title.present? and self.material_type.title == "video"
end

Only validate an Rails3 Model when an value entered

I need to validate a filed called phone_number in my rails3 app. This filed is optional but when a user enter a phone_number i will check the format. The RSpec2 test runs fine but when i go to the sign_up view and don't touch the phone_number field i become an "Phone number is too short (minimum is 6 characters)" and "Phone number is invalid" error.
What is the problem in my model? My target is to validate the phone_number if a user enter this if the number blank i will save an nil in my database.
This is my User model:
class User < ActiveRecord::Base
belongs_to :address
accepts_nested_attributes_for :address
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :confirmable, :lockable, :validatable
# Setup accessible (or protected) attributes for your model
attr_readonly :username
attr_accessible :email, :password, :password_confirmation, :remember_me, :phone_number, :username, :newsletter, :address_attributes
validates :username, :presence => true, :uniqueness => true, :length => {:minimum => 4, :maximum => 16 }, :format => { :with => /\A[a-z0-9][a-z0-9._-]*\z/i }
validates :phone_number, :length => {:minimum => 6, :maximum => 25}, :format => { :with => /\A\S[0-9\+\/\(\)\s\-]*\z/i }, :allow_nil => true
validates :address, :presence => true
end
My Rspec Method to test the phone_number:
it "should be valid without an phonenumber" do
Factory.build(:user, :phone_number => nil).should be_valid
end
it "should be invalid with an invalid phonenumber" do
invalid_phonenumbers.each do |invalid|
Factory.build(:user, :phone_number => invalid).should_not be_valid
end
end
it "should be valid with an valid phonenumber" do
valid_phonenumbers.each do |valid|
Factory.build(:user, :phone_number => valid).should be_valid
end
end
def invalid_phonenumbers
["Hans Wurst","+49 221 Hans","Gebe ich nicht ein"," ","110",""]
end
def valid_phonenumbers
["+492203969534","0221/549534","0800-2222 800","+49-0221-2222-390","+49 (221) / 549534 - 23","+49 (0) 221 / 549534 - 23","0221269534"]
end
try this instead of :allow_nil => true, :allow_blank => true
validates :phone_number, :length => {:minimum => 6, :maximum => 25}, :format => { :with => /\A\S[0-9\+\/\(\)\s\-]*\z/i }, :allow_blank => true

Resources