0

Here are my models:

Team:

class Team < ActiveRecord::Base

  has_many :team_users

  has_many :users, through: :team_users

  has_many :admins, through: :team_users,
                    foreign_key: :user_id,
                    class_name: 'User',
                    source: :user,
                    conditions: ["team_users.is_admin = ?", true]
end

User:

class User < ActiveRecord::Base

  has_many :team_users

  has_many :teams, through: :team_users

  has_many :administered_teams, through: :team_users,
                                foreign_key: :user_id,
                                class_name: 'Team',
                                source: :team,
                                conditions: ["team_users.is_admin = ?", true]


end

TeamUser:

# == Schema Information
#
# Table name: team_users
#
#  id       :integer          not null, primary key
#  team_id  :integer
#  user_id  :integer
#  is_admin :boolean
#

class TeamUser < ActiveRecord::Base
  belongs_to :team
  belongs_to :user

  # Validations
  validates_presence_of :team
  validates_presence_of :user

  attr_accessible :is_admin

end

So essentially team.users and team.admins are joined through the same table. Note that to be a team.admin you must be a team.user.

My question is, how do I save is_admin in the joiner-model automatically when I append to team.admins? i.e:

irb(main):001:0> user = User.find(1)
irb(main):002:0> team = Team.create
irb(main):003:0> team.admins << user
irb(main):004:0> team.users.count
              => 1
irb(main):005:0> team.admins.count
              => 0

irb(main):007:0> y team.team_users
               - !ruby/object:TeamUser
                 attributes:
                   id: 307
                   team_id: 210
                   user_id: 1
                   is_admin: 
                     => nil

I remember vaguely seeing somewhere that has_many conditions are automatically set. But I'm not sure if this is the case for joiner models? Or perhaps I'm doing it wrong and there is a better implementation?

Update

This question seems very similar to this one.

Community
  • 1
  • 1
Nathan Kot
  • 2,392
  • 1
  • 21
  • 31

2 Answers2

1

UPDATED

Based on the suggestion given in the question you linked to in your comment to another answer, you can fix this if you assign the conditions hash to the join model instead of the has_many_through association:

class Team < ActiveRecord::Base
  # standard join model
  has_many :team_users

  # join model with conditions
  has_many :team_admins, class_name: 'TeamUser', conditions: {is_admin: true}

  # uses standard join association
  has_many :users, through: team_users

  # uses the conditional join association
  has_many :admins, through: team_admins, source: user
end

team.admins << user
team.admins.count
=> 1

ORIGINAL ANSWER

Don't append through the admins has-many-through association. Rather append like this:

team.team_users << TeamUser.new(user: user, is_admin: true)

Or you can just use the magic create_ helper method:

team.create_team_users(user: user, is_admin: true)
Community
  • 1
  • 1
PinnyM
  • 35,165
  • 3
  • 73
  • 81
  • Thanks, I'm going to use this as a workaround. But it would still be nice to have a cleaner solution... – Nathan Kot Apr 17 '13 at 20:35
  • @NathanKot: Updated based on the answer given in the other question you linked to. Essentially, the conditions won't work as you like if you put them on the has-many-through association. But it will work if you put them on a new join model association and use that for your has-many-through association. – PinnyM Apr 18 '13 at 14:28
1

Try changing the conditions option from a SQL fragment to a hash.

From Rails' API documentation:

Record creations from the association are scoped if a hash is used. has_many :posts, :conditions => {:published => true} will create published posts with @blog.posts.create or @blog.posts.build.

In your case, it would become:

has_many :administered_teams, through: :team_users,
                              foreign_key: :user_id,
                              class_name: 'Team',
                              source: :team,
                              conditions: { team_users: { is_admin: true }}
joshuadavey
  • 239
  • 3
  • 4
  • Thanks for bringing up that a hash is required in the condition, however in this case it doesn't seem to work... Seems related to [this question](http://stackoverflow.com/questions/3081764/rails-has-many-through-and-setting-property-on-join-model) (which hasn't been answered) – Nathan Kot Apr 17 '13 at 20:34