3

У меня есть следующие модели: Team, Member, Assignment, RoleОграничение лимита валидности на листинге has_many: через

Модель команды has_many Участники. Каждый член имеет несколько ролей через назначения. Назначения ролей - капитан и бегун. Я также установил программу и CanCan, используя модель Member.

Что мне нужно сделать, это ограничить каждую команду максимальным капитаном и 5 бегунами.

Я нашел это example, и он, похоже, работал после некоторой настройки, но при обновлении ('teams/1/members/4/edit'). Он не работает над create ('teams/1/members/new'). Но моя другая проверка (validates: role_ids,: presence => true ) работает как с обновлением, так и с созданием. Любая помощь будет оценена по достоинству.

Обновление: Я нашел это example, что похоже на мою проблему, но я не могу заставить его работать для моего приложения.

Похоже, что корень проблемы заключается в том, как счет (или размер) выполняется до и во время проверки.

Для примера:

При обновлении записи ... Он проверяет, чтобы узнать, сколько бегунов есть в команде и возвращает число. (т. е. 5). Затем, когда я выбираю роль (роли) для добавления к члену, он принимает известный счет из базы данных (т. е. 5) и добавляет предлагаемые изменения (т. е. 1), а затем запускает проверку проверки. (Team.find (self.team_id) .members.runner.count> 5) Это работает отлично, потому что оно возвращает значение 6 и 6> 5, поэтому предлагаемое обновление выходит из строя без сохранения и возникает ошибка.

Но, когда я пытаюсь создать новый элемент в команде ... Он проверяет, чтобы узнать, сколько бегунов есть в команде и возвращает число. (т. е. 5). Затем, когда я выбираю роль (роли) для добавления к члену, он принимает известный счет из базы данных (т. е. 5), а затем запускает проверку проверки БЕЗ, факторизуя предлагаемые изменения. Это не работает, потому что оно возвращает значение 5 известных бегунов и 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 Частичное

<%= 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 %> 

ответ

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 
+0

I T это решение, и хотя оно работает, оно по-прежнему работает только на обновление, а не на создание. Спасибо за попытку. ** Примечание: ** Я внес небольшое изменение в оригинальную модель, которую я опубликовал, чтобы исправить ошибку. – Jeremy

+0

использовать .size вместо .count – Azi