[英]rails - Devise - Handling - devise_error_messages
在我的用戶編輯頁面中,有一行如下:
<%= devise_error_messages! %>
問題是這不會以應用程序其余部分的標准方式輸出錯誤:
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
我的問題是,如何讓設計錯誤消息像使用 flash.each 的其他人一樣工作?
謝謝。
我正在嘗試自己解決這個問題。 我剛剛發現這個問題登錄在 Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788
何塞說的是devise_error_messsages!
方法只是一個存根(盡管它包含實現),我們應該覆蓋/替換它。 如果在維基的某個地方指出這一點會很好,這就是為什么我猜有一些像我們這樣的人一直在猜測。
所以我將嘗試重新打開模塊並重新定義方法,有效地覆蓋默認實現。 我會讓你知道它是怎么回事。
是的,這有效。 我創建了app/helpers/devise_helper.rb
並像這樣覆蓋它:
module DeviseHelper
def devise_error_messages!
'KABOOM!'
end
end
所以知道了這一點,我可以修改方法以按照我想要的方式顯示錯誤消息。
幫助您解決最初的問題:這是Github上的原始devise_helper.rb
。 看一下錯誤消息是如何被遍歷的:
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
這應該可以幫助您入門。 :)
resource
對象實際上是設計正在使用的模型(見圖)。
resource.class #=> User
resource.errors.class #=> ActiveModel::Error
它似乎也被定義在更高的范圍內(可能來自控制器),因此可以在各種地方訪問它。
在您的助手中的任何位置
module DeviseHelper
def devise_error_messages1!
resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
end
def devise_error_messages2!
resource.errors.full_messages.map { |msg| content_tag(:p, msg) }.join
end
end
你的看法
<div><%= resource.errors.inspect %></div>
以下解決方案適用於目前的最新設計 (4.1.1) 和 Rails 4.2.6。 但是太簡單了,我不明白為什么它在 10 年后不起作用;)
如果你想回收你的錯誤消息並讓它們在你的應用程序中看起來相同,我會推薦這樣的東西(我從 Michael Hartl tut 那里學到的方式):
為錯誤消息創建部分: layouts/_error_messages.html.erb
放入以下代碼(這里我使用了一些引導程序 3 類):
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<p><strong>This form contains <%= pluralize(object.errors.count, 'error') %>.</strong></p>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
現在你有了可回收的東西,你可以全面使用它。 代替標准設計:
<%= devise_error_messages! %>
像這樣以您的形式調用它:
<%= render 'layouts/error_messages', object: resource %>
你可以把它放在任何形式。 您可以像這樣從表單中傳遞變量,而不是傳遞設計資源:
<%= form_for @post do |f| %>
<%= render 'layouts/error_messages', object: f.object %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
我知道這個問題發布已經有一段時間了,但我只是想評論我的發現。 已經回答的兩個人對我有很大的幫助,我只是想做出貢獻。
您將在整個設計中看到使用render_with_scope
調用。 我相信這是一種由 devise 定義的方法,基本上將當前范圍應用於渲染的下一個視圖。
為什么這是相關的? 設計在resource.errors
(不是@resource.errors
)中包含您的錯誤。 如果你想開箱即用,設計工作正常,可以這么說。
如果您開始更改用戶管理行為,就會出現這些錯誤的問題。 通過在 Devise 之前沒有的地方添加redirect_to
或render
(而不是render_with_scope
),您基本上是在render_with_scope
錯誤消息。 在我看來,這使得 Devise 對修改不友好。
我的解決方案是這樣的
# In application.html.erb
<% flash.each do |name, msg| %>
# New code (allow for flash elements to be arrays)
<% if msg.class == Array %>
<% msg.each do |message| %>
<%= content_tag :div, message, :id => "flash_#{name}" %>
<% end %>
<% else %>
# old code
<%= content_tag :div, msg, :id => "flash_#{name}" %>
<% end %> #don't forget the extra end
<% end %>
和
# Wherever you want Devise's error messages to be handled like
# your other error messages
# (in my case, registrations_controller.rb, a custom controller)
flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages
后一個代碼塊將 Devise 的錯誤消息作為一個數組,並將其附加到flash[:notice]
(作為一個數組)。 每條消息將一次打印一行。 如果我有時間,我想我將改變 Devise 處理錯誤消息的方式,以便在我的整個應用程序中執行此操作,因為擁有一個錯誤消息系統而不是兩個錯誤消息系統似乎要干凈得多。
我通過創建一個app/helpers/devise_helper.rb
並將其放入其中來解決這個問題,類似於 YoyoS:
module DeviseHelper
# Hacky way to translate devise error messages into devise flash error messages
def devise_error_messages!
if resource.errors.full_messages.any?
flash.now[:error] = resource.errors.full_messages.join(' & ')
end
return ''
end
end
工作了!
我只想在這里帶來一個新的小作品:
所以我找到了一種更簡單的方法來獲得“AnApprentice”想要的結果。
首先,如果您想自定義 Devise 插件中的任何內容,我強烈建議您將代碼從“\\Ruby_repertory\\lib\\ruby\\gems\\1.9.1\\gems\\devise-version\\app\\controllers |helpers|mailers...”添加到您的項目中所需的文件中。
[編輯] 或者你可以讓你的文件從“普通”設計文件繼承......就像......說......你只想覆蓋devise/registrations_controller.rb中的一個函數,你的用戶自定義的第一行注冊控制器將是:
class Users::RegistrationsController < Devise::RegistrationsController
[Edit August 7th 2013] 現在 Devise 甚至提供了一個生成控制器的工具: https : //github.com/plataformatec/devise/wiki/Tool :-Generate-and-customize-controllers
所以......無論如何......我設法得到了“AnApprentice”想要的東西(為了更清晰的解決方案,請參閱以下大編輯):
#/my_project/app/helpers/devise_helper.rb
module DeviseHelper
def devise_error_messages!
return "" if resource.errors.empty?
return resource.errors
end
end
而且,在我看來,接下來的幾行工作得很好:
<% devise_error_messages!.each do |key, value| %>
<div class="flash <%= key %>"><%= key %> <%= value %></div>
<% end %>
嗯...然后您可以訪問特定屬性的錯誤,如下所示:
#Imagine you want only the first error to show up for the login attribute:
<%= devise_error_messages![:login].first %>
而且...一個小技巧,讓每個屬性只顯示一個錯誤(第一個被捕獲的錯誤):
<% if resource.errors.any? %>
<% saved_key = "" %>
<% devise_error_messages!.each do |key, value| %>
<% if key != saved_key %>
<div class="flash <%= key %>"><%= key %> <%= value %></div>
<% end %>
<% saved_key = key %>
<% end %>
<% end %>
我知道這個問題發布已經有一段時間了,但我認為它會幫助很多設計用戶:)。
大編輯:
由於我喜歡擴展我的代碼,使其更簡潔並與他人分享,我最近想更改 devise_error_messages! 方法以便在我的視圖中使用它並使其顯示我上面解釋的技巧。
所以,這是我的方法:
def devise_error_messages!
html = ""
return html if resource.errors.empty?
errors_number = 0
html << "<ul class=\"#{resource_name}_errors_list\">"
saved_key = ""
resource.errors.each do |key, value|
if key != saved_key
html << "<li class=\"#{key} error\"> This #{key} #{value} </li>"
errors_number += 1
end
saved_key = key
end
unsolved_errors = pluralize(errors_number, "unsolved error")
html = "<h2 class=\"#{resource_name}_errors_title\"> You have #{unsolved_errors} </h2>" + html
html << "</ul>"
return html.html_safe
end
這里沒什么大不了的,我重用了我在視圖中編寫的代碼來僅顯示一個錯誤 pey 屬性,因為通常第一個是唯一相關的(例如當用戶忘記一個必填字段時)。
我正在計算那些“獨特的”錯誤,我正在使用復數形式制作 H2 HTML 標題並將其放在錯誤列表之前。
所以現在,我可以使用“devise_error_messages!” 作為默認值,它完全呈現我之前已經呈現的內容。
如果您想訪問視圖中的特定錯誤消息,我現在建議直接使用“resource.errors[:attribute].first”或其他任何內容。
塞亞,庫爾加。
我在 Rails 3 中使用 Devise,您的 Flash 代碼與我所擁有的幾乎相同。 在我的應用程序中,代碼按預期工作; 即設計錯誤消息與我的其余 flash 消息一起輸出:
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<% end %>
試試這個確切的代碼,看看它是否有任何不同 - 不同的 ID 屬性可能會有所幫助。
我想到了這個,到目前為止它正在工作。 這將向 flash 添加設計消息,因此它可以照常使用。 請考慮我是 Ruby 和 Rails 的新手...
class ApplicationController < ActionController::Base
after_filter :set_devise_flash_messages, :if => :devise_controller?
...
private:
def set_devise_flash_messages
if resource.errors.any?
flash[:error] = flash[:error].to_a.concat resource.errors.full_messages
flash[:error].uniq!
end
end
end
編輯:
抱歉,我正在守衛,並且出現了一些不需要的行為。 由於after_filter
是在渲染之后調用的,所以它不能按預期工作。 如果有人知道如何在操作之后但在渲染之前調用方法......
但是你可以使用類似的東西:
module ApplicationHelper
# merge the devise messages with the normal flash messages
def devise_flash
if controller.devise_controller? && resource.errors.any?
flash.now[:error] = flash[:error].to_a.concat resource.errors.full_messages
flash.now[:error].uniq!
end
end
end
在views/shared/_messages.html.erb
<% devise_flash %>
<!-- then display your flash messages as before -->
如果您希望能夠顯示多個給定類型的 flash(:alert、:notice 等...)並且不想浪費時間嘗試修改 gem 行為,這就是我與 Devise 一起使用的解決方案。 我很確定它可以與任何使用 flash 消息的 gem 一起使用。
首先要做的是,在您的 application_controller.rb 中,添加以下內容:
# Adds the posibility to have more than one flash of a given type
def flash_message(type, text)
flash[type] ||= []
flash[type] << text
end
第二件事,在 application.html.erb(或任何你想要的地方)中顯示你的 flash 消息:
<div class="flashes">
<% flash.each do |key, messages| %>
<% messages = Array(messages) unless messages.is_a?(Array) %>
<% messages.each do |message| %>
<div class="alert alert-<%= key %>">
<%= message %>
</div>
<% end %>
<% end %>
</div>
要做的第三件事,無論何時您想在任何控制器中添加一條 flash 消息,請執行以下操作:
flash_message(:success, "The user XYZ has been created successfully.")
創建設計助手:
module DeviseHelper
def devise_error_messages!
return "" if resource.errors.empty?
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg)}.join
return flash.now[:alert] = messages.html_safe
end
end
在你看來,替代
<%= devise_error_messages! %>
到:
<% devise_error_messages! %>
如果您希望利用 devise_error_messages,那么您可以通過添加到 resource.errors 來實現
如果您要超越注冊控制器,它可能看起來像
def create
if validation_or_other_check_passes
super
else
build_resource
clean_up_passwords(resource)
resource.errors.add(:notice, "The check failed.")
render :new
顯示每個字段的錯誤消息的非常簡單的方法
<%= resource.errors.messages[:email].join(" ") %>
將字段名稱放在方括號中的每個字段放在您要顯示內聯錯誤消息的每一行下方。
誠然,有點hacky,但我正在使用這個助手(app/helpers/devise_helper.rb)來抓取閃光燈並使用那些如果設置然后默認為resource.errors
。 這只是基於設計庫中的幫助程序。
module DeviseHelper
def devise_error_messages!
flash_alerts = []
error_key = 'errors.messages.not_saved'
if !flash.empty?
flash_alerts.push(flash[:error]) if flash[:error]
flash_alerts.push(flash[:alert]) if flash[:alert]
flash_alerts.push(flash[:notice]) if flash[:notice]
error_key = 'devise.failure.invalid'
end
return "" if resource.errors.empty? && flash_alerts.empty?
errors = resource.errors.empty? ? flash_alerts : resource.errors.full_messages
messages = errors.map { |msg| content_tag(:li, msg) }.join
sentence = I18n.t(error_key, :count => errors.count,
:resource => resource.class.model_name.human.downcase)
html = <<-HTML
<div id="error_explanation">
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
html.html_safe
end
end
我只是這樣做,對我有用:在app/helpers/ 中,我創建了一個文件devise_helper.rb
module DeviseHelper
def devise_error_messages_for(resource)
return "" if resource.errors.empty?
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
sentence = I18n.t("errors.messages.not_saved",
count: resource.errors.count,
resource: resource.class.model_name.human.downcase)
html = <<-HTML
<div id="error_explanation">
<h2>#{sentence}</h2>
<ul>#{messages}</ul>
</div>
HTML
html.html_safe
end
end
在我更改的所有視圖文件中
<%= devise_error_messages! %>
為了:
<%= devise_error_messages_for(#your object in your formular)%>
對我來說,它在我的視圖中編輯和新用戶:
<%=form_for resource, as: @user, url: user_path(@user),...
<%= devise_error_messages_for(@user) %>
希望它會幫助你;)
DeviseHelper#devise_error_messages!
已棄用,將在下一個主要版本中刪除。
Devise 現在默認devise/shared/error_messages
下的部分來顯示錯誤消息,並使它們更易於定制。 更新您的視圖更改調用:
<%= devise_error_messages! %>
到:
<%= render "devise/shared/error_messages", resource: resource %>
很簡單,將以下代碼放在 views/devise/sessions/new.html.erb 中
<% if flash[:alert] %>
<div class='alert alert-danger'><%= flash[:alert] %></div>
<% end %>
就是這樣!
從您的控制器顯示您的設計錯誤,僅顯示第一個錯誤。
flash[:error] = @resource.errors.full_messages.first
只是在上面使用所有 If 語句的地方添加 Eric Hu 的答案,而不是執行類似的操作。
# Controller
flash.now[:error] = flash[:error].to_a.concat(resource.errors.full_messages)
# View
<% flash.each do |name, msg| %>
<% Array(msg).uniq.each do |message| %>
<%= message %>
<% end %>
<% end %>
class Users::PasswordsController < Devise::PasswordsController
after_filter :flash_errors
def flash_errors
unless resource.errors.empty?
flash[:error] = resource.errors.full_messages.join(", ")
end
end
end
我喜歡這樣做,就像在其他 Devise 控制器中使用此作弊所做的那樣。
<% if flash.count > 0 %>
<div id="error_explanation">
<h2>Errors prevented you from logging in</h2>
<ul>
<% flash.each do |name, msg| %>
<li>
<%= content_tag :div, msg, id: "flash_#{name}" %>
</li>
<% end %>
</ul>
</div>
<% end %>
為了使 materialisecss 將設計錯誤消息顯示為吐司,我在 app/helpers/devise_helper.rb 中添加了此代碼
module DeviseHelper
def devise_error_messages!
messages = resource.errors.full_messages.map { |msg|
String.new(" M.toast({html: '" + msg + "' }); ".html_safe )
}.join
messages = ("<script>" + messages + "</script>").html_safe
end
end
我相信他們會是最干凈的寫法,但它完美地工作
我剛剛創建了一個像 John 一樣的app/helpers/devise_helper.rb
但覆蓋了這樣的方法:
module DeviseHelper
def devise_error_messages!
flash[:error] = resource.errors.full_messages.join('<br />')
return ''
end
end
有了這個,我不必修改任何其他東西。 這是一個壞主意嗎? 我是 Rails 的新手,請不要猶豫糾正我。 謝謝。
我剛剛聲明了 devise_error_messages! 作為空幫手。 並在我的應用程序的一般 _errors 部分中手動獲取和處理錯誤。 似乎是最簡單的解決方案,我不必瀏覽所有設計文件並刪除對錯誤處理程序的調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.