In Rails 6
, Ruby 2.6
, I ran into a similar issue where I had a User
which could belong to many Organizations
, but always had a primary_organization
which was the first Organization
they were assigned to. Originally I had set this with the method:
def primary_organization
organizations.first
end
However, that ultimately broke my scope chaining. The above primary_organization
method can be refactored into a chainable conditional without having to change the user.primary_organization
syntax:
user.rb
# has_many: OrganizationUsers > Organizations
# ==================================================================================
has_many :organization_users,
class_name: 'OrganizationUser',
inverse_of: :user,
dependent: :destroy,
autosave: true,
has_many :organizations,
class_name: 'Organization',
through: :organization_users,
inverse_of: :organization_users,
source: :organization
# *** ADDED IN REFACTOR ***
# has_one: Organization
# shortcut for:
# • `user.organization_users.first.organization`
# • `user.organizations.first`
# ==================================================================================
has_one :primary_organization_user,
-> {
order(
created_at: :desc
).limit(1)
},
class_name: 'OrganizationUser',
inverse_of: :user
has_one :primary_organization,
class_name: 'Organization',
through: :primary_organization_user,
inverse_of: :organization_users,
source: :organization
organization_user.rb
# belongs_to: Organization
# ==================================================================================
belongs_to :organization,
class_name: 'Organization',
inverse_of: :organization_users
# belongs_to: User
# ==================================================================================
belongs_to :user,
class_name: 'User',
inverse_of: :organization_users
organization.rb
# has_many: OrganizationUsers > Users
# ==================================================================================
has_many :organization_users,
class_name: 'OrganizationUser',
inverse_of: :organization,
autosave: true,
dependent: :destroy
has_many :users,
class_name: 'User',
through: :organization_users,
inverse_of: :organization_users,
autosave: true