【问题标题】:Triggering only certain validations on a particular action with Rails and devise使用 Rails 仅触发特定操作的某些验证并设计
【发布时间】:2021-08-15 08:40:39
【问题描述】:

我有和管理员模型与设计:

class Administrator < ApplicationRecord
     validate :max_num_admins, on: :create
     devise :invitable, :database_authenticatable,
         :recoverable, :rememberable, :validatable
     
       def max_num_admins
         self.errors.add(:base,
          I18n.t(
           'activerecord.errors.models.administrator.max_reached'
          )
         ) if Administrator.count > 3
        end
      end

“帐户所有者”可以通过管理仪表板添加管理员,这具有邀请管理员的效果(设计邀请方法邀请!):

def create
  resource = resource_class.new(resource_params)
  authorize_resource(resource)
  if resource.valid?
    Administrator.invite!(resource_params)
    redirect_to(
      [namespace, resource],
      notice: translate_with_resource('create.success')
    )
  else
    render :new, locals: {
      page: Administrate::Page::Form.new(dashboard, resource)
    }
  end
end

如您所见,我想检查我的记录是否有效,特别是如果该帐户的管理员记录不超过 3 条。问题是当我在resource(管理员)上调用valid? 时,我总是得到错误,因为在这个阶段,邀请管理员的唯一必要参数是有效的电子邮件,但会触发设计验证,因此我收到一个错误没有设置密码。

什么是保持触发此操作的电子邮件和 max_num_admins 验证而不是来自设计的密码的一种干净的方法?

【问题讨论】:

    标签: ruby-on-rails validation devise devise-invitable


    【解决方案1】:

    验证链是一个回调链,验证链的结果毕竟是errors(如果errors.empty?,则返回true),没有办法过滤(或fail early),所以当你模型设置设计,所有设计的验证都添加到验证链中,没有办法过滤掉它们,但删除设计。所以我想出了一个想法,你应该定义一个special validation范围,它将附加在验证链的末尾并强制errors.clear(这样它就会忽略以前的设计验证),看看下面的代码:

    class User < ActiveRecord::Base
     devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :validatable,
             :confirmable
        
     validate :max_num_admins, on: [:create, :special] # should be the last validation below devise validations
    
     def max_num_admins
       if self.validation_context == :special
         errors.clear # that mean previous validations (not only devise) be ignored
       end
         
       self.errors.add(:base,
         I18n.t(
          'activerecord.errors.models.administrator.max_reached'
         )
       ) if Administrator.count > 3
     end
    end
    

    然后

    def create
      # ...
      if resource.valid?(:special) # validate at special scope
      end
    end
    
    if resource.valid? # this will work as normal
    

    更新

    无需触及任何现有的验证,您可以在验证链的末尾添加一个验证special,它将slice!您要检查的那些错误:

    class User
     # ...
     validate :max_num_admins, on: [:create, :special]
     validate :special, on: [:special]
    
     def max_num_admins  
       self.errors.add(:max_num_admins,
         I18n.t(
          'activerecord.errors.models.administrator.max_reached'
         )
       ) if Administrator.count > 3
     end
    
     private
     def special
       # removes all errors except the given keys. 
       # so if you want to check email and max_num_admins
       errors.slice!(
        :email, 
        :max_num_admins
       )
     end
    end
    

    然后

    if resource.valid?(:special) # validate email and max_num_admins
    if resource.valid? # check as normal password, email, ..., max_num_admins
    

    注意 弃用警告:ActiveModel::Errors#slice!已弃用并将在 Rails 6.2 中删除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-03-02
      • 1970-01-01
      • 2019-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多