【发布时间】:2016-07-03 16:56:27
【问题描述】:
我正在搜索 4 天来解决这个问题,我在 ActiveRecord 和使用唯一性验证方面遇到了一些问题。 我无法在控制台或测试中创建包含至少一个唯一性验证的模型。但是,我可以使用 rails 服务器 (API) 创建对象。
这让我发疯了!当我将 Rails3 项目更新到 Rails4 时,它就开始了。
实际上,我使用以下宝石:
- Rails 4.0.15
- Ruby 2.2.0
- FactoryGirl Rails 4.6.0
- Rspec 3.4.1
- PG 0.18.4
相关型号:
class ContainerType < BaseModel
has_many :containers, :inverse_of => :container_type, :dependent => :restrict_with_exception
validates :name, :length => { :minimum => 1, :maximum => 25 },
:presence => true,
:uniqueness => true
end
BaseModel 是一个抽象,包含一些所有模型共有的include。
class BaseModel < ActiveRecord::Base
self.abstract_class = true
include [...]
end
在控制台中测试:
test = ContainerType.last.dup
ContainerType Load (0.7ms) SELECT "container_types".* FROM "container_types" ORDER BY "container_types"."id" DESC LIMIT 1
<ContainerType id: nil, name: "Type #1-6f896a99-fb63-4b3", created_at: nil, updated_at: nil>
test.save!
(0.3ms) 开始
ContainerType Exists (0.4ms) SELECT 1 AS one FROM "container_types" LIMIT 1
(0.3ms) 回滚
ActiveRecord::RecordInvalid:验证失败:名称已被占用
来自 /home/dev/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-4.1.15/lib/active_record/validations.rb:57:in `save!'
对于有效的 ContainerType:
ContainerType.delete_all
ContainerType.create!(name: 'my container type 1 !')
(0.3ms) 开始
ContainerType Exists (0.4ms) SELECT 1 AS one FROM "container_types" LIMIT 1
(0.3ms) 回滚
ActiveRecord::RecordInvalid:验证失败:名称已被占用
来自 /home/dev/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-4.1.15/lib/active_record/validations.rb:57:in `save!'
您可能注意到 SELECT 验证请求没有条件。 我确定它与 ActiveRecord 或不兼容的 gem 有关,但我找不到原因....
其他测试:
container_type = ContainerType.where(name: 'my container type 1 !').first_or_create
ContainerType Load (0.6ms) SELECT "container_types".* FROM "container_types" WHERE "container_types"."name" = '我的容器类型 1 !' ORDER BY "container_types"."id" ASC LIMIT 1
(0.1ms) 开始
ContainerType Exists (0.3ms) SELECT 1 AS one FROM "container_types" LIMIT 1
(0.2ms) 回滚
p container_type.inspect
"#<ContainerType id: nil, name: \"my container type 1 !\", created_at: nil, updated_at: nil>"
测试
所以问题是:
- 什么可以使唯一性验证无条件创建 SQL 请求?
- 你已经看到了吗?
编辑:
经过一番调查,我尝试了:
- 在所有 before_* 回调中添加 return true
- 创建用于唯一性验证的自定义验证器
- 我生成了一个脚手架模型来检查它是否与我的通用包含相关。
我认为:
这似乎与模型属性有关,通过 rails 更新,我将 StrongParameter 添加到我的控制器中。但模型可能仍在使用一种 protected_attribute 遗物。
【问题讨论】:
-
您可以尝试在唯一性验证器上将区分大小写的属性设置为 false,如下所示:
validates :name, uniqueness: { case_sensitive: false } -
@D.Visser :我试过了,没有任何变化......
-
在我看来,它完全按照它应该的方式工作。当您运行
ContainerType.last.dup时,您正在从最后创建的 ContainerType 中复制属性。您对name进行了唯一性验证...当您调用save时,该对象无法保存,因为它与另一个对象具有相同的名称。 -
@toddmetheny 哎呀,我忘记了有效的案例......我更新了问题。
-
delete_all之后你能保证对象已经被销毁了吗?你能发布你从运行delete_all获得的相关堆栈跟踪吗?改用destroy时会得到同样的结果吗?也许有相关的回调应该运行但不是?如果你在运行delete_all之后但在调用create!之前reload!控制台呢?
标签: ruby-on-rails validation activerecord