레일-고안-취급-devise_error_messages


125

내 사용자 편집 페이지에는 다음과 같은 줄이 있습니다.

<%= devise_error_messages! %>

문제는 이것이 나머지 앱이 수행하는 표준 방식으로 오류를 출력하지 않는다는 것입니다.

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

내 질문은 flash.each를 사용하는 다른 것과 비슷하게 고안 오류 메시지를 얻는 방법입니다.

감사.


1
Devise는 이미 앱의 나머지 부분에서 플래시를 사용하고 있습니다. devise_error_messages 플래시 메시지 (마지막 페이지의 정보)에 대한 것이 아니라 액티브 검증에서 오히려 검증 오류 guides.rubyonrails.org/v2.3.11/...
크리스토퍼 Oezbek

답변:


135

나는 이것을 스스로 알아 내려고 노력하고있다. 방금이 문제가 Github https://github.com/plataformatec/devise/issues/issue/504/#comment_574788에 기록 된 것을 발견했습니다.

Jose는 devise_error_messsages!메소드가 단지 스텁 (구현이 포함되어 있음)이고이를 재정의 / 교체해야한다고 말합니다. 이것이 위키의 어딘가에 지적되면 좋았을 것입니다. 그래서 우리와 같은 사람들이 추측하고있는 것 같습니다.

그래서 모듈을 다시 열고 메소드를 재정 의하여 기본 구현을 효과적으로 재정의하려고합니다. 어떻게되는지 알려 드리겠습니다.

최신 정보

그렇습니다. 나는 app/helpers/devise_helper.rb그것을 이렇게 만들고 무시했다.

module DeviseHelper
  def devise_error_messages!
    'KABOOM!'
  end
end

그래서 이것을 알면 원하는 방식으로 오류 메시지를 표시하도록 메소드를 수정할 수 있습니다.

원래 문제를 해결하기 위해 : devise_helper.rbGithub 의 원본 다음과 같습니다 . 오류 메시지가 어떻게 전달되는지 살펴보십시오.

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>

방금 시도했지만 작동하지 않습니다. 목표는 여기서 오류를 출력하는 것입니다 : <% flash.each do | key, value | %>
AnApprentice

@ColdTree 아니요, 목표는 플래시 메시지 처럼 작동하는 입니다. 마크 업을 제어 할 수있는 것이 좋은 솔루션입니다.
Benjamin Atkin

... 나는 이것이 좋은 연구 작업이지만 질문에 대답하지 않는다고 생각합니다.
deivid

37

아래 솔루션은 현재 최신 장치 (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">&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 %>

어떤 형태로든 넣을 수 있습니다. 고안 리소스를 전달하는 대신 다음과 같이 양식에서 변수를 전달할 수 있습니다.

<%= form_for @post do |f| %>
  <%= render 'layouts/error_messages', object: f.object %>  
  <%= f.text_field :content %>
  <%= f.submit %>
<% end %>

1
아마도 가장 훌륭하고 직관적 인 답변 일 것입니다.
Victor

2
멋진 솔루션. pluralize (object.errors.count, 'errors'는 pluralize (object.errors.count, 'error'로 변경되어야 함)
mizurnix

1
이 솔루션의 @LukaszMuzyka .. user.rb에서 : validatable을 제거해야합니까?
Vishal

1
@Vishal-아니요. 위의 솔루션은 단순히 다른 HTML을 사용하여 Devise의 메커니즘을 변경하지 않는 메시지를 표시합니다.
Lukasz Muzyka

1
@Vishal은 고안을 사용할 때 이미 추가 코드없이 언급 한 유효성 검사를 수행하고 있습니다. 위의 솔루션은 기본 고안 동작을 재정의하는 것입니다. 처음부터 일을해야합니다. 고안을 프로젝트와 통합하기위한 지침을 따랐습니까?
Lukasz Muzyka

22

이 질문이 게시 된 지 오래되었다는 것을 알고 있지만 찾은 내용에 대해 의견을 말하고 싶었습니다. 이미 답한 두 사람은 저에게 큰 도움이되었고 저는 단지 기여하고 싶었습니다.

Devise 전체에서을 사용하는 통화가 있음을 알 수 render_with_scope있습니다. 나는 이것이 고안에 의해 정의 된 방법이며 기본적으로 현재 범위를 렌더링 된 다음보기에 적용한다고 생각합니다.

이것이 왜 관련이 있습니까? Devise는 resource.errors( not @resource.errors ) 내에 오류를 포함합니다 . 상자 밖에서 사용하려면 Devise가 제대로 작동합니다.

사용자 관리 동작 변경을 시작하면 이러한 오류와 관련된 문제가 발생합니다. 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]. 각 메시지는 한 번에 한 줄씩 인쇄됩니다. 시간이 있다면 Devise가 오류 메시지를 처리하는 방법을 앱 전체에서 처리하는 방법을 변경한다고 생각합니다. 두 개가 아닌 하나의 오류 메시지 시스템을 갖는 것이 훨씬 깨끗해 보입니다.


3
그것에 대해 너무 감사합니다, 나는 그것을하려고 벽에 머리를 두드리고 있었다.
Lucas

1
이제 5 년이 지난 지금이 ​​응답으로 베이컨이 절약되었습니다. @ eric-hu에게 대단히 감사합니다.
marcamillion

12

나는 이것을 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

나는 단지 여기에 새로운 작은 조각을 가져오고 싶다.

그래서 "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

[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 %> 

그리고 ... 속성 당 하나의 오류 (첫 번째로 잡히는) 만 표시하는 작은 트릭입니다.

<% 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

여기서 큰 문제는 없었습니다. 내가 작성한 오류 코드 하나만 표시하기 위해 필자가 작성한 코드를 재사용했습니다.

이 "고유 한"오류를 세고 있으며 복수형을 사용하여 H2 HTML 제목을 만들고 오류 목록보다 먼저 표시합니다.

이제 "devise_error_messages!"를 사용할 수 있습니다 기본으로 사용하고 이전에 이미 렌더링 한 것과 정확하게 렌더링합니다.

보기에서 특정 오류 메시지에 액세스하려면 "resource.errors [: attribute] .first"등을 직접 사용하는 것이 좋습니다.

세야, 쿨 가르


6

Rails 3에서 Devise를 사용하고 있으며 플래시 코드는 내가 가진 것과 거의 동일합니다. 내 앱에서 코드는 예상대로 작동합니다. 즉, Devise 오류 메시지가 나머지 플래시 메시지와 함께 출력됩니다.

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

이 정확한 코드를 사용해보고 차이가 있는지 확인하십시오. 다른 ID 속성이 도움이 될 수 있습니다.


고마워하지만 아무것도 표시되지 않습니다. "<% = devise_error_messages! %>"는 오류를 출력합니다. 위는 아무것도하지 않았다? 아이디어?
AnApprentice

사과-나는 단지 당신의 의견을 보았습니다. 솔직히 말해서, 나는 아이디어가 부족합니다. 브라우저에서 소스를보고 생성 된 HTML을 확인했다고 가정합니까? CSS에 의해 무언가가 숨겨져있는 경우를 대비하여. 최신 버전의 Devise 1.1.3을 사용하고 있습니까?
스콧

5

나는 이것에 도달했고 지금까지 일하고있다. 이렇게하면 고안 메시지가 플래시에 추가되므로 평상시처럼 사용할 수 있습니다. 내가 Ruby and 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 -->

1
+1 좋은 답변입니다. 나는 이것이 가장 깨끗한 솔루션이라고 생각하며 현재의 아키텍처에 잘 어울립니다. 대답은 명확하지 않습니다-기본적으로 편집하기 전에 모든 것을 무시하고 제거하거나 imo를 강타해야합니다.
zelanix

3

주어진 유형 (: alert, : notice 등)의 플래시를 두 개 이상 표시하고 보석 동작을 수정하는 데 시간을 낭비하지 않으려면 이것이 Devise와 함께 사용한 솔루션입니다. 플래시 메시지를 사용하는 보석과 함께 사용할 수 있다고 확신합니다.

먼저 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.")

그러나 Devise 메시지가 오류 객체를 유지하는 대신 flash_messages를 호출하도록하는 방법.
Christopher Oezbek

3

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! %>

1
flash.now [: alert]
BM

2

분명히 약간 해키이지만이 도우미 (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

2

devise_error_messages를 피기 백하려는 경우 resource에 추가하면됩니다.

등록 컨트롤러를 과도하게 타면 다음과 같이 보일 수 있습니다.

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 

2

각 필드에 대한 오류 메시지를 표시하는 매우 쉬운 방법

<%= resource.errors.messages[:email].join(" ") %>

인라인 오류 메시지를 표시하려는 모든 행 아래에 대괄호 안에 필드 이름이있는 각 필드에 넣으십시오.


1

첫 번째 오류 만 표시하여 컨트롤러의 고안 오류를 표시합니다.

flash[:error] = @resource.errors.full_messages.first

1

모든 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 %>

1

나는 단순히 이것을하고 나를 위해 일했다 : 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) %>

그것이 당신에게 도움이되기를 바랍니다.)


나는 이것이 어떻게 어떻게되는지 이해하지 못한다? 이것이 표준 행동입니까? 그것은 또 다른 방법이며 <%= devise_error_messages! %>질문에 대답하지 않습니다. 질문은 각 메시지에 플래시를 적용하는 방법을 묻습니다.
Mark

0
  1. "devise_error_messages!"를 제거하십시오 "app / views / users / passwords / new"템플릿에서
  2. 사용자 (app / controllers / users / passwords_controller.rb) 및 사후 필터 추가 오류 플래시 배열에 대한 사용자 정의 컨트롤러를 만듭니다.
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

0

이 치트를 사용하여 다른 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 %>

0

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

나는 그들이 그것을 쓰는 가장 깨끗한 방법이라고 확신하지만 완벽하게 깨어납니다.


0

DeviseHelper#devise_error_messages! 는 더 이상 사용되지 않으며 다음 주요 버전에서 제거됩니다.

이제 Devise는 부분 언더 devise/shared/error_messages를 사용하여 기본적으로 오류 메시지를 표시하고보다 쉽게 ​​사용자 정의 할 수 있습니다. 다음에서 전화를 변경하여 조회수를 업데이트하십시오.

      <%= devise_error_messages! %>

에:

      <%= render "devise/shared/error_messages", resource: resource %>

-1

방금 app/helpers/devise_helper.rbJohn과 같은 것을 만들었지 만 다음과 같은 방법을 무시했습니다.

module DeviseHelper
  def devise_error_messages!
    flash[:error] = resource.errors.full_messages.join('<br />')
    return ''
  end
end

이것으로 나는 다른 것을 수정할 필요가 없습니다. 나쁜 생각입니까? 나는 레일을 처음 접했고 주저하지 말고 바로 잡으십시오. 감사.


플래시 메시지에 이제 html 태그 <br>가 포함되어 원하는대로 작동하지 않습니다. 일반적으로 플래시 메시지에는 문자열 만 넣습니다.
AZ.

아마도, 그러나 새로운 라인은 여전히 ​​작동합니다. 이 솔루션이 마음에 들지 않으면 다른 솔루션을 제안하십시오.
YoyoS

-2

방금 devise_error_messages를 선언했습니다! 빈 도우미로. 그리고 내 응용 프로그램의 일반적인 _errors 부분의 오류를 수동으로 가져 와서 처리했습니다. 가장 간단한 해결책처럼 보였고 모든 고안 파일을 거치지 않고 오류 처리기에 대한 호출을 제거 할 필요가 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.