Dino Maric

February 17, 2023

ActiveRecord associations with a conditions

ActiveRecord as a neat trick/ability which a lot of folks are not aware of.

You can pass a block to association, for example:


class Account < ApplicationRecord
 has_many :users, -> { where(admin: true) }
end

class User < ApplicationRecord
 belongs_to :account
end


What makes this even more interesting is that you can have multiple associations to the same model with different name and conditions.


class Account < ApplicationRecord
 has_many :users
 has_many :admin_users, -> { where(admin: true) }, class_name: "User"
end


Calling `@account.users` will return collection of all users, but calling `@account.admin_users` will return collection of only admin users.

To make things even more interesting, when creating a new record through the association will comply with the association condition.


@account.admin_users.create(name: "Admin User")
creates a new user with `admin` set to `true`.


Since, condition executes in the context of the association object, you can also use scopes.


class Account < ApplicationRecord
  has_many :users
  has_many :admin_users, -> { admins }, class_name: "User"
end

class User < ApplicationRecord
 belongs_to :account
 
 scope :admins, -> { where(admin: true) }
end

@account.admin_users # Works the same as examples above


This associations will also work for eager loading also, calling
`Account.includes(:admin_users)` will eager load admin users.


ActiveRecord can accomplish this because associations are built from `Relation` objects, and you can use `Relation` syntax to customize them.


Isn't this neat!


ps
This post is also published on our company dev blog 

About Dino Maric

Hey! I'm Dino, programmer and CTO of WizardHealth.
Subscribe bellow to follow my ramblings about programming for the web.