I have 2 forms.
Form 1 I have 10 fields which I am validating.
Form 2 but it only contains 2 fields.
The model is same.
What I need to do is:
To validate fields when they are submitted by forms. If I am not posting any fields it should not validate in model. If I post 5 fields it should validate 5 fields. If I post 2 fields it should validate only 2 not all of them.
So form 1 all 10 should be validated, form 2 only 2 should validate not rest of 8.
Here is my code:
validates :teacher_number, :title, :name, :gender, :location, :dob,
:contact_mobile, :contact_home, :street, :city, :state, :zip_code, :country,
presence: true
validates :teacher_number, uniqueness: {scope: :school_id}
validate :teacher_number_existance, :on => :create
validate :school_existance, :on => :create
Below is my attempt which successfully works fine but its bulk of code that somewhat a bad practice.
validates :teacher_number, presence: true, if: "teacher_number && teacher_number.blank?"
validates :title, presence: true, if: "title && title.blank?"
validates :name, presence: true, if: "name && name.blank?"
validates :gender, presence: true, if: "gender && gender.blank?"
validates :location, presence: true, if: "location && location.blank?"
validates :dob, presence: true, if: "dob && dob.blank?"
validates :contact_mobile, presence: true, if: "contact_mobile && contact_mobile.blank?"
validates :contact_home, presence: true, if: "contact_home && contact_home.blank?"
validates :street, presence: true, if: "street && street.blank?"
validates :city, presence: true, if: "city && city.blank?"
validates :state, presence: true, if: "state && state.blank?"
validates :zip_code, presence: true, if: "zip_code && zip_code.blank?"
validates :country, presence: true, if: "country && country.blank?"
validates :teacher_number, uniqueness: {scope: :school_id}, if: "teacher_number && teacher_number.blank?"
validate :teacher_number_existance, :on => :create, if: "self.teacher_number && self.teacher_number.blank?"
validate :school_existance, :on => :create, if: "self.teacher_number && self.teacher_number.blank?"
EDIT
UPDATED MY QUESTION.
I see two ways for this:
Some hidden param in form and attr_accesor in model to turn off validation.
Use save(validate: false) for save from that second form.
Next, you can do it like this
if validate_object?
validates :email, presence: true
validates :variant, presence: true
end
You can use some patterns like form object.
But you have to remember that this object will be invalid in future too.
If you want different validations of data in different circumstances, you should not be validating on the model. You should validate elsewhere: either in the view using HTML form validation, or in the controller using Rails' Strong Params.
I think you should use HTML form validation to manage this, because you're worried about the record missing attributes. Strong Params is more useful in case you are worried about people supplying forbidden values for record attributes.
Here is how you would use HTML form validation to manage this (example using HAML):
= form_for #model do |f|
= f.text_input(:teacher_number, required: true)
...all your other inputs...
= f.submit 'Submit Form'
Here is how you would use Strong Params to constrain the number of things you can get:
class ModelsController < ApplicationController
def form_action_1
Model.create(form_1_params)
end
def form_action_2
Model.create(form_2_params)
end
private
def form_1_params
# let's permit all the things you want for the first form
params.require(:model).permit(:teacher_number, :title, ...)
end
def form_2_params
# let's permit only the few things you want in the second form
params.require(:model).permit(:only, :a, :few, :things)
end
end
I'm not sure exactly what you're asking, but perhaps this approach would work. Write your validations like this:
validates :teacher_number,
:title,
:name,
:gender,
:location,
:dob,
:contact_mobile,
:contact_home,
:street,
:city,
:state,
:zip_code,
:country,
presence: true,
on: :form2
validates :teacher_number, uniqueness: {scope: :school_id}
validate :teacher_number_existance, :on => :create
validate :school_existance, :on => :create
The on: :form2 near the bottom of the first validator means the validations will only run if you explicitly ask them to run.
So in your controller action for saving form2, you would have to do this:
if valid?(:form2) && #model.save
The other validators will run when you save, as normal. Using the on: parameter of validates for your own symbols (as opposed to the built-in ones) is covered in the Rails Guide for validations, but it's easy to miss. I didn't notice it myself until recently. I hope this helps.
Finally, after so going back and forth below solution worked well for me.
before_validation :strip_validations
def strip_validations
['teacher_number', 'title', 'name', 'gender', 'location', 'dob', 'contact_mobile', 'contact_home', 'street', 'city', 'state', 'zip_code', 'country'].each do |attr|
errors.add("Teacher", {attr => " #{attr} can't be blank"}) if send(attr.to_sym) && send(attr.to_sym).blank?
end
end
Related
Is it possible to validate a field for presence after the initial creation?
I want to make phone number mandatory if the user wants to update their account after signing up.
validates :phone, presence: true, if: .....
if I use on: :update I can no longer authenticate until the field is filled
There are many ways to accomplish this task assuming it is a normal Rails model backed by a DB table. Off the top of my head you can do:
validates :phone,
presence: true,
if: Proc.new{ |model| model.id.present? }
Or more to the point and doesn't fail if you assign an ID before saving:
validates :phone,
presence: true,
if: Proc.new{ |model| model.persisted? }
Hi I have a spree model that has the following validations:
with_options presence: true do
validates :firstname, :lastname, :address1, :city, :country
validates :zipcode, if: :require_zipcode?
validates :phone, if: :require_phone?
end
I would like to remove the city and/or country from presence validation. In my address_decorator i wrote this
Spree::Address.class_eval do
with_options presence: true do
validates :firstname, :lastname, :address1
validates :zipcode, if: :require_zipcode?
validates :phone, if: :require_phone?
end
......
But this didnt remove city or country. Both are still demanded in order to create new record.
What am i missing? Please help.
When you add "with_options" you are not removing the previous validations, you are just adding more.
So, there is to remove the validations for :city and :country
Not checked myself, but I´ve seen something similar to:
.class_eval do
_validators.reject{ |key, _| key == :field }
_validate_callbacks.reject do |callback|
callback.raw_filter.attributes == [:field]
end
where :field is :city and :country
I have an issue with a model. I have a model that is updated through 2 forms (as 2 people need to enter separate data). Form 1 contains the first half of the required data and therefor only that data needs to be validated there.
I am having trouble finding a way to validate only the data entered in form 1. Below you'll find my subscription.rb model file.
class Subscription < ActiveRecord::Base
# werkgever form
if form_id == 'form1'
validates :email, presence: true
end
# werknemer form
if form_id == 'form2'
validates :name, presence: true
validates :city presence: true
end
end
I need the if statements to contain something that would make it so that only the values beloging to that form are validated so that i dont get errors on form2 when updating and vice versa.
I hope this is clear enough. Any help is appreciated.
Thanks.
You could set validations with condition:
attr_accessor :form_type
validates :email, presence: true, :if => :werkgever_form?
def werkgever_form?
form_type == 'werkgever'
end
:form_type is a virtual attribute, which is not saved in the database and needed only for validations. You can set this attribute as a hidden field in each form:
<%= form.hidden_field :form_type, 'werkgever' %>
attr_accessor :form_type
validates :email, presence: true, if: :check_if_form_one
validates :name, presence: true, unless: :check_if_form_one
validates :city presence: true, unless: :check_if_form_one
def check_if_form_one
/* Add your condition here
example: form_type == 'form1' */
end
You can set form_type from controller method or view page.
I have User model, it has some validations and they work on create. But when i call any user from database as #user=User.find(1) #user.valid? it returns false. Could you help me?
class User < ActiveRecord::Base
validates :name, :surname, :username, :phone, :role, :gender, :presence => true
validates :password_confirmation, :email_confirmation, :presence => true
validates :username, :email, :uniqueness => true
validates :verified, :bulletin, :inclusion => { :in => [true, false] }
validates :password,:email, :confirmation => true
....
end
I guess you need to add on: :create param for each validations that only need to be run on create.
For example when you're doing #user.valid? I gess you don't want to check if password_confirmation is present.
So in this case it should be:
validates :password_confirmation, :email_confirmation, :presence => true, :on => :create
Hope it helps :)
There is a special validation for this use case, that the user should provide a confirmation, but the confirmation is not stored in the database
validates :email, confirmation: true, :uniqueness => true
validates :password, confirmation: true, ....
This substitutes the validation for :password_confirmation and :email_confirmation, so you need also to remove them.
See the fine rails guides http://guides.rubyonrails.org/active_record_validations.html#confirmation
There is an AcviteRecord Model named User like this:
class User < ActiveRecord::Base
validates :name, :presence => true
validates :email, :presence => true, :uniqueness => true
validates :plain_password, :presence => true, :confirmation => true
validates :plain_password_confirmation, :presence => true
#...other codes
end
It requires that the update of name and email and the update of password are separated.
When only update name and password, using update or update_attributes will cause password validation which is not needed. But using update_attribute will save name and email without validation.
Are there any ways to update particular fields of model with validation without causing the other fields' validation?
Give it a try, might help
class User < ActiveRecord::Base
validates :name, presence: true
validates :email, presence: true, :uniqueness => true
validates :plain_password, length: { in: 4..255, allow_nil: true }, confirmation: true
validates :plain_password_confirmation, presence: true, if: -> (user){ user.plain_password.present? }
# ......
# ......
end
Apart from this you should reconsider about saving plain_password ;)
You can adjust your validations to only run on create. Requiring confirmation ensures changes on edit are applied.
validates :plain_password,
confirmation: true,
presence: {
on: :create },
length: {
minimum: 8,
allow_blank: true }
validates :plain_password_confirmation,
presence: {
on: :create }
I am assuming you are hashing your passwords, so this would accompany code similar to:
attr_accessor :plain_password
before_save :prepare_password
def encrypted_password( bcrypt_computational_cost = Rails.env.test? ? 1 : 10)
BCrypt::Password.create plain_password, cost: bcrypt_computational_cost
end
private #===========================================================================================================
# Sets this users password hash to the encrypted password, if the password is not blank.
def prepare_password
self.password_hash = encrypted_password if plain_password.present?
end
A better way to handle this is to not include the fields in the rest of the edit form, but rather provide a link to "Change my password". This link would direct to a new form (perhaps in a modal window) which will require the new password, confirmation of the new password, and the old password, to prevent account hijacking.
In your case you can use has_secure_password The password presence is only validated on creation.