How to correctly display a validation error if the date format is incorrect in Rails?

Im using Rails 4.2.7. I would like to throw a validation error if the user does not enter the date of birth of the field in the appropriate format, so I

def update @user = current_user begin @user.dob = Date.strptime(params[:user][:dob], '%m/%d/%Y') rescue ArgumentError => ex end if @user.update_attributes(user_params) 

and I have it in my opinion

  <%= f.text_field :dob, :value => (f.object.dob.strftime('%m/%d/%Y') if f.object.dob), :size => "20", :class => 'textField', placeholder: 'MM/DD/YYYY' %> <% if @user.errors[:dob] %><%= @user.errors[:dob] %><% end %> 

However, even if someone enters a date like "01-01 / 1985", the above does not return a validation error in the view. What do I need to do to get the correct validation error return correct?

Edit: According to one answer, I tried

 @user = current_user begin @user.dob = Date.strptime(params[:user][:dob], '%m/%d/%Y') rescue ArgumentError => ex puts "Setting error." @user.errors.add(:dob, 'The birth date is not in the right format.') end if @user.update_attributes(user_params) last_page_visited = session[:last_page_visited] if !last_page_visited.nil? session.delete(:last_page_visited) else flash[:success] = "Profile updated" end redirect_to !last_page_visited.nil? ? last_page_visited : url_for(:controller => 'races', :action => 'index') and return else render 'edit' end 

And although I see that the called "salvation" branch is called, I am not heading to the "render" edit block.

+6
source share
5 answers

Calling update_attributes fixes the errors you set in rescue . You should check for errors, and if not, continue, something like this:

 @user = current_user begin @user.dob = Date.strptime(params[:user][:dob], '%m/%d/%Y') rescue ArgumentError => ex puts "Setting error." @user.errors.add(:dob, 'The birth date is not in the right format.') end if !@user.errors.any ? && @user.update_attributes(user_params) last_page_visited = session[:last_page_visited] if !last_page_visited.nil? session.delete(:last_page_visited) else flash[:success] = "Profile updated" end redirect_to !last_page_visited.nil? ? last_page_visited : url_for(:controller => 'races', :action => 'index') and return end render 'edit' 

Since you are redirect_to ... and return , you can close the conditional expression and, if you do so, just render the edit page.

You can also add a simple check to your user model:

 validates :dob, presence: true 

This will always fail if the dob cannot be set for some other unforeseen reason.

To enter a user-entered string to fill in the field when reloading, you can add an accessor to the user model for: dob_string

 attr_accessor :dob_string def dob_string dob.to_s @dob_string || dob.strftime('%m/%d/%Y') end def dob_string=(dob_s) @dob_string = dob_s date = Date.strptime(dob_s, '%m/%d/%Y') self.dob = date rescue ArgumentError puts "DOB format error" errors.add(:dob, 'The birth date is not in the correct format') end 

Then change the form to set: dob_string

 <%= form_for @user do |f| %> <%= f.text_field :dob_string, :value => f.object.dob_string , :size => "20", :class => 'textField', placeholder: 'MM/DD/YYYY' %> <% if @user.errors[:dob] %><%= @user.errors[:dob] %><% end %> <%= f.submit %> <% end %> 

And update the controller to set dob_string:

 def update @user = User.first begin #@user.dob = Date.strptime(params[:user][:dob], '%m/%d/%Y') @user.dob_string = user_params[:dob_string] end if ! @user.errors.any? && @user.update_attributes(user_params) redirect_to url_for(:controller => 'users', :action => 'show') and return end render 'edit' end def user_params params.require(:user).permit(:name, :dob_string) end 
+3
source

Throwing an exception does not add anything to the errors list. If you just want to change this code a bit, you can call errors.add inside the rescue block. Something like @user.errors.add(:dob, 'some message here') .

Keep in mind that using this controller method will only confirm the date of birth. If you want to confirm the date of birth when the user is saved, you will need to explicitly add confirmation to the model. You can write your own custom class or validation method , and there are also some gems that add date validation.

+4
source

I would add a validation rule in the model. How:

 validates_format_of :my_date, with: /\A\d{2}\/\d{2}\/\d{4}\z/, message: 'Invalid format' 
+3
source

Try adding a validation rule to the model.

  validate :validate_date def validate_date begin self.dob = Date.parse(self.dob) rescue errors.add(:dob, 'Date does not exists. Please insert valid date') end end 

and in your controller update your code

 ... @user.update_attributes(user_params) if @user.save .... 
+3
source

I think this is the case when the active model is active. I like to use it to implement form objects without additional dependencies. I do not know the exact details of your situation, but below I have inserted a small demo version that you could adapt to your business.

The biggest advantage is that you do not pollute your controllers or models with support for profile updates . They can be extracted into a separate model that simplifies things.

Step 1: Store dob in users

Your users table should have a dob column of type date . For instance:

 class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name, null: false t.date :dob, null: false end end end 

Do not put anything in your model:

 class User < ActiveRecord::Base end 

Step 2: Add Profile

Put the following in app/models/profile.rb . See Comments for an explanation:

 class Profile # This is an ActiveModel model. include ActiveModel::Model # Define accessors for fields you want to use in your HTML form. attr_accessor :dob_string # Use the validatiors API to define the validators you want. validates :dob_string, presence: true validate :dob_format # We store the format in a constant to keep the code DRY. DOB_FORMAT = '%m/%d/%Y' # We store the user this form pertains to and initialize the DOB string # to the one based on the DOB of the user. def initialize(user) # We *require* the user to be persisted to the database. fail unless user.persisted? @user = user @dob_string = user.dob.strftime(DOB_FORMAT) end # This method triggers validations and updates the user if validations are # good. def update(params) # First, update the model fields based on the params. @dob_string = params[:dob_string] # Second, trigger validations and quit if they fail. return nil if invalid? # Third, update the model if validations are good. @user.update!(dob: dob) end # #id and #persisted? are required to make form_for submit the form to # #update instead of #create. def id @user.id end def persisted? true end private # Parse dob_string and store the result in @dob. def dob @dob ||= Date.strptime(dob_string, DOB_FORMAT) end # This is our custom validator that calls the method above to parse dob_string # provided via the params to #update. def dob_format dob rescue ArgumentError errors[:dob] << "is not a valid date of the form mm/dd/yyyy" end end 

Step 3: Use the form in the controller

Use Profile in ProfilesController :

 class ProfilesController < ApplicationController def edit # Ensure @profile is set. profile end def update # Update the profile with data sent via params[:profile]. unless profile.update(params[:profile]) # If the update isn't successful display the edit form again. render 'edit' return end # If the update is successful redirect anywhere you want (I chose the # profile form for demonstration purposes). redirect_to edit_profile_path(profile) end private def profile @profile ||= Profile.new(user) end def user @user ||= User.find(params[:id]) end end 

Step 4: form_for form using form_for

In app/views/profiles/edit.html.erb use form_for to display the form:

 <%= form_for(@form) do |f| %> <%= f.label :dob_string, 'Date of birth:' %> <%= f.text_field :dob_string %> <%= f.submit 'Update' %> <% end %> 

Step 5: Add Routing

Keep in mind to add routing to config/routes.rb :

 Rails.application.routes.draw do resources :profiles end 

What is it!

+2
source

Source: https://habr.com/ru/post/1013526/


All Articles