ユーザー編集ページには、次のような行があります。
<%= devise_error_messages! %>
問題は、これがアプリの他の部分が行う標準的な方法でエラーを出力しないことです:
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
私の質問は、flash.eachを使用する他のデバイスと同じように機能するためのdeviseエラーメッセージを取得するにはどうすればよいですか?
ありがとう。
私は自分でこれを理解しようとしています。この問題がGithubに記録されていることがわかりました https://github.com/plataformatec/devise/issues/issue/504/#comment_574788
ホセは、devise_error_messsages!
メソッドは単なるstub(実装が含まれていますが)であり、オーバーライド/置換することになっていると言っています。これがwikiのどこかで指摘されていれば良かったので、推測している私たちのような人が何人かいると思います。
そこで、モジュールを再度開き、メソッドを再定義して、デフォルトの実装を効果的にオーバーライドしてみます。どうなるかお知らせします。
うん、うまくいく。 app/helpers/devise_helper.rb
を作成し、次のようにオーバーライドしました。
module DeviseHelper
def devise_error_messages!
'KABOOM!'
end
end
これを知っているので、エラーメッセージを希望どおりに表示するようにメソッドを変更できます。
元の問題を解決するために:元の devise_helper.rb
on Github です。エラーメッセージがどのように走査されるかを見てみましょう。
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
それはあなたが始めるのに役立つはずです。 :)
resource
オブジェクトは、実際にはdeviseが使用しているモデルです(図を参照)。
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
次のコード内に配置します(ここでは、いくつかのbootstrap 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 %>
任意の形式で配置できます。 deviseリソースを渡す代わりに、次のようにフォームから変数を渡すことができます。
<%= form_for @post do |f| %>
<%= render 'layouts/error_messages', object: f.object %>
<%= f.text_field :content %>
<%= f.submit %>
<% end %>
この質問が投稿されてからしばらく経ちましたが、見つけたものについてコメントしたいだけです。すでに答えた二人は私に多大な助けをしてくれたので、貢献したかっただけです。
Devise全体で、render_with_scope
を使用した呼び出しがあることがわかります。これはdeviseによって定義されたメソッドであり、基本的に現在のスコープをレンダリングされた次のビューに適用すると信じています。
なぜこれが関連するのですか? Deviseには、resource.errors
(not@resource.errors
)内にエラーが含まれています。いわば、箱から出して使用する場合は、デバイスは正常に機能します。
ユーザー管理動作の変更を開始すると、これらのエラーの問題が発生します。 Deviseに以前はなかった場所にredirect_to
またはrender
(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]
(配列として)に追加します。各メッセージは一度に1行ずつ印刷されます。時間がある場合は、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ファイルからファイルを継承させることもできます。登録コントローラーは次のようになります。
class Users::RegistrationsController < Devise::RegistrationsController
[2013年8月7日編集] 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 %>
そして...属性ごとに1つのエラー(最初にキャッチされるエラー)を表示するためのちょっとしたトリック:
<% 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
ここでは大したことではありません。ビューで記述したコードを再利用して、エラーペイ属性を1つだけ表示しました。
私はそれらの「固有の」エラーを数えています。また、複数形を使用してH2 HTMLタイトルを作成し、エラーリストの前に配置しています。
だから今、私は「devise_error_messages!」を使用することができますデフォルトとして、それは私が以前にすでにレンダリングしていたものを正確にレンダリングします。
ビューで特定のエラーメッセージにアクセスする場合は、「resource.errors [:attribute] .first」などを直接使用することをお勧めします。
瀬谷、クルガー。
Rails 3でDeviseを使用していますが、フラッシュコードは私が持っているものとほとんど同じです。私のアプリでは、コードは期待どおりに機能します。つまり、deviseエラーメッセージは、残りのフラッシュメッセージとともに出力されます。
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<% end %>
この正確なコードを試して、違いがあるかどうかを確認してください-異なるID属性が役立つ場合があります。
私はこれを思いつき、今のところうまくいっています。これにより、フラッシュにデバイスメッセージが追加されるため、通常どおり使用できます。私が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 -->
特定のタイプの複数のフラッシュ(:alert、:noticeなど)を表示し、gemの動作を変更しようとして時間を無駄にしたくない場合、これがDeviseで使用したソリューションです。フラッシュメッセージを使用するすべての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(または任意の場所)でこれを使用してフラッシュメッセージを表示します。
<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>
3番目に行うことは、コントローラーにフラッシュメッセージを追加するときはいつでも、これを実行することです。
flash_message(:success, "The user XYZ has been created successfully.")
DeviseHelperを作成します。
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! %>
私はこれを行うだけで、私のために働いた: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) %>
それがあなたを助けることを願っています;)
確かに少しハックですが、このヘルパー(app/helpers/devise_helper.rb)を使用してフラッシュを取得し、設定されている場合はフラッシュを使用してからresource.errors
にデフォルト設定します。これは、devise libにあるヘルパーに基づいています。
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
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(" ") %>
uインラインエラーメッセージを表示するすべての行の下の角かっこ内のフィールド名を持つ各フィールドに配置します。
上記のEric Huの回答に、すべてのIfステートメントが使用されている場所に追加するだけで、代わりにこのようなことをしてください。
# 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 %>
最初のエラーのみを表示して、コントローラーからデバイスエラーを表示します。
flash[:error] = @resource.errors.full_messages.first
このチートを使って、他の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
私は彼らがそれを書く最もきれいな方法になると確信していますが、それは完全に目覚めています
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