I've got the following models: Team, Member, Assignment, Role
The Team model has_many Members. Each Member has_many roles through assignments. Role assignments are Captain and Runner. I have also installed devise and CanCan using the Member model.
What I need to do is limit each Team to have a max of 1 captain and 5 runners.
I found this example, and it seemed to work after some customization, but on update ('teams/1/members/4/edit'). It doesn't work on create ('teams/1/members/new'). But my other validation (validates :role_ids, :presence = true
) does work on both update and create. Any help would be appreciated.
Update: I've found this example that would seem to be similar to my problem but I can't seem to make it work for my app.
It seems that the root of the problem lies with how the count (or size) is performed before and during validation. 
For Example:
When updating a record... 
It checks to see how many runners there are on a team and returns a count. (i.e. 5) Then when I select a role(s) to add to the member it takes the known count from the database (i.e. 5) and adds the proposed changes (i.e. 1), and then runs the validation check. (Team.find(self.team_id).members.runner.count  5) This works fine because it returns a value of 6 and 6  5 so the proposed update fails without saving and an error is given.
But when I try to create a new member on the team...
It checks to see how many runners there are on a team and returns a count. (i.e. 5) Then when I select a role(s) to add to the member it takes the known count from the database (i.e. 5) and then runs the validation check WITHOUT factoring in the proposed changes. This doesn't work because it returns a value of 5 known runner and 5 = 5 so the proposed update passes and the new member and role is saved to the database with no error.
Member Model:
class Member < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  attr_accessible :password, :password_confirmation, :remember_me
  attr_accessible :age, :email, :first_name, :last_name, :sex, :shirt_size, :team_id, :assignments_attributes, :role_ids
  belongs_to :team
  has_many :assignments, :dependent => :destroy
  has_many :roles, through: :assignments
    accepts_nested_attributes_for :assignments
  scope :runner, joins(:roles).where('roles.title = ?', "Runner")
  scope :captain, joins(:roles).where('roles.title = ?', "Captain")
  validate :validate_runner_count
  validate :validate_captain_count
  validates :role_ids, :presence => true
  def validate_runner_count
     if Team.find(self.team_id).members.runner.count > 5
       errors.add(:role_id, 'Error - Max runner limit reached')
     end
  end
  def validate_captain_count
     if Team.find(self.team_id).members.captain.count > 1
       errors.add(:role_id, 'Error - Max captain limit reached')
     end
  end
  def has_role?(role_sym)
    roles.any? { |r| r.title.underscore.to_sym == role_sym }
  end
end
Member Controller:
class MembersController < ApplicationController
  load_and_authorize_resource :team
  load_and_authorize_resource :member, :through => :team
  before_filter :get_team
  before_filter :initialize_check_boxes, :only => [:create, :update]
  def get_team
    @team = Team.find(params[:team_id])
  end
  def index
    respond_to do |format|
      format.html # index.html.erb
      format.json { render json: @members }
    end
  end
  def show
    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @member }
    end
  end
  def new
    respond_to do |format|
      format.html # new.html.erb
      format.json { render json: @member }
    end
  end
  def edit
  end
  def create
    respond_to do |format|
      if @member.save
        format.html { redirect_to [@team, @member], notice: 'Member was successfully created.' }
        format.json { render json: [@team, @member], status: :created, location: [@team, @member] }
      else
        format.html { render action: "new" }
        format.json { render json: @member.errors, status: :unprocessable_entity }
      end
    end
  end
  def update
    respond_to do |format|
      if @member.update_attributes(params[:member])
        format.html { redirect_to [@team, @member], notice: 'Member was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: "edit" }
        format.json { render json: @member.errors, status: :unprocessable_entity }
      end
    end
  end
  def destroy
    @member.destroy
    respond_to do |format|
      format.html { redirect_to team_members_url }
      format.json { head :no_content }
    end
  end
  # Allow empty checkboxes
  # http://railscasts.com/episodes/17-habtm-checkboxes
  def initialize_check_boxes 
    params[:member][:role_ids] ||= [] 
  end
end
_Form Partial
<%= form_for [@team, @member], :html => { :class => 'form-horizontal' } do |f| %>
  #...
  # testing the count...
    <ul>
    <li>Captain - <%= Team.find(@member.team_id).members.captain.size %></li>
    <li>Runner - <%= Team.find(@member.team_id).members.runner.size %></li>
    <li>Driver - <%= Team.find(@member.team_id).members.driver.size %></li>
    </ul>
    <div class="control-group">
      <div class="controls">
      <%= f.fields_for :roles do %>
      <%= hidden_field_tag "member[role_ids][]", nil %>
        <% Role.all.each do |role| %>
          <%= check_box_tag "member[role_ids][]", role.id, @member.role_ids.include?(role.id), id: dom_id(role) %>
          <%= label_tag dom_id(role), role.title %>
        <% end %>
      <% end %>
     </div> 
    </div>
  #...
<% end %>