在Rails中显示链接表单错误消息

时间:2011-03-16 16:53:00

标签: ruby-on-rails ruby-on-rails-3 validation internationalization

在我们的注册表单上,我们validates_uniqueness_of :email

当用户尝试使用我们的注册表单并指定现有的电子邮件地址时,我希望他们看到这样的错误消息

  

此电子邮件地址已被使用。如果您在登录时遇到问题,可以reset your password

显然,我想使用命名路由作为链接,但我的用户模型无法访问它。我怎么能做到这一点?

旁注:我们很快会为我们的应用提供翻译,所有这些错误消息都会以YAML文件结尾。我可以以某种方式在我的YAML语言环境文件中的消息中注入new_password_url吗? (例如,config/locales/en.yml

6 个答案:

答案 0 :(得分:14)

我知道这是一个老问题,但对于想要在错误消息中插入链接的未来用户,以下是一些适用于我的指南。

首先,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 :(得分:1)

这可能不能很好地简化翻译,但这里有一个建议:

在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'将使用先前输入的数据重新填充自己(如果用户只是错误输入了自己的电子邮件地址,并且实际上不在系统中)。< / p>

如果你决定使用这种方法,我会在两者控制器和模型中发表评论,表明电子邮件的唯一性基本上是在2个地方检查过的。如果其他人必须查看此代码,它将帮助他们理解和维护它。

答案 2 :(得分:0)

您可以在错误消息中放置自己的标记,如〜[new_password_url]。然后在渲染您的错误消息gsub ur标签与实际。如果你想一般性地做到这一点,你可以使用regexp获取路径,然后评估它以获取url然后gsub它。如果你将html放入你的文本,请使用raw方法。

答案 3 :(得分:0)

如果您使用的是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

答案 4 :(得分:0)

今天偶然发现了这个:

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步

现在我们只需要一种方法来为原始问题中描述的错误消息添加插值。这就是我目前陷入困境的地方:(

答案 5 :(得分:-1)

经过几个小时试图用设计来解决Rails 4,我意识到你可以直接将链接添加到验证中:

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

这种情况下的链接是我的用户索引。希望这会对某人有所帮助!