我希望验证属性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
。解决此问题的最佳做法是什么?
答案 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_user
。 UserFund
对象将不知道current_user
是什么,因此根本无法使用它。
答案 1 :(得分:0)
如果此验证基于同一模型中的数据,则可以跳过current_user
。例如,假设此验证适用于具有实例方法User
,admin?
和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)