I'm having some issues using rails validation on a form. What I'm doing is, in a form users are entering a URL for some of their favorite sites. When they submit, my create method uses nokogiri to open to URL and parse the header of the web page. The problem I'm running into is, if the user enters the form and it's blank, my create method tried to open nil, which causes is to error out. I tried to add validation to the method like so:
validates :url, :presence => true
If the user enters the form, this validation does not catch the empty text area, and fails as it tried to open the path before checking the validation. Is there a way in rails to specify I want to run the validation at the start of the create rather the end (which I'm assuming is happening)?
Why not call nokogiri in an after_validation or after_create callback? This would elegantly solve your problem.
Related
Question is as above. I have a record that I need to validate before deciding which form to show. The record is created invalid, and we check its validity to see if the form the user is on is the initial registration form or a subsequent form.
My issue is when I call record.valid? the record gets various error messages added to it which are then incorrectly displayed on the registration form. It's not possible for me to simply clear the errors after validating as I need the errors present if the user enters invalid data.
Is there any way to call valid? or an equivalent that does not add errors to the instance?
Thanks in advance
You want to validates with a steps system ? I think you can look at with_options block.
example :
with_options condition do
# your validations or anything...
# validates :attribute
end
documentation :
https://apidock.com/rails/Object/with_options
With good conditions you will avoid adding errors on validations already "validated" and focus on the new ones.
I hope I understood your request correctly.
After calling valid? you can clear errors from object ie.
record.errors.clear
In my Ruby on Rails application I am trying to add in validations that will ensure the user has entered a value in a text box. In my system I have a table called Account which stores users' email account information, when they go onto the views/accounts/_form.html.erb page to add a new email account I want to validate the presence of a port number. I can do this through the following code:
validates :port, presence: true
This successfully ensures that users enter their port number, but when a user signs up through the views/users/_new.html.erb page they have to enter only an email address (e.g example#example.com) and the users_controller will then create a record in the Account table for this email address. My problem is that on the views/accounts/_form.html.erb page the port number is required but on the views/users/_new.html.erb it is not.
Is there a way of validating that the user enters the port number if they are on the views/accounts/_form.html.erb page or invoking the create method in the accounts_controller?
I am aware that I could do this through the HTML required validation like so: <%= f.text_field :port, :required => true %> but I need to add in further validation as well as presence, so this is not suitable.
You can create an attr_accessor field that determines if the validation should occur...
class Account < ActiveRecord:Base
attr_accessor :port_needs_validation
validates :port, presence: true, if: -> {port_needs_validation}
Then just set the accessor in your create method...
def create
#account = Account.new
#account.assign_attributes(account_params)
#account.port_needs_validation = true
if #account.save
...
Extract that part of the logic into a form object, check out the legendary 2012 blog entry from CodeClimate. Things have changed since then, the author uses Virtus to build form objects, more popular & up-to-date gems these days are:
reform
dry-rb
active type
but really you can make anything behave like an ActiveModel object
if it's a one-off thing, just do what Steve said in the other answer but that is a sure way to hell, safe-hate and divorce (at least from personal experience) in any slightly teeny weeny bigger project (i.e. you mean to spend some hours more working on it, it's not like you just finished everything and want to go home).
Actually, just use form classes everywhere and avoid model validations & other callbacks at all. You don't want things sending account activation mails or validating your password complexity when you're writing tests and just need a "post" that belongs to "user".
My own favorite personal fuckup due to model callbacks is sending 240.000 "your account has been upgraded/downgraded" emails because of an innocent spelling change update in an account_type attribute migration just because account_type_changed? was true.
So.. Form classes for ever, model callbacks never.
I would not recommend you have model aware of views. In #SteveTurczyn 's solution, an abstract field is introduced into model to identified the which page it come from, which is an good solution.
As from Ruby on Rail MVC, both View and Model talk to the controller, another solution will be have controller handle validation of params before passing the value to create account.
I'm using state_machine for an online purchasing process in Ruby on Rails. One of the states consists of the user filling in a form with billing information. This form is required, so I'm validating it when transitioning to the next state like so:
state :confirm do
validates_presence_of :name, :email
end
Where the form is on state :info and the next one is :confirm.
This works fine: If any fields are missing state_machine will not transition to the next state.
However I can't find information on how to display an error notification when the validation returns false. I want to display a message when this validation fails, and redirects to the form state. Thanks in advance for your help!
(I assume you have solved this long ago, but...)
I think this answer has nothing to do with state_machine. This is the problem:
I want to display a message when this validation fails, and redirects to the form state.
If you redirect, the object is reloaded and all the unsaved attributes are lost, as are any validation errors.
Standard way to handle failed validation is to (re-)render the edit view, not redirect to the edit action. This retains the unsaved attributes and validation errors.
I am trying to create similar functionality as this gem authlogix-rpx, which optimistically saves the session/user object even if some of the validated fields are missing.
http://github.com/tardate/authlogic_rpx/tree/master/lib/authlogic_rpx (line 167)
With this gem it's possible to create the record that does not meet validation criteria and later on call the registration_complete? method which return false if all the validations do not pass.
I am not sure how this save is taking place, in my gem (which is an add on to authlogic using oauth2) I have tried doing save(false), save_with_vaidation_false but nothign really works, the validations fail and the record get saved.
Any ideas?
Thanks
You should be able to run user.save(false) to save the user and then use user.errors.full_messages to access the validation error messages.
Or you could provide the :on parameter to your validations to restrict them to :create, :update or both (:save)
validates_presence_of :email, :on=>:update
I need to run the built-in validations on the login field prior to actually creating the user record, is there a way to do this in Authlogic? The reason for is when a user types in a new login, AJAX is invoked to check and see that the login in unique, valid, etc. Once that is done, the user can enter his email to claim the login, it's a 2 step process.
The User model uses ActiveRecord validations, so this isn't specific to Authlogic. If you want to run the validations on a model you can call user.valid?. This will return true or false depending on if the entire model is valid. However it also fills up the user.errors object so you can then check if a given attribute is valid.
Here is some code that uses RJS to do the AJAX. But you can use anything and organize it however you want.
user = User.new(params[:user])
user.valid? # we aren't interested in the output of this.
error = user.errors.on(:login)
if error
page.insert_html :before, "user_login", content_tag(:span, error, :class => "error_message")
end
You may be interested in my Mastering Rails Forms screencast series where I cover this topic in the 2nd episode.