stacker
stacker

Reputation: 270

create a model instance with associations

I'm working on a Rails app. I encountred a problem with Rails associations: I got 3 models: User, Company and CompanyMember

#  id :integer not null, primary key
class User < ActiveRecord::Base
  has_one :company_member
  has_one :company, through: :company_member
end

#  id          :integer          not null, primary key
#  name        :string(255)      not null
class Company < ActiveRecord::Base
  has_many :company_members
  has_many :members, through: :company_members, foreign_key: "user_id", source: :user
  has_many :admins, -> {where admin: true }, through: :company_members, foreign_key: "user_id", source: :user
end

#  id         :integer          not null, primary key
#  company_id :integer
#  user_id    :integer
#  admin      :boolean
#  created_at :datetime
#  updated_at :datetime
class CompanyMember < ActiveRecord::Base
  belongs_to :company
  belongs_to :user
end

An user can have only one company. He can be admin of this company. A Company can have more than one admin.

so when i want to add a member to the company i do : company.members << user. it's working: when i query company.members it returns the user and the the company_member record is like {user_id: 5, company_id: 8, admin: false}

Now i want to add an user as admin: what i have to do would be this: company.admins << user then company.members should return the user same as company.admins and the company_member record should be like {user_id: 5, company_id: 8, admin: true}

It is possible through Rails associations ? Because actually, it's not working :/ : the company_member is recorded as {user_id: 5, company_id: 8, admin: false} Can you help me ?

Thanks !

I'm using Rails 4.1.3 and ruby 2.1.2

Upvotes: 4

Views: 585

Answers (2)

stacker
stacker

Reputation: 270

I thought what if anyone is interested:

In Company, the association admins must be like this:

class Company < ActiveRecord::Base
  has_many :company_members
  has_many :members, through: :company_members, source: :user
  has_many :admins, -> {where(company_members: {admin: true })}, through: :company_members, source: :user
end

Now I have the expected behavior when i do

company.admins << user

It adds instanciate a company_member with admin: true (which defaults to false)

so I don't need the suggested callback from SampritiPanda but thanks dude !

Upvotes: 0

Zero Fiber
Zero Fiber

Reputation: 4465

When you specify a scope in a has_many relationship, you only customize the query used by has_many. So if you add a User to the list of admins for a company, it does not make it an admin.

You can achieve this by setting a association callback. Rails passes the object being added or removed to the callback, which you can set as the admin.

class Company < ActiveRecord::Base
  has_many :company_members
  has_many :members, through: :company_members, foreign_key: "user_id", source: :user
  has_many :admins, -> {where admin: true }, through: :company_members, foreign_key: "user_id", source: :user, after_add: :set_user_as_admin

  def set_user_as_admin(user)
    user.company_member.update(admin: true)
  end
end

Upvotes: 1

Related Questions