Richbits
Richbits

Reputation: 7624

Multiple associations on same models

I have models for a business and for a user. A business may have multiple managers, but only one of those managers can be an owner. I have tried to model as follows:

class Business < ApplicationRecord
   has_many :managements
   has_many :managers, through: :managements, source: :user, autosave: true
   has_one :ownership, -> { where owner: true },
                 class_name: 'Management',
                 autosave: true
   has_one :owner, through: :ownership, source: :user, autosave: true
end
class Management < ApplicationRecord
  belongs_to :user
  belongs_to :business
end
class User < ApplicationRecord
  has_many :managements
  has_many :businesses, through: :managements
end

This all seems to work fine until I try to save the business:

business.owner = owner
#<User id: nil, email: "[email protected]", password_digest: "$2a$04$aXswT85yAiyQ/3Pa2QAMB.4eDs9JPikpFfb8fJtwsUg...", confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, created_at: nil, updated_at: nil>
business.ownership
#<Management id: nil, user_id: nil, business_id: nil, owner: true, created_at: nil, updated_at: nil>
(byebug) business.owner
#<User id: nil, email: "[email protected]", password_digest: "$2a$04$aXswT85yAiyQ/3Pa2QAMB.4eDs9JPikpFfb8fJtwsUg...", confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, created_at: nil, updated_at: nil>
(byebug) business.valid?
false
(byebug) business.errors
#<ActiveModel::Errors:0x007f9ef5ca5148 @base=#<Business id: nil, longitude: #<BigDecimal:7f9ef2c23e48,'0.101E3',9(27)>, latitude: #<BigDecimal:7f9ef2c23d58,'-0.23E2',9(27)>, address: "line 1, line2, town, county", postcode: "B1 1NL", business_name: "Business 1", deleted_at: nil, created_at: nil, updated_at: nil>, @messages={:"ownership.business"=>["must exist"]}, @details={:"ownership.business"=>[{:error=>:blank}]}>

I don't understand what the ownership.business relationship is? What can I do to make this work?

I am using rails 5.0.6.

Upvotes: 0

Views: 102

Answers (1)

fongfan999
fongfan999

Reputation: 2624

Try to append inverse_of: :business to the has_one :ownership

has_one :ownership, -> { where(owner: true) },
                 class_name: 'Management',
                 autosave: true,
                 inverse_of: :business

From the documentation, it seems like the :inverse_of option is a method for avoiding SQL queries, not generating them. It's a hint to ActiveRecord to use already loaded data instead of fetching it again through a relationship.

I think :inverse_of is most useful when you are working with associations that have not yet been persisted.

  • Without the :inverse_of arguments, ownership.business would return nil, because it triggers an sql query and the data isn't stored yet.
  • With the :inverse_of arguments, the data is retrieved from memory.

Upvotes: 1

Related Questions