Как правильно отобразить ошибку проверки, если мой формат даты неверен в Rails?
Я использую Rails 4.2.7. Я хотел бы выдать ошибку проверки, если пользователь не вводит свое поле даты рождения в правильном формате, поэтому у меня есть
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)
и у меня есть это на мой взгляд
<%= 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 %>
Однако, даже если кто-то вводит дату, например "01-01/1985", вышеприведенное не возвращает ошибку проверки представлению. Что мне нужно сделать, чтобы получить правильную ошибку проверки?
Редактировать: в одном из ответов, я пытался
@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
И даже несмотря на то, что я вижу вызываемую ветвь "спасения", я не обращаюсь к своему блоку "render 'edit".
5 ответов
Призвание update_attributes
очищает ошибки, которые вы установили в rescue
, Вы должны проверить на наличие ошибок, а если их нет, то продолжить, примерно так:
@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'
С вами redirect_to ... and return
Вы можете закрыть условное выражение и, если вы сделаете это так далеко, просто отобразить страницу редактирования.
Вы также можете добавить простую проверку вашей пользовательской модели:
validates :dob, presence: true
Это всегда будет неудачным, если dob не может быть установлен по какой-то другой, непредвиденной причине.
Чтобы получить введенную пользователем строку для заполнения поля при повторной загрузке, вы можете добавить средство доступа к пользовательской модели для: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
Затем измените форму, чтобы установить: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 %>
И обновите контроллер, чтобы установить 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
Запуск исключения ничего не добавляет к errors
список. Если вы просто хотите немного подправить этот код, вы сможете позвонить errors.add
внутри rescue
блок. Что-то вроде @user.errors.add(:dob, 'some message here')
,
Имейте в виду, что это будет проверять только дату рождения при использовании этого метода контроллера. Если вы хотите проверять дату рождения при каждом сохранении пользователя, вам нужно явно добавить проверку в модель. Вы можете написать свой собственный класс или метод проверки, а также есть некоторые гемы, которые добавляют проверку даты.
Я бы добавил правило проверки в модель. Подобно:
validates_format_of :my_date, with: /\A\d{2}\/\d{2}\/\d{4}\z/, message: 'Invalid format'
Попробуйте добавить правило проверки в модель.
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
и в вашем контроллере обновите свой код
...
@user.update_attributes(user_params)
if @user.save
....
Я думаю, что это тот случай, когда активная модель сияет. Мне нравится использовать его для реализации объектов формы без дополнительных зависимостей. Я не знаю точных деталей вашей ситуации, но ниже я вставил небольшую демонстрацию, которую вы сможете адаптировать к вашему делу.
Самым большим преимуществом является то, что вы не загрязняете свои контроллеры или модели методами поддержки обновлений профиля. Они могут быть извлечены в отдельную модель, которая упрощает вещи.
Шаг 1: Магазин dob
в users
Ваш users
таблица должна иметь столбец dob
типа date
, Например:
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name, null: false
t.date :dob, null: false
end
end
end
Не добавляйте в свою модель ничего необычного:
class User < ActiveRecord::Base
end
Шаг 2: Добавить Profile
Поместите следующее в app/models/profile.rb
, Смотрите комментарии для объяснений.
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
Шаг 3: Используйте форму в контроллере
использование Profile
в 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
Шаг 4: визуализируйте форму с form_for
В app/views/profiles/edit.html.erb
использование form_for
для отображения формы:
<%= form_for(@form) do |f| %>
<%= f.label :dob_string, 'Date of birth:' %>
<%= f.text_field :dob_string %>
<%= f.submit 'Update' %>
<% end %>
Шаг 5: Добавьте маршрутизацию
Имейте в виду, чтобы добавить маршрутизацию к config/routes.rb
:
Rails.application.routes.draw do
resources :profiles
end
Это оно!