Rails一对一的关系

cgf*_*cgf 10 ruby ruby-on-rails one-to-one

我有以下内容:

class User < ActiveRecord::Base
  has_one :car, :class_name => 'Car', :foreign_key => 'user_id'

class Car < ActiveRecord::Base
  belongs_to :worker, :class_name => 'User', :foreign_key => 'user_id'
Run Code Online (Sandbox Code Playgroud)

它基本上是用户和汽车之间的一对一关系.

我想要的是用户能够拥有一辆且只有一辆车.这意味着如果他创造了一辆分配给他的汽车,他将无法创造第二辆汽车.

怎么可以这样做?

Rob*_*ert 18

肯定有几种不同的方法可以实现这一目标.我建议在该表上创建一个复合键索引,以确保user_id在表中是唯一的.这将确保它只出现一次.在迁移中,您可以编写类似这样的内容.

add_index(:cars, :worker_id, :unique => true)
Run Code Online (Sandbox Code Playgroud)

第一个参数是表名(不要忘记这通常是类名的复数版本).字段名称排在第二位.唯一的真实是阻止您插入额外行.

注意:这是数据库级别约束.如果你点击这个是因为验证没有捕获它,它将引发错误.

除此解决方案外,您还需要为Car模型本身添加验证.

validates_uniqueness_of :worker_id, message: "can not have more than one car"
Run Code Online (Sandbox Code Playgroud)

你会看到这个错误来自"工人ID不能有多辆汽车"之类的东西.您很可能想要自定义此"工作者ID"部分.有关如何执行此操作的说明,请参阅此帖子.

您当然不必执行db约束,但是如果有其他人插入数据库,那么这是个好主意.否则,就Rails而言,您将拥有"无效"数据.


Ric*_*own 12

稍微改变关系的定义:

class User < ActiveRecord::Base
  has_one :car

class Car < ActiveRecord::Base
  belongs_to :worker, :class_name => 'User', :foreign_key => 'user_id'
Run Code Online (Sandbox Code Playgroud)

而且你将建立你正在寻找的东西.请参阅:http://guides.rubyonrails.org/association_basics.html#the-has-one-association


Ada*_*amT 1

为什么不在用户尝试添加汽车之前进行测试呢?

if worker.car
 raise "sorry buddy, no car for you"
else
 car = Car.create(user_id: worker.id)
end
Run Code Online (Sandbox Code Playgroud)