2011-05-27 81 views
6

我正在调查validates_presence_of实际如何工作。假设我有两个型号validates_presence_of与belongs_to关联,正确的方式

class Project < ActiveRecord::Base 
    [...] 
    has_many :roles 
end 

class Role < ActiveRecord::Base 
    validates_presence_of :name, :project 

    belongs_to :project 
end 

我希望它让角色始终属于现有的项目,但我刚刚从this example发现,这可能会导致保存无效(孤立的)角色进入数据库。所以正确的做法是在我的Role模型中插入validates_presence_of :project_id,它似乎工作,即使我认为语义上有更多的意义来验证项目的存在而不是项目ID。

除此之外,我想我可以把一个无效的id(对于一个不存在的项目),如果我只是验证project_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 |   | 
+----+------+------------+ 

当然我不会写这样的代码,但我想阻止这种在DB错误的数据。

我想知道如何确保一个角色总是有一个(真实的和保存的)项目关联。

我发现了validates_existence宝石,但我宁愿不添加宝石到我的项目中,除非是绝对必要的。

对此有何想法?

更新

validates_presence_of :project和在迁移PROJECT_ID列添加:null => false似乎是一个清洁的解决方案。

+0

我强烈建议使用validates_existence gem来做这件事,因为它正是你需要的。此外,它具有相当小的依赖性。 – Jits 2011-06-02 13:47:50

+1

只是一个快速不 - 确保你使用你的数据库来验证。让生活更安全。 – CharlesJHardy 2011-06-02 17:34:20

+0

@Jits,我想我会那样做的。 @Chuck我也会这样做,但这样我就不会有验证错误,所以我仍然需要在ruby级别进行验证。 – Fabio 2011-06-06 16:57:21

回答

2

我尝试了很多验证器的组合,但最干净的解决方案是使用validates_existence宝石。有了,我可以写这样

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"]} 

代码,所以我最终的模型很简单,只要

class Role < ActiveRecord::Base 
    belongs_to :project 
    validates_existence_of :project 
    # or with alternate syntax 
    validates :project, :existence => true 
    [...] 
end 

使用DB验证加阿迪亚溶液(即:空=>在迁移和validates_presence_of假:项目在模型中)Role#valid?将返回true,Role#save将在project_id为空时在数据库级别引发异常。

6

如果找不到具有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 

我看到你的问题也想处理作者对象提供的情况,但是新的而不是db。在存在检查不起作用的情况下。将解决。

Role.create!(:name => "admin", :project => Project.new) # Validation passes when it shouldn't. 

更新: 在一定程度上可以减轻这样做对相关的验证通过虚设新对象的效果:项目。

class Role < ActiveRecord::Base 
    belongs_to :project 
    validates_presence_of :project 
    validates_associated :project 
end 

如果Project.new.valid?是假的,然后Role.create!(:name => "admin", :project => Project.new)也将产生一个错误。但是,如果Project.new.valid?为真,那么上述内容将在保存时创建一个项目对象。

是否使用validates_associated :project对您有帮助?

+0

我不喜欢'validates_associated:project',因为它似乎需要两条线才能满足相同的要求,即项目必须存在,但它确实有效。 – Fabio 2011-06-01 02:08:19

相关问题