рельсы - разработка - обработка - devise_error_messages - PullRequest
122 голосов
/ 05 ноября 2010

на моей странице редактирования пользователя есть строка:

<%= devise_error_messages! %>

Проблема в том, что стандартные ошибки не выводятся ошибками, как в остальных приложениях:

<% flash.each do |key, value| %>
    <div class="flash <%= key %>"><%= value %></div>
<% end %>

Мой вопрос: как мне заставить сообщение об ошибке устройства работать так же, как и другие, использующие flash.each?

Спасибо.

Ответы [ 20 ]

135 голосов
/ 30 ноября 2010

Я пытаюсь понять это сам.Я только что обнаружил, что эта проблема зарегистрирована в 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

Поэтому, зная это, я могу изменить метод отображения сообщений об ошибках так, как я хочу.

Чтобы помочь вам решитьВаша оригинальная проблема: Вот оригинал devise_helper.rb на 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>
32 голосов
/ 20 декабря 2013

Ниже решение работает с последними разработками на данный момент (4.1.1) и Rails 4.2.6. Но это так просто, что я не вижу причины, почему это не сработало бы через 10 лет;)

Если вы хотите перерабатывать свои сообщения об ошибках, чтобы они выглядели одинаково в вашем приложении, я бы порекомендовал что-то вроде этого (как я узнал с Майклом Хартлом, тут):

Создать частичное для сообщений об ошибках: 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">&times;</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 %>
23 голосов
/ 06 апреля 2011

Я знаю, что прошло много времени с тех пор, как этот вопрос был опубликован, но я просто хотел прокомментировать то, что нашел.Два человека, которые уже ответили, оказали мне огромную помощь, и я просто хотел внести свой вклад.

В Devise вы увидите, что есть звонки с использованием render_with_scope.Я считаю, что это метод, определенный в devise, и в основном применяет текущую область видимости к следующему отображаемому представлению.

Почему это важно?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'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 обрабатывает сообщения об ошибках, чтобы сделать это во всем приложении, так как гораздо проще иметь одну систему сообщений об ошибках вместо двух.

11 голосов
/ 30 декабря 2013

Я решил это аналогично 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

Работал!

11 голосов
/ 05 июля 2011

Я просто хочу принести новый маленький кусочек сюда:

Итак, я нашел более простой способ получить результат, которого хотел «AnApprentice».

Прежде всего, если вы хотите что-то настроить в плагине Devise, я настоятельно советую вам скопировать код из "\ Ruby_repertory \ lib \ ruby ​​\ gems \ 1.9.1 \ gems \ devise-version \" app \ controllers | helpers | mailers ... "к файлу, который вы хотите в своем проекте.

[Edit] Или вы можете сделать так, чтобы ваш файл наследовал от «обычных» файлов devise ... Как ... скажем ... Вы хотите перезаписать только одну функцию в devise / registrations_controller.rb, первой строке Ваш пользовательский контроллер пользовательских регистраций будет:

class Users::RegistrationsController < Devise::RegistrationsController

[Редактировать 7 августа 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, используя множественное число, и помещаю его ДО списка ошибок.

Так что теперь я могу использовать "devise_error_messages!" по умолчанию, и он отображает именно то, что я уже делал раньше.

Если вы хотите получить доступ к конкретному сообщению об ошибке в своем представлении, я сейчас рекомендую использовать непосредственно «resource.errors [: attribute] .first» или что-то еще.

Сея, Kulgar.

6 голосов
/ 05 ноября 2010

Я использую Devise в Rails 3, и ваш флеш-код в значительной степени идентичен тому, что у меня есть.В моем приложении код работает как положено;т.е. сообщения об ошибках Devise выводятся вместе с остальными моими флэш-сообщениями:

<% flash.each do |name, msg| %>
  <%= content_tag :div, msg, :id => "flash_#{name}" if msg.is_a?(String) %>
<% end %>

Попробуйте этот точный код и посмотрите, имеет ли он какое-то значение - может помочь другой атрибут ID.

5 голосов
/ 14 апреля 2012

Я пришел к этому, и он работает до сих пор.Это добавляет сообщения об устройстве на флэш-память, поэтому его можно использовать как обычно.Пожалуйста, учтите, что я новичок в 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

In views/shared/_messages.html.erb

<% devise_flash %>
<!-- then display your flash messages as before -->
3 голосов
/ 24 мая 2013

Если вы хотите иметь возможность отображать более одной вспышки заданного типа (: alert,: alert и т. Д.) И не тратить свое время на попытки изменить поведение 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>

Третье, что нужно сделать, когда вы хотите добавить флеш-сообщение в любой контроллер, сделайте следующее:

flash_message(:success, "The user XYZ has been created successfully.")
2 голосов
/ 15 октября 2018

Создать 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! %>
2 голосов
/ 13 февраля 2017

Я просто делаю это, работал для меня: в 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) %>

надеюсь, это поможет вам;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...