I have a set of custom fields attached to a devise model called Entrant.
I have two forms, one for registration form (three fields) and one which sits in the account area (12 fields). Most of the custom fields area required but only within the form the sits in the account area.
How do I achieve this?
I am using rails 4.2 and ruby 2.1
You can simply specify validations on actions, that is:
validates :name, presence: true, on: :create # which won't validate presence of name on update action
If you ask where to put your custom fields, then generate devise's views and update corresponding ones with these fields.
There are several ways! You could do conditional validations, for instance
class Entrant < ActiveRecord::Base
validate :foo, if: :account_area?
def account_area?
!new_record? # Assumes that Entrant that has already been saved
# is in the account area
end
end
However, it sounds like your needs are advanced enough that you should consider making a Form Object
A form object is an object that accepts parameters, performs validations on that data, then saves a model instance.
class AccountForm
include ActiveModel::Model
include Virtus # Provides AR like attribute functionality and mass assignment
def initialize(entrant)
#entrant = entrant
end
attribute :foo, String
validates :foo, presence: true # This is only used on the account page, so no need to mess with conditional logic
def save
if valid?
persist!
true
else
false
end
end
def persist!
#entrant.update_attributes(foo: self.foo)
end
end
This is just a great example of how non-rails-specific object oriented programming can make your life easier and your app more maintainable. Make a class like above, stick it in app/forms and restart your server. Then in your controller, you'll just pass it the model
class EntrantController < ApplicationController
def update
#form = Form.new(Entrant.find(params[:id]))
#form.attributes = params[:entrant]
if #form.save
redirect_to some_path
else
render "edit"
end
end
end
By default devise only asks for a combination of email/password, you can add other fields by adding a sanitizer (see there -> Devise how to add a addtional field to the create User form?).
If you want to add other fileds to validate, you should create a secondary Entrant controller and add a specific callback to your model.
Typically:
after_update :validate_entrant_form, if: :property_changed?
I hope this will help you.
validates :name, presence: true, if: :condition_holds?
def condition_holds?
# some code here that evaluates to a boolean
end
Maybe this way help you.
Add attribute in devise model : say attr_accessor :validate_certain. In your controller action, devise model instance say #user have to update like this #user.validate_certain = true. and change your appropriate validation conditions in devise model
validates :name, presence: true, if: :validate_certain_changed?
def validate_certain_changed?
validate_certain.present?
end
When I have to do something like this I like to think of it as it validates if something in in the field but you can also take a nil value
Entrant.validates_presence_of(:foo, :allow_nil => true)
I also have this concern when using devise on customer with forms on separate pages updating different set of customer fields
I believe most of the solution works but I was looking for the simplest, easiest and foolproof way to implement the solution
Thus came this.
validates :phone, :country, :postal_code, :street_address, presence: true, allow_nil: true
The allow_nil: true instruct the model to validate the fields ONLY if it exists on the submitted form. If you want more protection, you can use extra para like :on => :update
Related
I not using ActiveRecords rather using ActiveModel to validate form data.
I am stuck into some point where i needed to validate a form field depending on a radio button value.
My model is
class Payment
include ActiveModel::Model
attr_accessor :method_id, :crad_name
validates_presence_of :card_name, :if => :method_type?
private
def method_type?
self.method_id == 1
end
end
Here, method_id = 1 for credit card and method_id = 2 for bank
That does not validate the form field and does not show any error either.
I have searched in google and got some valuable stuff for here Rails - How to validate a field only if a another field has a certain value?
But it does not work in this case. Thanks in advance for your suggestion and help
You're almost there. I'd like to say first though that using Method as a model name isn't a great idea, as it's generally considered a reserved word. Moving on.
class Payment
attr_accessor :method_id, crad_name
validates_presence_of :card_name, :unless => :method_id.nil?
end
Try this
class Payment
include ActiveModel::Model
attr_accessor :method_id, :crad_name
validates_presence_of :card_name, :if => lambda { |pay| pay.method_id == 1 }
end
EDIT
Try this or refer Active Record Validations
class Payment
include ActiveModel::Model
attr_accessor :method_id, :crad_name
validates :card_name, presence: true, if: :method_type?
private
def method_type?
method_id == 1
end
end
This should work for sure or god help me!
I have a Rails 3.2.18 app where I'm trying to do some conditional validation on a model.
In the call model there are two fields :location_id (which is an association to a list of pre-defined locations) and :location_other (which is a text field where someone could type in a string or in this case an address).
What I want to be able to do is use validations when creating a call to where either the :location_id or :location_other is validated to be present.
I've read through the Rails validations guide and am a little confused. Was hoping someone could shed some light on how to do this easily with a conditional.
I believe this is what you're looking for:
class Call < ActiveRecord::Base
validate :location_id_or_other
def location_id_or_other
if location_id.blank? && location_other.blank?
errors.add(:location_other, 'needs to be present if location_id is not present')
end
end
end
location_id_or_other is a custom validation method that checks if location_id and location_other are blank. If they both are, then it adds a validation error. If the presence of location_id and location_other is an exclusive or, i.e. only one of the two can be present, not either, and not both, then you can make the following change to the if block in the method.
if location_id.blank? == location_other.blank?
errors.add(:location_other, "must be present if location_id isn't, but can't be present if location_id is")
end
Alternate Solution
class Call < ActiveRecord::Base
validates :location_id, presence: true, unless: :location_other
validates :location_other, presence: true, unless: :location_id
end
This solution (only) works if the presence of location_id and location_other is an exclusive or.
Check out the Rails Validation Guide for more information.
I have a user object, he can update his profile which includes name, user_name, password (blank), password_confirmation (blank), email, email_confirmation (blank), bio and picture url.
My model states that all of the (blank) MUST be filled in. but if your admin and your just going to the users page to update the user's role - You as the admin should not have to fill in user data you obviously don't know.
So how does one get around this? should I instead create a list of users with a drop down beside them? is this not, essentially , a giant form? If so - how would this get created?
essentially: What's the best way to deal with this situation?
This is currently how users get updated
def update
#user = User.friendly.find(params[:id])
#user.update_attributes(user_update_params)
if #user.save
render :show
else
render :edit
end
end
private
def user_update_params
params.require(:user).permit(:name, :user_name, :email, :email_confirmation, :password,
:password_confirmation, :bio, :picture_url, :role)
end
The real problem seems to be that you have a logical error in your User model validations.
You seem to have a validation of the form,
validates :password, presence: true, confirmation: true
which is enforced EVERY TIME, i.e. a new password has to be selected every single time a user object is saved. But this is likely not what you want. You likely want this validation to only be enforced when the user is created for the first time, i.e. when it is a new record.
You can do this with,
validates :password, presence: true, confirmation: true, if: :new_record?
update_attribute
Updates the attribute without doing validations, you need this one.
check out this api doc
EDIT:
Speaking about reading documentation
Here is an abstract from the method documentation
update_attribute(name, value) public
Updates a single attribute and saves the record. This is especially
useful for boolean flags on existing records. Also note that
Validation is skipped.
Callbacks are invoked.
updated_at/updated_on column is updated if that column is available.
Updates all the attributes that are dirty in this object.
EDIT:
If you still need to validate with this method, note that it says that callbacks are invoked, so what you can do is write your own code to validate input and use callbacks as described here.
I am creating a Tumblr alternative to learn how use Rails. I am at the authentication part, and I decided to do it from scratch. I want to allow users to log in using either their username or their email. The user logs in via the Sessions controller but I need to verify if the login is either a valid username or a valid email. So I need to validate data in the Sessions controller using the User model.
I found this answer on SO: How do I validate a non-model form in Rails 3? but it will force me to duplicate the validations. Is that the only way to do it, or is there another way that is cleaner?
The best option I can imagine is creating a module and then including it at your User model and at the object you're going to use for the form:
module AuthenticationValidation
def self.included( base )
base.validates :username, :presence => true
base.validates :email, :presence => true
# add your other validations here
end
end
And then include this module at your models:
class User < ActiveRecord::Base
include AuthenticationValidation
end
class LoginForm
include ActiveModel::Validations
include ActiveModel::Conversion
include AuthenticationValidation
attr_accessor :username, :email
end
And then you have avoided repeating the validation itself.
I have a simple User class with the following validation of name uniqueness:
class User < ActiveRecord::Base
validates :name, :uniqueness => true,
It works great when a new user is created. However, when I check the login form, the user enters his name, and the system says it's already taken which doesn't make any sense.
So I implemented a separate valid_login? method, however I can't turn that unqueness check there:
def valid_login?
validates :name, :uniqueness => false # doesn't work
end
This is my controller's code:
def login
return unless request.post?
#user = User.new(params[:user])
if #user.valid_login?
# Redirect to user's page
end
end
I'm using my own authentication system which is quite simple: I store user's ID + password's hash in the cookies.
How can I turn of certain validation when I don't need it?
I solved this problem with the :if/:unless parameters.