Подтвердить что ты не робот

Показать ссылку в Rails form error message

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

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

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

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

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

4b9b3361

Ответ 1

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

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

# 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 и т.д.)

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

Ответ 2

Это может не упорядочить хорошо с переводами, но вот предложение:

В вашем действии user_controller # create оберните все, что у вас уже есть, с помощью оператора 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. Контроллер предназначен для взаимодействия с представлением и моделью. Это немного нарушает принцип DRY, поскольку вы в основном обходите validates_uniqueness_of :email, но вы получаете какое-то индивидуальное поведение. DRY не кажется мне 100% достижимым, если вы хотите создавать более сложные приложения, но, возможно, вы можете уточнить это и доказать, что я ошибаюсь;)

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

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

Ответ 3

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

Ответ 4

Если вы используете 2.3.x, замените свой вызов на error_messages своим помощником, написанным в UserHelper. Он должен принять объект 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, прежде чем они будут отправлены в представление.

Ответ 5

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

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

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

Ответ 6

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

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

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