3

我有以下模型:团队、成员、分配、角色

Team 模型有_many 成员。每个成员通过分配有_many 角色。角色分配是队长和跑步者。我还使用 Member 模型安装了 devise 和 CanCan。

我需要做的是限制每个团队最多有 1 名队长和 5 名跑步者。

我找到了这个例子,它似乎在一些定制后工作,但在更新('teams/1/members/4/edit')。它不适用于创建('teams/1/members/new')。但是我的其他验证(验证 :role_ids, :presence => true )确实适用于更新和创建。任何帮助,将不胜感激。

更新:我发现这个例子似乎与我的问题相似,但我似乎无法让它适用于我的应用程序。

问题的根源似乎在于在验证之前和期间如何执行计数(或大小)。

例如:

更新记录时...它检查团队中有多少跑步者并返回计数。(即 5)然后,当我选择要添加到成员的角色时,它会从数据库中获取已知计数(即 5)并添加建议的更改(即 1),然后运行验证检查。(Team.find(self.team_id).members.runner.count > 5) 这很好用,因为它返回的值是 6 和 6 > 5,所以建议的更新会在不保存的情况下失败并给出错误。

但是当我尝试在团队中创建新成员时......它会检查团队中有多少跑步者并返回计数。(即 5)然后,当我选择要添加到成员的角色时,它会从数据库中获取已知计数(即 5),然后运行验证检查而不考虑建议的更改。这不起作用,因为它返回值 5 known runner 和 5 = 5 因此建议的更新通过并且新成员和角色被保存到数据库中而没有错误。

会员型号:

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

成员控制器:

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_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 %>
4

1 回答 1

1

尝试

class Member < ActiveRecord::Base
  ...

  def validate_runner_count
     if self.team.members.runner.count > 5
       errors.add(:role_id, 'Error - Max runner limit reached')
     end
  end

  def validate_captain_count
     if self.team.members.captain.count > 1
       errors.add(:role_id, 'Error - Max captain limit reached')
     end
  end
end
于 2012-10-29T13:25:23.373 回答