Fab*_*bio 6 validation activerecord ruby-on-rails
我正在调查validates_presence_of实际上是如何工作的.假设我有两个模型
class Project < ActiveRecord::Base
[...]
has_many :roles
end
Run Code Online (Sandbox Code Playgroud)
和
class Role < ActiveRecord::Base
validates_presence_of :name, :project
belongs_to :project
end
Run Code Online (Sandbox Code Playgroud)
我想要它,以便角色总是属于现有项目,但我从这个例子中发现,这可能导致无效(孤立)角色保存到数据库中.因此,正确的方法是插入validates_presence_of :project_id
我的角色模型,它似乎有效,即使我认为在语义上更有意义来验证项目的存在而不是项目ID.
除此之外,如果我只是验证project_id的存在,我认为我可以放置一个无效的id(对于一个非现有项目),因为默认情况下AR不会为迁移添加完整性检查,即使我手动添加了一些数据库不支持它们(即MySQL与MyISAM或sqlite).这个例子证明了
# with validates_presence_of :name, :project, :project_id in the role class
Role.create!(:name => 'foo', :project_id => 1334, :project => Project.new)
AREL (0.4ms) INSERT INTO "roles" ("name", "project_id") VALUES ('foo', NULL)
+----+------+------------+
| id | name | project_id |
+----+------+------------+
| 7 | foo | |
+----+------+------------+
Run Code Online (Sandbox Code Playgroud)
当然我不会写这样的代码,但我想防止DB中的这种错误数据.
我想知道如何确保角色总是与(真实的和保存的)项目相关联.
我找到了validates_existence gem,但我不想在我的项目中添加gem,除非是绝对必要的.
有什么想法吗?
更新
validates_presence_of :project
并且:null => false
在迁移中添加project_id列似乎是一个更清洁的解决方案.
如果找不到具有id的对象,Rails将尝试查找id并添加验证错误.
class Role < AR::Base
belongs_to :project
validates_presence_of :project, :name
end
Role.create!(:name => "admin", :project_id => 1334)# Project 1334 does not exist
# => validation error raised
Run Code Online (Sandbox Code Playgroud)
我看到你的问题也想处理提供作者对象但是新的而不是db的情况.如果存在检查不起作用.会解决.
Role.create!(:name => "admin", :project => Project.new) # Validation passes when it shouldn't.
Run Code Online (Sandbox Code Playgroud)
更新:在某种程度上,您可以通过对关联的项目进行验证来减轻传递虚拟新对象的影响.
class Role < ActiveRecord::Base
belongs_to :project
validates_presence_of :project
validates_associated :project
end
Run Code Online (Sandbox Code Playgroud)
如果Project.new.valid?
为false Role.create!(:name => "admin", :project => Project.new)
则会引发错误.但是,如果是,Project.new.valid?
则上面将在保存时创建项目对象.
使用validates_associated :project
帮助吗?
我尝试了很多验证器的组合,但最干净的解决方案是使用validates_existence gem。这样我就可以编写这样的代码
r = Role.new(:name => 'foo', :project => Project.new) # => #<Role id: nil, name: "foo", project_id: nil, created_at: nil, updated_at: nil>
r.valid? # => false
r.errors # => {:project=>["does not exist"], :project_id=>["does not exist"]}
Run Code Online (Sandbox Code Playgroud)
所以我的最终模型很简单
class Role < ActiveRecord::Base
belongs_to :project
validates_existence_of :project
# or with alternate syntax
validates :project, :existence => true
[...]
end
Run Code Online (Sandbox Code Playgroud)
使用数据库验证加上 Aditya 解决方案(即迁移中的 :null => false 和模型中的 validates_presence_of :project)Role#valid?
将返回 true,并且Role#save
当 project_id 为 null 时,将在数据库级别引发异常。
归档时间: |
|
查看次数: |
9182 次 |
最近记录: |