ruby-on-rails - 在 ActiveModel 对象上,如何检查唯一性?

标签 ruby-on-rails validation activemodel rails-activerecord

在 Bryan Helmkamp 的优秀博文“7 Patterns to Refactor Fat ActiveRecord Models”中,他提到使用表单对象来抽象多层表单并停止使用accepts_nested_attributes_for

编辑:参见below寻求解决方案。

我几乎完全复制了他的代码示例,因为我有同样的问题需要解决:

class Signup
  include Virtus

  extend ActiveModel::Naming
  include ActiveModel::Conversion
  include ActiveModel::Validations

  attr_reader :user
  attr_reader :account

  attribute :name, String
  attribute :account_name, String
  attribute :email, String

  validates :email, presence: true
  validates :account_name,
    uniqueness: { case_sensitive: false },
    length: 3..40,
    format: { with: /^([a-z0-9\-]+)$/i }

  # Forms are never themselves persisted
  def persisted?
    false
  end

  def save
    if valid?
      persist!
      true
    else
      false
    end
  end

private

  def persist!
    @account = Account.create!(name: account_name)
    @user = @account.users.create!(name: name, email: email)
  end
end

我的代码的不同之处之一是我需要验证帐户名(和用户电子邮件)的唯一性。但是,ActiveModel::Validations 没有唯一性 验证器,因为它应该是 ActiveRecord 的非数据库支持变体。

我认为可以通过三种方法来处理这个问题:

  • 编写我自己的方法来检查这一点(感觉多余)
  • 包含 ActiveRecord::Validations::UniquenessValidator(尝试过此操作,但没有成功)
  • 或者在数据存储层添加约束

我更喜欢使用最后一个。但后来我一直想知道如何我将实现这个。

我可以做类似的事情(元编程,我需要修改一些其他区域):

  def persist!
    @account = Account.create!(name: account_name)
    @user = @account.users.create!(name: name, email: email)
  rescue ActiveRecord::RecordNotUnique
    errors.add(:name, "not unique" )
    false
  end

但现在我的类中运行了两项检查,首先使用 valid?,然后使用 rescue 语句来进行数据存储约束。

有谁知道解决这个问题的好方法吗?也许为此编写我自己的验证器会更好(但随后我会对数据库进行两次查询,理想情况下一个就足够了)。

最佳答案

如果这恰好是一次性要求,那么创建自定义验证器可能有点过分了。

简化的方法...

class Signup

  (...)

  validates :email, presence: true
  validates :account_name, length: {within: 3..40}, format: { with: /^([a-z0-9\-]+)$/i }

  # Call a private method to verify uniqueness

  validate :account_name_is_unique


  def persisted?
    false
  end

  def save
    if valid?
      persist!
      true
    else
      false
    end
  end

  private

  # Refactor as needed

  def account_name_is_unique
    if Account.where(name: account_name).exists?
      errors.add(:account_name, 'Account name is taken')
    end
  end

  def persist!
    @account = Account.create!(name: account_name)
    @user = @account.users.create!(name: name, email: email)
  end
end

关于ruby-on-rails - 在 ActiveModel 对象上,如何检查唯一性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14670396/

相关文章:

css - 将目标 ="_blank"用于 anchor 不再返回 html5 文档类型中的验证错误

javascript - URL 的 <input> 标签验证

ruby-on-rails - ActiveModel 是否有包含 "update_attributes"方法的模块?

ruby-on-rails - Rails validates_presense 未验证 boolean 值?

ruby-on-rails - cucumber 显示页面未显示页面(解决方案: it was on the wrong line)

php - 如何显示空字段错误消息

ruby-on-rails - Rails Association Validations : The field, 或 _id 字段?

ruby-on-rails - rails : overriding model name in params

javascript - 事件未在第一页加载时加载但在刷新后有效

ruby-on-rails - rails 3 : jopenssl load error