Ruby on Rails form validation: default field value - ruby-on-rails

How do I make Rails treat the "http://" value as blank: if the value is "http://", do not validate website field and insert an empty string (not "http://") into database?
In view:
<%= f.text_field :website, value: "http://" %>
In model:
validates :website, format: { with: /^https?:\/\/\S+/i }, allow_blank: true

You can use :if or :unless to conditionally validate (untested):
validates :website, format: { with: /^https?:\/\/\S+/i }, allow_blank: true, :unless => ['http://', 'https://'].include?(params[:website]) }
Use a before_save callback to convert the string to blank:
def before_save
self.website = "" if ['http://', 'https://'].include?(self.website)
true
end

Related

how to create Proc to prevent DRY in rails model? Rails 5.2.1, rails_admin

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

Rails 5: How to implement a conditional validation for an ActiveModel?

As the code below shows, I am trying to validate an form value of an ActiveModel object based on the value of a checkbox of the same form.
If the box is checked (I made sure it will return true not 1) the validation on order_number should be deactivated, as the field is being deactivated as well (by JS). The naive approach shown below, using the attribute that is connected to the checkbox not_a_customer as conditional for the validation of order_number didn't work.
What else can I try?
I have an ActiveModel class:
class SupportCase
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor(:email, :os, :inquiry_type, :order_number, :first_name, :last_name, :message, :not_a_customer)
validates :order_number, presence: true,
numericality: { only_integer: true },
length: { in: (4..5), message: 'doh' },
unless: :not_a_customer
end
And a form for creating support cases:
= simple_form_for #support_case, html: { class: 'form inset' } do |f|
.row
.col.sm-6
.row{ id: 'order-row' }
.col.sm-6
= f.input :order_number, input_html: { class: 'icon-field hash-icon' }
.col.sm-6
.label-title{ title: t("simple_form.labels.support_case.hint") }
= f.input :not_a_customer, as: :boolean do
= f.check_box :not_a_customer, {}, "true", "false"
.col.sm-6
= f.input :email, input_html: { type: 'email', required: 'true' }
= f.input :first_name, input_html: { type: 'text' }
= f.input :last_name, input_html: { type: 'text' }
.col.sm-12
~ f.input :message, as: 'text', input_html: { required: 'true' }
%button.btn.btn-action
= t('views.contact.form.submit')
Check the value of not_a_customer. You are just getting a string instead of a boolean value, which is always truthy ("true", "false" are both truthy value).
In Rails, you can do not_a_customer.to_bool to convert it into boolean.
The checkbox does not convert your value into boolean, because params is parsed as if they are all strings (including int, string, boolean values).

rails email validation only if present

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

how to skip model validation for particular function in rails?

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

Generate reset password token don't save on model

Hello I trying to create a reset password for my rails app; but when I try to save I get the following error:
Validation failed: Password can't be blank, Password is too short
(minimum is 6 characters), Password confirmation can't be blank
This is my user model.
class User < ActiveRecord::Base
attr_accessible :email, :password, :password_confirmation
has_secure_password
before_save { |user| user.email = email.downcase }
before_save :create_remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, uniqueness: { case_sensitive: false }
validates :password, presence: true, length: { minimum: 6 }
validates :password_confirmation, presence: true
def send_password_reset
self.password_reset_token = SecureRandom.urlsafe_base64
self.password_reset_at = Time.zone.now
self.password = self.password
self.password_confirmation = self.password
save!
end
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
the method "send_password_reset" doesn't update the user and I don't understand why is trying to save the user instead on updating just password_reset_token and the password_reset_at.
Does anybody can help me, please?
When you call save! on the model instance, it's going to run the validations on your User model; all of them.
There are a number of ways to skip the password validations conditionally. One is to use a Proc
validates :password, presence: true, length: { minimum: 6 }, unless: Proc.new { |a| !a.new_record? && a.password.blank? }
This will allow the User instance to be saved and will skip the validation of the :password field if it's blank and the User is not new (already persisted to the database).
Here is most of a password validation I use in my applications
validates :password, confirmation: true,
length: {:within => 6..40},
format: {:with => /^(?=.*\d)(?=.*([a-z]|[A-Z]))([\x20-\x7E]){6,40}$/},
Notice, you don't need the separate validation on :password_confirmation. Instead just pass confirmation: true to the :password validator.
Suggested Reading:
http://guides.rubyonrails.org/active_record_validations_callbacks.html#confirmation

Resources