基于用户角色的属性验证

时间:2018-09-20 16:37:08

标签: ruby-on-rails ruby

我希望验证属性amount。每个管理员用户角色允许的数量不同。因此,需要根据更新资金的管理员(而不是资金所属的用户)的角色来更新(或不更新)。

  class UserFund
    validate :validate_amount

      def validate_amount
        if current_user.admin?
          amount <= 100
        elsif current_user.cs?
          amount <= 25
        elsif current_user.staff?
          amount <= 15
        end
      end
    end

User has_many :user_funds UserFund belongs_to :user 但 current_user!=用户。 编辑资金的用户(current_user)是admin,而不是资金所属的用户。

但是我不应该在模型中使用current_user。解决此问题的最佳做法是什么?

3 个答案:

答案 0 :(得分:1)

如果current_user与将要保存的UserFund对象没有关系,那么我认为将验证器转换为单独的方法会更好。并且由于该方法隐含了有关User类的知识,因此将其作为实例方法移至User类是有意义的(或者如果admin和user不同,则移至admin类):

class User < ApplicationRecord
  def amount_too_big?(amount)
    return admin? && amount > 100 || cs? && amount > 25 || staff? && amount > 15
  end
end

并在保存UserFund对象之前在控制器中调用此方法:

if current_user.amount_too_big?(amount)
  # Render error message about unacceptably big funds 
  return
end

为什么呢? current_user对象很可能是由某些控制器过滤器定义的,因此它仅在控制器和视图中可用。 UserFund对象只能访问属于User模型的资金。只有通过调用其他方法并传递current_user作为参数,才能从UserFund访问current_user

其他要点:从Rails控制台运行时,未定义current_userUserFund对象将不知道current_user是什么,因此根本无法使用它。

答案 1 :(得分:0)

如果此验证基于同一模型中的数据,则可以跳过current_user。例如,假设此验证适用于具有实例方法Useradmin?cs?的{​​{1}}模型,则可以写为:

staff?

但是,ActiveRecord的class User < ApplicationRecord validate :validate_amount def validate_amount if admin? amount <= 100 elsif cs? amount <= 25 elsif staff? amount <= 15 end end end 方法将验证错误集合为空,因此当您希望验证失败时,您的自定义验证方法应向其中添加错误:

valid?

更多详细信息在这里: https://guides.rubyonrails.org/active_record_validations.html#custom-methods

答案 2 :(得分:0)

我认为这对于验证https://guides.rubyonrails.org/active_record_validations.html#on

的“上下文”是一个很好的例子

您可以在不同的上下文(即不同的角色)上定义不同的验证。

validate :admin_amount, on: :admin
validate :cs_amount, on: :cs
validate :staff_amount, on: :staff

def admin_amount
  errors.add(:amount, 'is too long') if amount > 100
end

def cs_amount
  errors.add(:amount, 'is too long') if amount > 25
end

def staff_amount
  errors.add(:amount, 'is too long') if amount > 15
end
#of course, you can DRY this a lot, i'm just repeating a lot of code to make it clearer

现在,您可以使用“上下文”键保存记录(或检查是否有效)。

fund = UserFund.new
fund.save(context: current_user.role.to_sym) #assuming the role is a string
# of fund.valid?(context: current_user.role.to_sym)