Rails 3 validation with unique scope conditional - ruby-on-rails-3

I have for example this code in my model validation:
validates :fb_user_id, :uniqueness => {:scope => :campaign_id}
But can occurs that campaign_id has value -1 for different users, that raises the validate exception.
It's possible to do something like this?
validates :fb_user_id, :uniqueness => {:scope => :campaign_id}, if :campaign_id != -1
Can I put a if conditions inline in the validates statement or if not possible how can I do the trick?

Following the idea of MagicMarkker, I have found a solution:
validates :fb_user_id, :uniqueness => {:scope => :campaign_id}, :if => :valCampaign?
def valCampaign?
if campaign_id == -1
return false # skip the validation
else
return true # run the validation
end
end

Related

Rails 3 Validation with Scope Conditions

I have an invoice model with approver_note, po_number and state_id.
I need validations to check:
validates :approver_note, :presence => true, {:scope => state_id == 3}
validates :po_number, :presence => true, {:scope => state_id ==2}
So, if the user selects state_id = 3, he must enter a note.
If he selects state_id = 2, he must enter a po_number.
Any assistance would be great... thanks!
You're looking for the :if option instead of :scope.
validates :approver_note, :presence => true,
:if => lambda { |invoice| invoice.state_id == 3 }
But since a lambda is a little ugly, I'd probably add a method to encapsulate what you're doing a bit better:
validates :approver_note, :presence => true, :if => :requires_note?
validates :po_number, :presence => true, :if => requires_po_number?
def requires_note?
state_id == 3
end
def requires_po_number?
state_id == 2
end
If you actually have a bunch of different attributes that are required when state_id is 3, not just a note, then you may want something like this:
validates :approver_note, :presence => true, :if => :green_state?
validates :po_number, :presence => true, :if => orange_state?
def green_state?
state_id == 3
end
def orange_state?
state_id == 2
end
(Replace "green" with -- I dunno -- "high_documentation" or whatever makes sense in your world.)
Or maybe you want to let the state decide what it is:
def green_state?
state.green?
end
It really does help to make the terminology in your code adhere more closely to your real-world language, as opposed to "3" and "2".

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

turning off validation not working

I have the following in my model:
validates :name, :if => :should_validate_name?,
:presence => {:message => "Enter your name"},
:length => { :maximum => 50 },
:allow_blank => true
def should_validate_name?
validating_name || new_record?
end
In my controller I have the following:
def create
#user = User.new(params[:user])
#user.validating_name = false
if #user.save
else
render :action => 'new'
end
end
I don't want to validate for the presence of a name at this point and wish to turn it off.
I thought the code above would work but it doesn't. I don't know why.
You're in the create action, creating a new record. So new_record? will be true, even if validating_name isn't.

Custom method after some validation passes

Ok.
1) I need to validate :link in my model and do that only if it is not blank (or nil).
2) If :link is not blank and standard validation passes — I need to run my custom validation method to check URL availability.
By "standard" validation I mean something like this:
validates :link, :presence => true, :uniqueness => true,
:format => { :with => /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix }
What is the correct way to implement this?
It checks for validation in your model only if link isn't blank:
validates_presence_of :link, :uniqueness => true,
:format => { :with => /^(http|https)://[a-z0-9]+([-.]{1}[a-z0-9]+).[a-z]{2,5}(:[0-9]{1,5})?(/.)?$/ix }, :if => :link_present?
def link
self.link
end
def link_present?
link.present?
end
Ok. With friends help I finally solved this.
class Post < ActiveRecord::Base
# skipped some things not necessary
validates_format_of :link, :with => /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix , :allow_blank => true
validates_length_of :link, :maximum => 2000
validates_uniqueness_of :link, :allow_blank => true
validate :ensure_link_is_available, :if => proc{|post| post.link.present? && post.errors.empty?}
def ensure_link_is_available
begin
require "net/http"
url = URI.parse(self.link)
req = Net::HTTP.new(url.host, url.port)
res = req.request_head(url.path)
rescue
# error occured, add error
self.errors.add(:link, 'The requested URL could not be retrieved')
else
# valid site
if (res.code.to_i > 308)
error_message = 'Server responded with ' + res.code
self.errors.add(:link, error_message)
end
end
end
end
validates_format_of :url_field, :with => URI::regexp(%w(http https))

Rails 3 validates rule based on action

This seems like a simple question but I can't seem to find an answer short of writing custom validators. I have this validator
validates :password, :presence => true, :confirmation => true, :length => { :minimum => 5}
there are more rules applied such as some regex for complexity, but this gives the gist.
The issue is that I only want presence applied on create, everything else needs to be on create and update. Because the user may not be changing a password when updating their information.
I tried splitting the rules
validates :password, :presence => true, :on => :create
validates :password, # The rest of the rules
This resulted in all rules being ignored for update. Is there a simple way to apply only one rule to create and the rest to everything?
You can try keeping it in one line, but applying :on => :create to just the :presence check:
validates :password, :presence => {:on => :create}, :confirmation => true, :length => { :minimum => 5}
However, I'm not sure it makes sense to always require a minimum length, but not always require presence -- if you update an existing record with a blank password, it's going to fail validations anyway since the length is 0.
My hunch is that the problem is that the validate :password call is not additive. Can you switch the presence check to:
validates_presence_of :password, :on=>:create
And then keep your other validations using the validate. Does that work?