Rails one-to-one relationship

cgf picture cgf · Feb 26, 2013 · Viewed 24.7k times · Source

I have the following:

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'

It is basically a one-to-one relationship between a user and a car.

What I want is for the User to be able to have one and only one car. That implies the fact that if he creates a car assigned to him, he won't be able to create the second.

How could this be done?

Answer

Robert picture Robert · Mar 8, 2013

There are certainly a couple different ways of accomplishing this. I would suggest creating a composite key index on that table to ensure that the user_id is unique in the table. This will ensure that it will only be present once. In a migration, you could write something like this.

add_index(:cars, :worker_id, :unique => true)

The first argument is the table name (don't forget this is generally the pluralized version of the class name). The field name comes second. The unique true is what will prevent you from inserting an extra row.

Note: This is a database level constraint. If you hit this because validations didn't catch it, it will throw an error.

In addition to this solution, you will want to add a validation to the Car model itself.

validates_uniqueness_of :worker_id, message: "can not have more than one car"

You'll see this error come through with something like "Worker ID can not have more than one car". You will most likely want to customize the "Worker ID" section of this. Refer to this post for instructions on how to do that.

You certainly don't have to do the db constraint, but in case anyone else inserts into the DB, it's a good idea. Otherwise, you'll have "invalid" data as far as Rails is concerned.