2016-12-26 211 views
6

我正在使用Rails 4.2.7。我想拋出一個驗證錯誤,如果用戶沒有以正確的格式輸入自己的出生場的日期,所以我有如果我的日期格式在Rails中不正確,我該如何正確顯示驗證錯誤?

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 

即使我可以看到「救市」分支叫,我不是針對我的「渲染‘編輯’」塊。

回答

3

調用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 [email protected]? && @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 
+0

謝謝。這確實將我引導到正確的頁面,但顯示日期的文本字段(以我的問題中的「<%= f.text_field:dob」開頭的行)不包含用戶輸入的原始不正確文本。 – Dave

+0

@Dave - 在'rescue'塊中添加'@user.dob = params [:user] [:dob]'可能會有幫助。這將爲「@ user」模型分配值。 :) – 31piy

+0

可悲的是,「@ user.dob = params [:user] [:dob]」「不會執行任何操作,儘管」params [:user] [:dob]「中有數據,」我可以在調試中看到,在將它分配給「@ user.dob」之後,查詢「@ user.dob」不會顯示任何數據。我在想這是否與我的基礎PostGres列有類型日期有關。 – Dave

3

我會在模型中添加一個驗證規則。像:

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

同意在模型中添加驗證規則。當OP似乎想要使用斜線時,此特定規則使用連字符作爲分隔符。如果月份和日期字段通常不被視爲有效日期,那麼它也將允許某些數字,如果這對OP的用例很重要。 – Max

+1

如果某人輸入「99/88/0010」,這是否會驗證日期?如果是這樣,那是不正確的,因爲我列出的(「99/88/0010」)不是有效的日期。 – Dave

4

觸發一個異常不添加任何東西到errors列表。如果您只是稍微調整此代碼,則應該可以在rescue塊內調用errors.add。像@user.errors.add(:dob, 'some message here')

請記住,這隻會驗證使用此控制器方法時的出生日期。如果您想要在用戶保存時驗證出生日期,則需要明確將驗證添加到模型中。您可以編寫自己的custom validation class or method,並且還有一些添加日期驗證的寶石。

+0

我嘗試了yoru的建議(請參閱我的編輯),但即使我看到在我的控制器中調用的「rescue」分支,執行不會下降到我返回到原始視圖的部分,而是將「配置更新成功」就好像所有數據都輸入正常。 – Dave

+0

編輯中顯示的代碼的問題在於,調用'update_attributes'只會檢查在模型中顯式定義的驗證,而'begin' /'rescue'塊與此無關。如果你沒有更新除dob之外的任何其他字段,你可以檢查@ user.errors是否有任何內容,然後用save來代替'update_attributes'。我傾向於在模型中添加驗證,然後使用'update_attributes'。不幸的是,在驗證運行的時候,Rails已經將提交的字符串解析成日期。 – Max

+0

我不明白這裏提供的解決方案是什麼。你能編輯你的答案,包括我可以剪切和粘貼的代碼嗎? – Dave

3

嘗試增加模型中的驗證規則。

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 
.... 
+0

這有幾個問題 - 其中一個將驗證日期事件不是真正的日期,如「2/29/2017」。 – Dave

+0

我已經更改了代碼,請看看。這可能會解決您的問題。 –

+0

很酷。這會確認正確和錯誤的日期,但是當我返回到我的視圖時,文本字段(我的問題中的一個「f.text_field:dob」)不包含任何內容。理想情況下,它應該包含用戶輸入的錯誤值,以便用戶可以更正它。 – Dave

2

我覺得這是在活動模型閃耀的情況下。我喜歡用它來實現沒有額外依賴的表單對象。我不知道你的情況的具體細節,但下面我粘貼了一個小的演示,你應該能夠適應你的情況。

最大的好處是,你不會污染你的控制器或模型與方法支持配置文件更新。他們可以被提取到一個單獨的模型,簡化了事情。

第1步:商店dobusers

users表應該有date類型的列dob。例如:

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步意見:使用形式在控制器

使用ProfileProfilesController

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 

這就是它!