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!
Related
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
Let's say that I have an input field with a value, and I want to validate it (on the server side) to make sure, for instance, that the field has at least 5 characters.
The problem is that it is not something that I want to save in the database, or build a model. I just want to check that the value validates.
In PHP with Laravel, validation is quite easy:
$validator = Validator::make($data, [
'email' => ['required', 'email'],
'message' => ['required']]);
if ($validator->fails()) { // Handle it... }
Is there anything similar in Rails, without need of ActiveRecord, or ActiveModel? Not every data sent from a form makes sense as a Model.
You can use ActiveModel::Validations like this
class MyClass
include ActiveModel::Validations
validates :email, presence: true
validates :message, presence: true
end
It will act as a normal model and you will be able to do my_object.valid? and my_object.errors.
Rails validations live in ActiveModel so doing it without ActiveModel seems kind of counter-productive. Now, if you can loosen that requirement a bit, it is definitely possible.
What I read you asking for, and as I read the PHP code doing, is a validator-object that can be configured on the fly.
We can for example build a validator class dynamically and use instance of that class to run our validations. I have opted for an API that looks similar to the PHP one here:
class DataValidator
def self.make(data, validations)
Class.new do
include ActiveModel::Validations
attr_reader(*validations.keys)
validations.each do |attribute, attribute_validations|
validates attribute, attribute_validations
end
def self.model_name
ActiveModel::Name.new(self, nil, "DataValidator::Validator")
end
def initialize(data)
data.each do |key, value|
self.instance_variable_set("##{key.to_sym}", value)
end
end
end.new(data)
end
end
Using DataValidator.make we can now build instances of classes with the specific validations that we need. For example in a controller:
validator = DataValidator.make(
params,
{
:email => {:presence => true},
:name => {:presence => true}
}
)
if validator.valid?
# Success
else
# Error
end
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.
model: User
has_one :beta_invite
before_save :beta_code_must_exist
def beta_code_must_exist
if beta_invite_id == beta_invite.find_by_name(beta_invite.id)
user
else
nil
end
end
model: BetaInvite
has_many :users
What I`m trying to do is check for the existence of a beta invite in DB, before allowing the user to be saved.
Since the User will be passing in the BetaInvite name into the field, I would like to check if it matches any existing Codes in the DB.
Hope I didn`t mix things up too much.
Would appreciate any help with this problem.
Add a text field to the form for :beta_code
Add an attr_accessor for that field: attr_accessor :beta_code
Then add the following line to the model (Assumes you only want to do this check on user creation):
validate :beta_code_must_exist, :on => :create
Change beta_code_must_exist to add an error to the form. Also be sure to properly cast :beta_code into the correct type.
Warning untested code below
def beta_code_must_exist
#invite = BetaInvite.find_by_name(beta_code)
if #invite.empty?
errors.add(:beta_code, "is not a valid invite code")
else
beta_invite_id = #invite.id
end
end
Use :inclusion with the :in option. You can supply :in with any enumerable:
validates :beta_invite, :inclusion => { :in => BetaInvite.all,
:message => "%{value} is not a valid beta invite code" }
Source: Rails Active Record Validation
I need to validate a value's presence, but only AFTER the value is populated. When a User is created, it is not required to set a shortcut_url. However, once the user decides to pick a shorcut_url, they cannot remove it, it must be unique, it must exist.
If I use validates_presence_of, since the shortcut_url is not defined, the User isn't created. If I use :allowblank => true, Users can then have "" as a shortcut_url, which doesn't follow the logic of the site.
Any help would be greatly appreciated.
Here we are always making sure the shortcut_url is unique, but we only make sure it is present if the attribute shortcut_selected is set (or if it was set and now was changed)
class Account
validates_uniqueness_of :shortcut_url
with_options :if => lambda { |o| !o.new_record? or o.shortcut_changed? } do |on_required|
on_required.validates_presence_of :shortcut_url
end
end
You'll need to test to make sure this works well with new records.
Try the :allow_nil option instead of :allow_blank. That'll prevent empty strings from validating.
Edit: Is an empty string being assigned to the shortcut_url when the user is being created, then? Maybe try:
class User < ActiveRecord::Base
validates_presence_of :shortcut_url, :allow_nil => true
def shortcut_url=(value)
super(value.presence)
end
end
try conditional validations, something like:
validates_presence_of :shortcut_url, :if => :shortcut_url_already_exists?
validates_uniqueness_of :shortcut_url, :if => :shortcut_url_already_exists?
def shortcut_url_already_exists?
#shortcut_url_already_exists ||= User.find(self.id).shortcut_url.present?
end