Rails - How to build a custom validation - ruby-on-rails

I have a Rails 3 form, with data-remote => true.
The form field is handle, like a twitter handle. I want to add validation to ensure it's handle friendly, meaning, no spaces, or non-url friendly characters.
Where to start, do I build a customer validation for this?
Thanks

Looks like you want to use validates_format_of
class Product < ActiveRecord::Base
validates_format_of :handle, :with => /\A[a-zA-Z]+\z/, :message => "Only letters allowed"
end
Change the regular expression pattern to match your needs. See the Rails Guides on validation for more information.

Look into validates_each
validates_each :handle do |record,attribute,value|
# your validation code here, and you can record.errors.add().
end

In rails 3 the best practice will be using
validates :handle, :format => {:with => /\A[a-zA-Z]+\z/, :message => "Only letters allowed"}

Related

How to do a simple regex validation in rails

How can perform a reguler expression to validate for either - or _ in the person username. i dont want to accept any other character like .#()$etc just - or _ so the person can either have a name like mike, mikel_mark or mike-mark. very simple. Thank you
example:
validate_format_of :username, with: "...."
The Rails 3 way to do validations is the following:
validates :username, :format => {:with => /\A[0-9a-z_]+\Z/i}
The form of validate_format_of is more Rails < 3 like and followed the "type of validation" concept, whereas the validates form is attribute based (you write all validations that apply to the attribute in one statement).
Check out the docs here: http://apidock.com/rails/v3.2.13/ActiveModel/Validations/ClassMethods/validates

Validate on custom words

I have a field in my form, that should not accept some specific words(www, ftp, smtp, etc). Is there any validator that could make some kind of black listed words, that can not be written to db?
validates :subdomain, :exclusion => { :in => %w(www ftp smtp) }
ref: rails guide
You should create your own black list validator.
The syntax could be
validates :field, :black_list => {:file_path => "/path/to/words_file"}
Your validator will look to each word in the /path/to/words_file file and add errors on your model if the attribute field contains one black listed word.

Rails validate :if with checkboxes

I am working with a form having 2 checkboxes: option_one and option_two.
I don't want to allow submission of the form if option_two is checked and option_one is not.
In other words if somebody checks option_two, they must check option_one as well.
So in my MyModel I wrote :
validates :option_one, :presence => true, :if => option_two_active?, :message => "Dummy message."
Then in the MyController, I added :
def option_two_active?
params[:option_two] == "1"
end
But it keeps giving me the following error :
NoMethodError in MyController#index
Is my approach correct ? How can I achieve this ? Thanks in advance.
You have to specify the conditional method with a symbol:
validates :option_one, :presence => true, :if => :option_two_active?, :message => "Dummy message."
Also, you since you can't use params from a model, you should assign that value to the model from the controller, either with create, update_attributes, or manually. If you want to persist the option_two field, then it should be a database column, else you can just create an attribute accessor:
attribute_accessor :option_two
The way you reference the method, it will be called directly as the class is first loaded. However, the :if parameter is expected to be used with either a proc which is then called during validation or with a symbol representing a method name. In your case, you should thus setup your validation like this:
validates :option_one, :presence => true, :if => :option_two?, :message => "Dummy message."
Notice the colon before the method name. Furthermor, the validation method needs to be defined on the model, not the controller. Fortunately, ActiveRecord already defines the proper methods for Boolean fields, as used here.

Negate regex of validates_format_of

In my rails model I have some kind of template system. I want to make sure that users editing it do not make accidental mistakes so I use some simple validators.
They can use markers like ##user_id## that will be replaced later. I want to make sure they do not enter something like ###user_id## that contains too many #, so not any ### (or ####) must appear in the field.
class Template
validates_format_of :text, :with => /##user_id##/,
:message => "##user_id## must be present"
validates_format_of :text, :not_with => /###/,
:message => "Too many #"
end
Unfortunately there is no :not_with option ... is there any chance to solve it using a :with-regex or should I go a separate validate method?
I tried some negative look-ahead, but as there are (mostly) several ## and only one ### they always match one of them.
Use the :without option:
validates_format_of :text, :without => /###/, :message => "Too many #"
What about this...
validates_format_of :text, :with => /(^|[^#])##user_id##($|[^#])/
EDIT: I copied acheong87's rubular examples with my regex.
Can you do something like this?
/^(.(?!###+user_id##|##user_id###+))*$/
Here's a live demo: http://rubular.com/r/SPwsyDlj0y.
In (more) English, it says,
A string in which no character is followed by ###+user_id## or ##user_id###+.

Passing a defined method unless an attribute is present?

Having newbie trouble getting this working. I have Stores that don't have addresses (just a website) as well so the gem (Google-Maps-for-Rails) when seeding actually doesn't create them at all but only the ones with an address.
Store.rb
validates :address,
:presence => {:unless => :website,
:message => "You must enter an address, website, or both."}
acts_as_gmappable :check_process => :prevent_geocoding,
:address => "address",
:normalized_address => "address",
:msg => "Sorry, unable to find address."
# How do I correct this block?
def prevent_geocoding
unless website.present?
address.blank? || (!latitude.blank? && !longitude.blank?)
end
end
I still want to use everything here but what's the correct way to pass this block?
Thank you.
You're on the right track. You can bypass validations by passing a method into if or unless as options on the validation. In the above code, you're passing it as an option to the presence validator and not to the validation itself. Move the unless out of the hash and pass it the name of a method or a Proc — really anything that returns true or false. Here's an example:
validates :address,
:presence => { :message => "You must enter an address, website, or both." },
:unless => Proc.new { |store| store.address.nil? && store.website.present? }
That validation will run every time except in cases where the store both doesn't have an address and does have a website. If you need more complex logic, I recommend moving that out of a Proc and into a method.

Resources