【问题标题】:Decisions based on ActiveRecord validation errors基于 ActiveRecord 验证错误的决策
【发布时间】:2011-12-25 11:15:33
【问题描述】:

我对 Rails 很陌生,想知道最好的方法是什么:

我有一个控制器在数据库中创建一条记录。

如果发生特定的验证错误,我想设置一个标志,但我看不到使用我熟悉的 rails 模式完成此操作的好方法。

我要检测的模型验证是:

validates_uniqueness_of :title

我的控制器正在这样做:

fcs = Entity.create(:title => text)

当上述错误失败时,我可以使用 ActiveModel 错误集合。

我应该如何可靠地设置一个标志,以编程方式表明标题已被占用?

到目前为止我已经考虑过

fcs.errors.messages.has_key?(:title)

但是如果标题由于其他原因失败,这将返回 true。所以我需要更多类似的东西:

fcs.errors.messages[:title]==["has already been taken"]

但这将是一个令人头疼的维护问题,并且还会被不同的语言环境破坏......

那么有谁知道应该如何使用 RoR 来完成这项工作?

感谢您的建议

编辑:建议标志“is_title_duplicated”的示例用法:

if(! fcs.errors.empty?)
      json['success']=false
      json['errors']=fcs.errors.full_messages
      json['title_was_duplicate'] = is_title_duplicated
      render :json => json

...

【问题讨论】:

  • 你这样做是为了达到什么目的?
  • 这是一个 ajax 控制器,它返回一个成功或失败的 json 消息。如果验证失败,则会显示消息集合,并显示咆哮通知。其中一个失败可能是因为存在与节点上具有相同标题的列表。在这种情况下,我想显示一个模式弹出窗口以捕获替代标题,然后再次尝试验证。

标签: ruby-on-rails validation activerecord activemodel


【解决方案1】:

你的意思是在记录上设置一个标志?每当验证失败时,记录就不会保存到数据库中

如果您只是想设置错误消息,则不必这样做。 Rails 会自动将 fsc.erros 设置为一个类似于 {:title => "title has already beentaking"} 的哈希值。您可以通过将 :message 传递给您的验证来指定该消息。

此外,您可以使用 l18n 将消息国际化。只需按照此处所述编辑 yaml 文件: http://guides.rubyonrails.org/i18n.html#configure-the-i18n-module

【讨论】:

  • 我的意思是我需要一个局部变量标志 - 这样我就可以针对这种情况运行不同的逻辑。
  • 你能举个例子说明你想如何使用那个局部变量标志吗?
  • 我已在问题中附加了一个示例。
  • 那么像 is_title_duplicated = ( fcs.errors.messages[:title]==[t("long.path.to.my.error.message")] ) 是最好的方法吗?
【解决方案2】:

我建议向您的模型类添加一个方法来检测唯一性。

class Entity < ActiveRecord::Base
  def unique_title?
    Entity.where(:title => title).count > 0
  end
end

当然,这意味着您要运行该查询两次(一次用于validates_uniqueness_of,一次用于unique_title?)。只要性能可以接受,我更喜欢可读性而不是性能。如果性能不可接受,您仍然可以选择。您可以在自己的自定义验证中重复使用unique_title? 并缓存结果。

class Entity < ActiveRecord::Base
  validate :title_must_be_unique

  def unique_title?
    # you may want to unset @unique_title when title changes
    if @unique_title.nil?
      @unique_title = Entity.where(:title => title).count > 0
    end
    @unique_title
  end

  private

  def title_must_be_unique
    unless unique_title?
      errors.add(:title, I18n.t("whatever-the-key-is-for-uniqueness-errors"))
    end
  end
end

【讨论】:

  • 谢谢,我想应该是 .count == 0 但我明白了。
  • 性能不是问题,所以使用可读版本,但很高兴知道存在解决方法:)
猜你喜欢
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多