I'm trying to make a validation in a model that only is enforced if the model is called from a specific controller.
In my controller I have:
#created_by_user = true
#message.save
In my model I have
validates :subject, length: {in: 0..78, if: #created_by_user}
However it seems that even if I save this model from a different script or controller the validation is still checked. How do I get the results I want?
From the controller where you dont need validation, just call
#message.save(:validate => false)
Related
I have a model like this:
class Profile < ApplicationRecord
validates :username, presence: true, on: :data_setup
end
where :data_setup is a page.
After installing the client side validation gem, it won't work, unless I erase the context part on: :data_setup
Is there any way to make it work?
Your expectations for this are completely wrong. Models are not aware of the request, controller or anything else really outside the the model unless you explicitly pass it in or its a global.
For validations on: is most commonly used to restrict the validation to the create or update contexts. Note that this has nothing to do with what "page" you are on - the context is just tied to if the model instance is a new record or not.
When using custom contexts you need to manually trigger it by passing the context to valid?, invalid? or save:
Profile.new(username: nil).valid? # true
Profile.new(username: nil).valid?(:data_setup) # false
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
I have two separate forms for a profile picture and the rest of the profile information. Both forms, however, correspond to the profile model. For several of the profile attributes, I have validations like:
validates :title, presence: true
validates :zip_code, presence: true
The problem is that the validations are checked when someone tried to upload an image, which I don't want. That being said, I also have an image validator, so I don't want to avoid validation completely, just certain ones. I was thinking of trying to access the params hash in the model, but I can't figure out how and I'm pretty certain its a bad idea anyway. How can I make the right validation conditions? I already tried this:
validates :title, presence: true, :unless => :picture_exists?
def picture_exists?
if self.pic
puts 'yo pic exist'
return true
else
puts 'yo no pic'
return false
end
end
but it does not work because it checks whether or not the profile has a picture, not whether the params have a picture. So if someone had already saved a picture, they would be able to bypass the validations which I don't want. I want the validations to be bypassed when they are not using the picture submit form.
You can approach the issue in several ways:
1.- Skip all validations in your controller action (and validate manually, I guess)
save(validate: false) (source)
2.- Use a condition that you set manually before saving like this.
3.- Use a custom validation that stops all other validations from triggering if passes.
Maybe you can come up with more.
PS: Why would you expect your user to bypass the other validations before setting the profile picture?
GL & HF
In controller action I have two parameters: params[:name] and params[:email]. I would like check them. if they not null and haven't some wrong symbols. Why I asking - because I am not sure can I use validation in controller and I don't know how check param for some symbols...use regular function?...Here is my try:
Controller:
validates :name, :presence => true
validates :email, :presence => true
def check
name = params[:name].valid?
email = params[:email].valid?
end
The validation should occur in the model. Remember the controller should only translate HTTP requests into your application actions.
When you are creating an object you are doing it at the Model layer, so the validation should be at this layer, the model.
I'm trying to update single attribute of a user model from a admin controller (not users controller).
While doing this I tried update_attribute() but it was changing the users password also.
I think the password is changing because I have before_save method on user model which hashes the password.
update_attributes() is not working because it is checking the validations for password which is presence=>true
Is there any way to achieve this?
You can set a condition on your validations by using the :if option. In my code, it looks something like this:
validates :password,
:length => { :minimum => 8 },
:confirmation => true,
:presence => true,
:if => :password_required?
def password_required?
crypted_password.blank? || password.present?
end
So basically, it's only if the crypted_password in the database is not set (meaning a new record is being created) or if a new password is being provided that the validations are run.
Try update_column(name, value), it might work.
You can update single attribute of user like this
#user is that user whose attribute you want to update
e.g user_name
#user.update_attributes(:user_name => "federe")
Try it and it will only update one attribute..
ActiveRecord has an 'update-column' method that skips both validations and callbacks:
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column
However, I'd suggest that could be dangerous - you have that :before_save filter for a reason. If you place an :except method on the filter to circumvent in specific cases, it not only becomes reusable but you keep behaviour consistent and avoid having a method buried in a controller that's bypassing your Model's validation/callback stack.
I'm personally not overly keen on seeing methods like update_column anywhere except as protected methods inside Models.
Try :
To bypass callback and validations use :
User.update_all({:field_name => value},{:id => 1})
Just wanted to let you know :
In Rails, update_attribute method bypasses model validations, while update_attributes and update_attributes! will fail (return false or raise an exception, respectively) if a record you are trying to save is not valid.
The difference between two is update_attribute use save(false) where as update_attributes uses save or you can say save(true) .