仅在满足特定条件时才运行一组验证的最佳实践?

时间:2018-07-31 06:15:23

标签: ruby-on-rails validation ruby-on-rails-5.2

我有一个Review模型,该模型具有3个验证,只有在评论的status"submitted"时才应运行。这是我目前的模特...

    class Review < ApplicationRecord
      enum status: { pending: 0, submitted: 1 }
      ...

      belongs_to :reviewable, polymorphic: true
      belongs_to :user

      validates :title, presence: true, length: { in: 5..50 }, if: -> { status == "submitted" }
      validates :description, length: { in: 10..500 }, if: -> { status == "submitted" }
      validates :stars, presence: true, inclusion: { in: (1..5) }, if: -> { status == "submitted" }
      ...
    end

将生成一个新的审阅,状态为“待处理”。创建新评论时,我仍然需要验证reviewableuser是否与评论相关联(因此,我不能在create动作中一起跳过所有验证)...但仅用户更新评论时需要验证titledescriptionstars

有没有一种方法可以将三个验证(标题,说明和星号)包装成条件,以便仅在用户更新评论(将statuspendingsubmitted)...而不是全部调用if: -> { status == "submitted" }

1 个答案:

答案 0 :(得分:2)

第一个简化是,您可以使用符号代替内联块:

  validates :title, presence: true, length: { in: 5..50 }, if: :submitted?
  validates :description, length: { in: 10..500 }, if: :submitted?
  validates :stars, presence: true, inclusion: { in: (1..5) }, if: :submitted?

通常,您将定义一个匹配的方法:

  def submitted?
    status == "submitted"
  end

..但您不需要在这里,因为enum免费提供了这种方法。


如果您真的想挤压它,还有一个更晦涩的选择:

  with_options if: -> { status == "submitted" } do |x|
    x.validates :title, presence: true, length: { in: 5..50 }
    x.validates :description, length: { in: 10..500 }
    x.validates :stars, presence: true, inclusion: { in: (1..5) }
  end

(由于只有一个副本,所以我切换回了该块,尽管在这种情况下我仍然倾向于使用if: :submitted?格式。)

with_options并不是一种特别知名或广泛使用的方法,它确实存在,但是我只建议在非常不寻常的情况下使用它。