I'm trying to add validations to just a specific page.
right now I have a user put in their e-mail/pw/pw-confirmation when they sign up and after clicking submit it directs them to the users edit page.
I'm using the following line of code:
validates :first_name, :last_name, :date_of_birth, :goals, uniqueness: true, on: :edit
unfortunately it's not validating can someone help me explain why ?
The problem is you are trying to perform 'sexy validation' on multiple attributes at once. It won't work. try this instead:
validates_uniqueness_of :first_name, :last_name, :date_of_birth, :goals, on: :update
Previous answer is a bit misleading. Problem with your code wasn't the validation syntax. You can still use
validates :first_name, :last_name, :date_of_birth, :goals, uniqueness: true but instead of on: :edit you should have on: :update
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? }
I am using devise for user registrations, meaning, that by default new user is registered through registrations_controller. So by clicking button "Register" user is redirected to a new_user_registration path.
My registration form however has two steps. In first step (new_user_registration) I am asking for a name and password. In the second step (users_controller), when user is saved, I am asking for address. This I am doing with wizard gem:
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to user_steps_path
else
render :new
end
end
So, those a kind of partioal validations, but I cannnot validate depending in the step, as the first part of my form is handeled through registrations controller. The second part is however in the users_controller. It's getting complicated here and I would like to know, if I can validatede depending on the controller. Like:
validates :first_name, presence: true, if: -> { new_user_registration_path }
validates :last_name, presence: true, if: -> { new_user_registration_path }
validates :street, presence: true, if: -> { new_user_path }
I know, like this, it makes no sence, but maybe it helps to understand my thinking behind. Also, maybe I can work with smth. like:
validates :first_name, presence: true, if: -> { #user.save }
validates :last_name, presence: true, if: -> { #user.save }
validates :street, presence: true, if: -> { #user.update}
So basically, when creating a new user, I would validate if name and password is present. And when then adding address (it's an update action for user), I will check if address is present. Does anyone has experince with forms like this?
Another thought, maybe, I can skip registrations controller, redirecting directly to the user and creating two steps for partial validations? But as I am working with devise, I don't know, if I can just go throught users controller, skipping new_user_registration path. I did it, how it was advised on the wicked tutorial, but still ended up in the registrations controller:
def create
super
end
def update
super
end
Thanks!
The best solution to this type of problem is to use form objects. See this example and the gem Reform.
With form objects, each HTML form is processed via a form object. In your example you could have a "User Registration" form, and a "User update" form. The key point is that the validation is done by the form and not the model. That way the validation is relevant to the current form input, and you avoid the issues of classing validation rules.
It's as easy as that:
validates :first_name, presence: true, :on => :create
validates :last_name, presence: true, :on => :create
validates :street, presence: true, :on => :update
validates :house_number, presence: true, :on => :update
validates :city, presence: true, :on => :update
validates :zip_code, presence: true, :on => :update
Clearly "Sign-Up" creates a User. And the wizard_steps just update the user. So for this simple example this works perfectly and raises validation errors according to the controller action.
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
I'm a newbie in rails and I'm stuck with this problem: I have a model named User
class User < ActiveRecord::Base
attr_accessor :password
EMAIL_REGEX = /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i
validates :first_name, :presence => true,:format => /\A[a-zA-Z]+\z/
validates :last_name, :presence => true,:format => /\A[a-zA-Z]+\z/
validates :email, :presence => true, :uniqueness => true, :format => EMAIL_REGEX
validates :password, :presence => true
validates_length_of :password, :in => 6..20, :on => :create
end
with database attributes first_name, last_name, email, hashed_password and encrypted_password.
When I create new Object of User and saves it in the database there is no problem. NOW, here's the problem I want to edit attributes of my User Object EXCEPT email and password.
Once I try to edit the record through edit of rails resource it flags an error that password should not be empty. I am planning to have an exemption of validation if the user wants to edit his/her information but I know that it is not a good practice.
Hoping to find the best answer.
For starters check out http://guides.rubyonrails.org/active_record_validations.html#conditional-validation - once this approach becomes unDRY (repeated more then 2-3 times) see http://apidock.com/rails/Object/with_options
Once you get more advanced you will want to try something in the lines of a form/service class and extract form/action-specific validations there - http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
...and welcome to rails :)
Try using
validates :password, :presence => true, on: :create
And in the user edit form add every field except email and password.
But thing is that while you are going to change the password, there is no validation on password. So when you are implementing the change_password section, you need handle it and nee to add the errors manually for the password.
Problem Solved! Im not sure if this is the best solution. Once I instantiate a User object I use the after_initialize then set updatePassword to true as a default value then in the edit action of User Object I set updatePassword to false so that it will be exempted in the validation. I also use the conditional validation for the updatePassword. :D Thanks for all the ideas!
I am having a little problemo here. I have a model, view and controller. I go from the index.html.erb to the animals.html.erb. (Assume from my posted code this has already happened) On the animals view I would like to display some data represented by my Profile model.
Here is my code.
Profile Model
class Profile < ActiveRecord::Base
has_many :animals
validates :firstname, presence: true
validates :lastname, presence: true
validates :address, presence: true
validates :city, presence: true
validates :state, presence: true
validates :zip, presence: true
validates :gender,
presence: true,
length: {minimum: 1, maximum: 2 }
validates :breeder, presence: true
end
Animals Model
class Animal < ActiveRecord::Base
belongs_to :profile
validates :fullname, presence: true
validates :profileID, presence: true
validates :age,
presence: true,
length: {minimum: 1, maximum: 3 }
validates :gender,
presence: true,
length: {minimum: 1, maximum: 2 }
validates :purrfactor, presence: true
:weight
:height
:length
validates :fixed, presence: true
validates :shots, presence: true
validates :papers, presence: true
validates :created_at, presence: true
validates :updated_at, presence: true
end
Home Controller
class HomeController < ApplicationController
def index
end
def show
#profile = Profile.find(1)
end
end
Home/Show View
<div class="container-fluid">
<div class="row">
<p><%= #profile.firstname %></p>
</div>
</div>
SQL Generated by Find
Profile Load (0.2ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."id" = ? LIMIT 1 [["id", 1]]
I don't want anyone to solve my problem per say. What I have learned thus far about RoR, this should work. However, it does not bring back the firstname model value from my Sqlite3 db. Is the SQL generated by my find statement correct? Are my models messed up? Just looking for some advice to steer me in the right direction to fix this issue. Also, should I have the ID referenced in my models (Unique ID in my db table) Big thanks in advance!
Update
I would think that the home/show route would work. The link_to tag goes to the correct action and renders the show page without error.
Link To Tag
<%= link_to "Get Started!", {:controller => 'home', :action => 'show'}, { class: "btn btn-primary" } %>
Routes.rb
get "home/index"
get "home/show"
Rake Routes
home_index GET /home/index(.:format) home#index
home_show GET /home/show(.:format) home#show
root GET / home#index
Solution
I cleaned up my code a bit. Got rid of the unneeded Animals Controller, as well as, the routes. I updated my post, to show these revisions.
I found that the generated SQL was valid and returned an Active Record, however it was not being displayed on the View. After removing the attr_accessible attribute from the Profiles.rb model class the value displayed.
Why did the attr_accessible attribute block the data from displaying on the view? I thought this attribute was only for mass assignment security. I.E. updates, saves, etc...
You do not need :id in your models because they will be generated automatically. In my opinion, if the routes are correct and the Animals View rendered on home#show, then everything is probably fine in RoR and just Profile with :id 1 does not exist in your DB.