Рельсы - Разработка - Обработка - devise_error_messages
на моей странице редактирования пользователя есть следующая строка:
<%= devise_error_messages! %>
Проблема заключается в том, что это не выводит ошибки стандартным способом, который выполняет остальная часть приложения:
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
Мой вопрос в том, как заставить сообщение об ошибке разработки работать как другие, которые используют flash.each?
Спасибо.
Ответы
Ответ 1
Я пытаюсь понять это сам. Я только что нашел эту проблему в журнале Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788
Хосе говорит, что метод devise_error_messsages!
- это просто заглушка (хотя и содержит реализацию), и мы должны переопределить его/заменить. Было бы неплохо, если бы это было указано где-то в вики, поэтому я думаю, что есть несколько таких людей, как мы, которые догадывались.
Итак, я собираюсь попробовать снова открыть модуль и переопределить этот метод, эффективно переопределяя реализацию по умолчанию. Я дам вам знать, как это происходит.
Update
Да, это работает. Я создал app/helpers/devise_helper.rb
и переделал его так:
module DeviseHelper
def devise_error_messages!
'KABOOM!'
end
end
Поэтому, зная это, я могу изменить метод отображения сообщений об ошибках так, как я хочу.
Чтобы помочь вам решить вашу оригинальную проблему: здесь оригинал devise_helper.rb
в Github. Посмотрите, как проходят сообщения об ошибках:
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>
Ответ 2
Ниже решения работают с последними разработками на данный момент (4.1.1) и Rails 4.2.6. Но так просто, что я не вижу причины, почему он не будет работать через 10 лет;)
Если вы хотите переработать свои сообщения об ошибках и заставить их выглядеть одинаково в своем приложении, я бы рекомендовал что-то вроде этого (так, как я узнал у Майкла Хартла):
Создать частичное для сообщений об ошибках: layouts/_error_messages.html.erb
Вставьте следующий код (здесь я использую несколько классов загрузки):
<% 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 %>
Ответ 3
Я знаю, что прошло некоторое время, так как этот вопрос был опубликован, но я просто хотел прокомментировать то, что нашел. Два человека, которые уже ответили, оказали мне огромную помощь, и я просто хотел внести свой вклад.
Во всем приложении Devise вы увидите, что есть вызовы с помощью render_with_scope
. Я считаю, что это метод, определенный при разработке, и в основном применяет текущую область к следующему визуализированному представлению.
Почему это актуально? В Devise содержатся ваши ошибки в resource.errors
( не @resource.errors
). Devise отлично работает, если вы хотите использовать его из коробки, так сказать.
Проблемы с этими ошибками возникают, если вы начнете изменять поведение пользователя. Добавив redirect_to
или render
(вместо render_with_scope
), в котором у Devise ранее не было одного, вы в основном отбрасываете сообщения об ошибках. Это делает 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 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 обрабатывает сообщения об ошибках, чтобы сделать это во всем моем приложении, так как кажется, что гораздо чище иметь одну систему сообщений об ошибках вместо двух.
Ответ 4
Я просто хочу принести сюда новый кусочек:
Итак, я нашел более простой способ получить результат, который хотел получить "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 ошибки, потому что часто первый из них является единственным релевантным (например, когда пользователь забывает одно обязательное поле).
Я подсчитываю эти "уникальные" ошибки, и я делаю HTML-заголовок H2, используя pluralize и помещая его перед списком ошибок.
Итак, теперь я могу использовать "devise_error_messages!" как и по умолчанию, и делает именно то, что я уже показывал раньше.
Если вы хотите получить доступ к определенному сообщению об ошибке в своем представлении, теперь я рекомендую использовать непосредственно "resource.errors [: attribute].first" или что-то еще.
Сея,
Kulgar.
Ответ 5
Я решил это аналогично YoyoS, создав app/helpers/devise_helper.rb
и разместив его в нем:
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
Работали!
Ответ 6
Я использую Devise in Rails 3, и ваш flash-код в значительной степени идентичен тому, что у меня есть. В моем приложении код работает так, как ожидалось; Т.е. сообщения об ошибках проекта выводятся вместе с остальными моими флэш-сообщениями:
<% flash.each do |name, msg| %>
<%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<% end %>
Попробуйте этот точный код и посмотрите, не имеет значения - может помочь другой атрибут ID.
Ответ 7
Я подошел к этому, и он работает до сих пор.
Это добавляет готовые сообщения к вспышке, поэтому ее можно использовать как обычно. Пожалуйста, учтите, что я новичок в 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
Edit:
Извините, что я работал охранником, и появилось какое-то нежелательное поведение. Поскольку 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 -->
Ответ 8
Если вы хотите отображать более одной вспышки данного типа (: alert,: notice и т.д.) и не тратьте время на то, чтобы изменить поведение драгоценного камня, это решение, которое я использовал с Разрабатывают. Я уверен, что он может быть использован с любым камнем, который использует флэш-сообщения.
Прежде всего, в вашем приложении 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>
Третье, что нужно сделать, когда вы хотите добавить флэш-сообщение на любом контроллере, сделайте следующее:
flash_message(:success, "The user XYZ has been created successfully.")
Ответ 9
Я просто делаю это, работал у меня: в приложении/помощниках/, я создаю файл 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
во всех файлах просмотра я change
<%= 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) %>
надеюсь, что это вам поможет;)
Ответ 10
Допустимо, немного взломано, но я использую этот помощник (app/helpers/devise_helper.rb), чтобы захватить вспышки и использовать те, которые установлены, а затем по умолчанию - resource.errors
. Это просто основано на помощнике, который в разработке 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
Ответ 11
Очень простой способ отображения сообщения об ошибке для каждого поля
<%= resource.errors.messages[:email].join(" ") %>
поместить для каждого поля с именем поля в квадратной скобке ниже каждой строки, где u хочет отображать встроенное сообщение об ошибке.
Ответ 12
Чтобы показать свою ошибку разработки с вашего контроллера, вы увидите только первую ошибку.
flash[:error] = @resource.errors.full_messages.first
Ответ 13
Если вы хотите скомпоновать 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
Ответ 14
Просто добавьте к Эрику Ху ответ выше, где используются все операторы 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 %>
Ответ 15
- Удалите "devise_error_messages!" из шаблона "app/views/users/passwords/new".
- Создайте пользовательский контроллер для своего пользователя (приложение/контроллеры/users/passwords_controller.rb), а в после фильтрации добавьте ошибки в flash-массив:
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
Ответ 16
Мне нравится делать это так же, как это делалось в другом контроллере 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 %>
Ответ 17
Я только что создал app/helpers/devise_helper.rb
как Джон, но перепробовал такой метод:
module DeviseHelper
def devise_error_messages!
flash[:error] = resource.errors.full_messages.join('<br />')
return ''
end
end
С этим мне не нужно ничего изменять.
Это плохая идея? Я новичок в рельсах, не стесняйтесь меня поправлять. Спасибо.
Ответ 18
Я только что объявил devise_error_messages! как пустой помощник.
И вручную извлекал и обрабатывал ошибки в общем _errors, частичном для моего приложения. Казалось, что это самое простое решение, и мне не нужно проходить все файлы разработки и удалять вызов обработчику ошибок.