Ruby on Rails

ActiveRecord Associations

belongs_to

A belongs_to association sets up a one-to-one connection with another model, so each instance of the declaring model “belongs to” one instance of the other model.

For example, if your application includes users and posts, and each post can be assigned to exactly one user, you’d declare the post model this way:

class Post < ApplicationRecord
  belongs_to :user
end

In your table structure you might then have

create_table "posts", force: :cascade do |t|
  t.integer  "user_id",  limit: 4
end

has_one

A has_one association sets up a one-to-one connection with another model, but with different semantics. This association indicates that each instance of a model contains or possesses one instance of another model.

For example, if each user in your application has only one account, you’d declare the user model like this:

class User < ApplicationRecord
  has_one :account
end

In Active Record, when you have a has_one relation, active record ensures that the only one record exists with the foreign key.

Here in our example: In accounts table, there can only be one record with a particular user_id. If you try to associate one more account for the same user, it makes the previous entry’s foreign key as null(making it orphan) and creates a new one automatically. It makes the previous entry null even if the save fails for the new entry to maintain consistency.

user = User.first
user.build_account(name: "sample")
user.save   [Saves it successfully, and creates an entry in accounts table with user_id 1]
user.build_account(name: "sample1")  [automatically makes the previous entry's foreign key null]
user.save  [creates the new account with name sample 1 and user_id 1]

has_many

A has_many association indicates a one-to-many connection with another model. This association generally is located on the other side of a belongs_to association.

This association indicates that each instance of the model has zero or more instances of another model.

For example, in an application containing users and posts, the user model could be declared like this:

class User < ApplicationRecord
  has_many :posts
end

The table structure of Post would remain the same as in the belongs_to example; in contrast, User would not require any schema changes.

If you want to get the list of all the published posts for the User, then you can add the following (i.e. you can add scopes to your association objects):

class User < ApplicationRecord
  has_many :published_posts, -> { where("posts.published IS TRUE") }, class_name: "Post"
end

Polymorphic association

This type of association allows an ActiveRecord model to belong to more than one kind of model record. Common example:

class Human < ActiveRecord::Base
  has_one :address, :as => :addressable
end

class Company < ActiveRecord::Base
  has_one :address, :as => :addressable
end

class Address < ActiveRecord::Base
  belongs_to :addressable, :polymorphic => true
end

Without this association, you’d have all these foreign keys in your Address table but you only would ever have a value for one of them because an address, in this scenario, can only belong to one entity (Human or Company). Here is what it would look like:

class Address < ActiveRecord::Base
  belongs_to :human
  belongs_to :company
end

The has_many :through association

A has_many :through association is often used to set up a many-to-many connection with another model. This association indicates that the declaring model can be matched with zero or more instances of another model by proceeding through a third model.

For example, consider a medical practice where patients make appointments to see physicians. The relevant association declarations could look like this:

class Physician < ApplicationRecord
  has_many :appointments
  has_many :patients, through: :appointments
end

class Appointment < ApplicationRecord
  belongs_to :physician
  belongs_to :patient
end

class Patient < ApplicationRecord
  has_many :appointments
  has_many :physicians, through: :appointments
end

The has_one :through association

A has_one :through association sets up a one-to-one connection with another model. This association indicates that the declaring model can be matched with one instance of another model by proceeding through a third model.

For example, if each supplier has one account, and each account is associated with one account history, then the supplier model could look like this:

class Supplier < ApplicationRecord
  has_one :account
  has_one :account_history, through: :account
end

class Account < ApplicationRecord
  belongs_to :supplier
  has_one :account_history
end

class AccountHistory < ApplicationRecord
  belongs_to :account
end

The has_and_belongs_to_many association

A has_and_belongs_to_many association creates a direct many-to-many connection with another model, with no intervening model.

For example, if your application includes assemblies and parts, with each assembly having many parts and each part appearing in many assemblies, you could declare the models this way:

class Assembly < ApplicationRecord
  has_and_belongs_to_many :parts
end

class Part < ApplicationRecord
  has_and_belongs_to_many :assemblies
end

Self-Referential Association

Self-referential association is used to associate a model with itself. The most frequent example would be, to manage association between a friend and his follower.

ex.

rails g model friendship user_id:references friend_id:integer

now you can associate models like;

class User < ActiveRecord::Base
  has_many :friendships
  has_many :friends, :through => :friendships
  has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
  has_many :inverse_friends, :through => :inverse_friendships, :source => :user
end

and the other model will look like;

class Friendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, :class_name => "User"
end

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow