I want to skip some model validation for controller functions. I am doing like this
Model :
attr_accessible :skip_method_2
validates :name, presence: true, length: { maximum: 50 }, :unless => :skip_method_2
VALID_PHONE_REGEX = /\(?([0-9]{3})\)?([ .-]?)([0-9]{3})\2([0-9]{4})/
validates :phoneno, presence: true,uniqueness: { case_sensitive: false, :scope => :user_id}, format: { with: VALID_PHONE_REGEX }, :unless => :skip_method_2
Controller :
def contacts_callback
#contacts = request.env['omnicontacts.contacts']
#contacts.each do |contact|
next if current_user.contacts.exists?(:email => "#{contact[:email]}")
contact1 = current_user.contacts.new(:skip_method_2 => true)
contact1.name = contact[:name]
contact1.email = contact[:email]
contact1.group = "Others"
contact1.save
end
redirect_to "/contact"
end
I dont want to save it by :validation => false. I want to skip name and phoneno validation for contacts_callback function. But it is not working.
It gives error in controller -
undefined local variable or method `skip_method_2' for contacts_callback. I already mentioned attr_accessible in my model
Change validates :name, presence: true, length: { maximum: 50 }, :unless => :skip_method_2
to
validates :name, presence: true, length: { maximum: 50 }, :unless => lambda {|x| x.skip_method_2}
Also checkout this answer
Related
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: Proc.new { |a| a.email.blank? }
},
length: {
minimum: 10,
unless: Proc.new { |a| a.phone.blank? }
}
validates :email,
uniqueness: {
unless: Proc.new { |a| a.email.blank? }
},
presence: {
message: "Phone/Email can't both be blank",
if: Proc.new { |a| a.phone.blank? }
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
unless: Proc.new { |a| a.email.blank? }
}
def phone_blank?
Proc.new { |a| a.phone.blank? }
end
end
How do I create a method to replace with all the Proc?
I just learned about Proc and I'm not too familiar with that yet. I tried to use :phone_blank to replace all the proc after if:/unless:, but it failed to work. Can someone tell me how to make the phone_blank? method work to replace all the proc embeded in the code? thanks~
edited:
I forgot to mention I'm using rails_admin for the admin interface. If I call methods in if:/unless:, the admin panel will show Model 'Client' could not be found then the model would disappear from the admin panel. I'm not sure it's a rails_admin thing or that's how Rails 5 behaves. I'm quite new to RoR and still quite confuse with all different versions of Rails....
For using method there is no need in Proc wrapper.
e.g.
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: email_blank?
},
length: {
minimum: 10,
unless: phone_blank?
}
validates :email,
uniqueness: {
unless: email_blank?
},
presence: {
message: "Phone/Email can't both be blank",
if: phone_blank?
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
unless: email_blank?
}
def phone_blank?
phone.blank?
end
def email_blank?
email.blank?
end
end
Also you can simply specify this condition in validation directly without method or Proc as a string.
e.g.
class Client < ApplicationRecord
has_many :projects
validates :name, presence: true
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: 'email.blank?'
},
length: {
minimum: 10,
if: 'phone.present?'
}
validates :email,
uniqueness: {
if: 'email.present?'
},
presence: {
message: "Phone/Email can't both be blank",
if: 'phone.blank?'
},
format: {
with: URI::MailTo::EMAIL_REGEXP,
if: 'email.present?'
}
end
You could write a class method that returns a lambda, something like:
def self.blank_field?(field)
->(m) { m.send(field).blank? }
end
and then say things like:
validates :phone,
presence: {
message: "Phone or Email can not be blank",
if: blank_field?(:email)
},
length: {
minimum: 10,
unless: blank_field?(:phone)
}
Note that we use blank_field? instead of blank? since blank? is already taken and we don't want to override it. And since this is an "internal" method, we don't have to worry about public_send versus send.
Not a direct answer, but an alternative approach in DRY-ing things is to make use of with_options:
with_options if: -> { email.blank? } do
validates :phone, presence: { message: "Phone or Email can not be blank" }
end
with_options if: -> { phone.blank? } do
validates :email, presence: { message: "Phone/Email can't both be blank" }
end
with_options if: -> { email.present? } do
validates :phone, length: { minimum: 10 }
validates :email, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
end
This is especially useful when the validations have conditions depending on different... say, categories (if you have a category column), and you can just simply group these validations up with_options
Trivia:
You can think of -> { ... } just like Proc.new { ... } which you were already familiar with (though accurately speaking it's a lambda ... which is like a special type of Proc. If you're interested further, see these SO posts: HERE and HERE
I have a Model Product with fields:
name price product_type_id:integer size:string page_quantity:integer.
How can make this validation work for Product model create action?
- if product_type.id == "1"
validates :size, presence: true
validates :page_quantity, presence:false
- else
validates :size, presence: false
validates :page_quantity, presence:true
end
validates :size, presence: true, if: Proc.new { |p| p.product_type_id == "1" }
validates :page_quantity, presence:false, if: Proc.new { |p| p.product_type_id == "1" }
validates :size, presence: false, unless: Proc.new { |p| p.product_type_id == "1" }
validates :page_quantity, presence:true, unless: Proc.new { |p| p.product_type_id == "1" }
end
In my user model, I have the field email, not required.
I want to validate the field, if and only if it's present.
It can be blank but if it's present should be validated.
Well, how it is now, it's never validated.
If I remove the unless condition it is always validated (normally)
class User < ActiveRecord::
validates :email,
format: { with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i },
uniqueness: true,
unless: lambda { email.nil? }
Any suggestion?
if you are using devise,then you dont need to wory about it...if not then you can use the below code in the model:-
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX,unless: lambda { self.email.blank? }
Probably because it's not nil, but an empty string. Use allow_blank instead:
validates :email,
format: { with: /\A([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i },
uniqueness: true,
allow_blank: true
In model I want something like below
validates :category, :presence => true if self.post = "this_is_post"
Is it possible or I have to use a hook method before save for this checking?
This should work:
validates :category, :presence => true, :if => ->(a){ a.post == 'this_is_post' }
Here, more than one code snippest for validate condition in rails:
class Person < ActiveRecord::Base
validates :surname, presence: true, if: "name.nil?"
end
========================
validates :category,
:presence => true,
:if => :valid?
def valid?
self.post == "this_is_post"
end
================
class Person < ActiveRecord::Base
validates :category, presence: true, if: "self.post.eql?('this_is_post')"
end
post.rb
#allowed_post_types = [
'type1',
'type2',
'type3',
'type4'
]
#validate post type
validates :post_type, :presence => true, :inclusion=> { :in => #allowed_post_types }, :if => :valid_post_type?
def valid_post_type?
self.post_type != 'type5'
end
how can i enable validates :post_type line of code whenever the :post_type is not type5 ?
Tried the above but it doesn't seem to work
Try:
validates :post_type,
:presence => true,
:inclusion=> { :in => #allowed_post_types },
:if => lambda { |a| a[:post_type] != "type5" }