Показать ссылку в сообщении об ошибке в форме Rails - PullRequest
12 голосов
/ 16 марта 2011

В нашей регистрационной форме мы validates_uniqueness_of :email

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

Этот адрес электронной почты уже используется. Если у вас возникли проблемы при входе в систему, вы можете сбросить пароль

Очевидно, я хотел бы использовать именованный маршрут для ссылки, но моя модель User не имеет к ней доступа. Как мне это сделать?

Примечание: Мы скоро предложим переводы для нашего приложения, и все эти сообщения об ошибках будут в конечном итоге в файлах YAML. Могу ли я каким-то образом вставить свой new_password_url в сообщение в моих файлах локали YAML? (например, config/locales/en.yml)

Ответы [ 6 ]

14 голосов
/ 26 сентября 2012

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

Во-первых, сообщения об ошибках I18n предполагаются htmlуже в безопасности, так что вы можете пойти дальше и написать подходящее сообщение об ошибке.В этом примере я изменяю сообщение «электронное письмо принято».

# config/locales/en.yml
activerecord:
  errors:
    models:
      user:
        attributes:
          email:
            taken: 'has already been taken. If this is your email address, try <a href="%{link}">logging in</a> instead.'

Обратите внимание на интерполированную переменную %link.

Теперь все, что вам нужно, это передать значение дляэта переменная в вашем валидаторе, например, так:

# app/models/user.rb
validates :email, :uniqueness => {:link => Rails.application.routes.url_helpers.login_path}

(По умолчанию все передаваемые здесь опции будут автоматически отправляться в транслятор I18n в виде переменных, включая некоторые специальные предварительно заполненные переменные, такие как %value, %model и т. Д.)

Вот и все!Теперь у вас есть ссылка в сообщении об ошибке.

1 голос
/ 22 марта 2011

Возможно, это не совсем хорошо с переводами, но вот предложение:

В вашем user_controller # create action оберните все, что у вас уже есть, с помощью оператора if. Вот грубый пример:

class UserController < ApplicationController
...

def create
  if User.find(params[:email])
    flash[:alert] = "This email address is in use.  You can ".concat(generate_reset_password_link(params[:email])
    render :action => 'new'
  else
    <your current code>
  end
end

После этого вам придется написать вспомогательный метод generate_reset_password_link, но я думаю, что в основном это соответствует макету MVC. Контроллер предназначен для взаимодействия с видом и моделью. Это немного нарушает принцип СУХОГО, так как вы, по сути, обходите validates_uniqueness_of :email, но вы получаете некоторое нестандартное поведение. Мне кажется, что DRY не достижим на 100%, если вы хотите создавать более сложные приложения, но, возможно, вы можете уточнить это и доказать, что я не прав;)

Возможно, вам придется немного помассировать его, чтобы render :action => 'new' снова заполнился ранее введенными данными (в случае, если пользователь просто набрал свой собственный адрес электронной почты, а его фактически нет в системе).

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

0 голосов
/ 25 мая 2015

После нескольких часов попыток выяснить это для Rails 4 с помощью devise, я понял, что вы можете просто добавить ссылку непосредственно в валидацию:

# app/models/user.rb
validates :username, presence: true, uniqueness: {:message => "username has already been taken - <a href='/users'>search users</a>" }

, где ссылка в этом случае - мой индекс пользователей.Надеюсь, это кому-нибудь поможет!

0 голосов
/ 25 марта 2011

Наткнулся на это сегодня:

http://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html

Если вам нужен доступ к этому автоматически сгенерированному методу из других мест (например, из модели), то вы можете сделатьчто включив ActionController::UrlFor в ваш класс:


Шаг 1

Получение информации об именованных маршрутах к модели является сложной частью;это дает мне большую часть пути.

Теперь я могу сделать что-то вроде

class User < ActiveRecord::Base
  include Rails.application.routes.url_helpers

  def reset_password_uri
    new_user_password_path(self)
  end
end

# User.find(1).reset_password_uri => "/users/password/new"

Шаг 2

Итак, у нас есть доступ к названномумаршрут, но теперь нам нужно вставить его в сообщение YAML.

Вот что я только что узнал о переменных YAML:

# en.yml
en:
  welcome: "Hello, %{username}!"

# es.yml
es:
  welcome: "¡Hola, %{username}!"

Я могу добавить username, добавив хеш сt метод

<div id="welcome">
  <%= t :welcome, :username => @user.username %>
</div>

Шаг 3

Теперь нам просто нужен способ добавить интерполяцию к сообщению об ошибке, описанному в исходном вопросе.Вот где я сейчас застрял: (

0 голосов
/ 25 марта 2011

Если вы используете 2.3.x, замените ваш звонок на error_messages своим собственным помощником, написанным в UsersHelper. Он должен принять FormBuilder или объект ActiveRecord и настроить сообщение об ошибке, как вам удобно. Вы можете сделать столько настроек, сколько хотите, или это может быть так просто, как gsub:

def user_error_messages(f)
  find_error = "This email address is already in use."
  replacement = "This email address is already in use. #{link_to(...)} to reset your password"
  f.error_messages.sub(find_error, replacement).html_safe
end

Если вы используете Rails3, создайте вспомогательный метод для простой обработки @user.errors.full_messages до того, как они будут переданы в представление.

0 голосов
/ 16 марта 2011

Вы можете разместить собственный тег, например ~ [new_password_url], в своих сообщениях об ошибках.Затем в момент отрисовки ваших сообщений об ошибках тег gsub ur с актуальным.если вы хотите сделать это в общем, вы можете получить путь с помощью regexp, а затем проверить его, чтобы получить URL, затем gsub вернуть его обратно. заставить использовать метод raw, если вы вставляете html в ваш текст.

...