Ruby Rails SystemStackError 堆栈级别太深验证 Wicked gem

Ruby on Rails SystemStackError stack level too deep validate Wicked gem

调用 validate :method_name 导致无限循环 SystemStackError

直接内联进行验证允许验证无错误地通过。

一定是我忽略了或做错了什么...

直接在模型中而不是在 conditional_reservation_validation 中进行验证时效果很好。

导致 SystemStackError stack level too deep

的示例代码

已按照此示例构建基本流程: Building Partial Objects Step by Step

我知道这需要重构/清理。

来自模型的代码段:

validate :conditional_reservation_validation

def conditional_reservation_validation
  if created_by_admin?
    validates_presence_of :vehicle_location
    validates_presence_of :pickup, :dropoff, :departure_date, :departure_time, :passengers
  else
    if active_or_parking?
      validates_presence_of :vehicle_location
      # SystemStackError occurs when validate :parking_agreement_if_location fires
      validate :parking_agreement_if_location
    end
    if active_or_pickup?
      # additional validations
    end
  end
  # ... 
end

def parking_agreement_if_location
  if vehicle_in_special_parking_location(vehicle_location)
    if self.parking_agreement == true
      # ok
    else
      self.errors.add :base, "Must read and understand parking instructions."
    end
  end
end

def vehicle_in_special_parking_location(vehicle_location)
  parking_locations = Location.where(require_parking: true)
  if parking_locations.include?(vehicle_location)
    return true
  else
    return false
  end
end

# methods to check the step in process
def active_or_parking?
  status.include?('parking') || active?
end

调用验证:parking_agreement_if_location 触发 SystemStackError

停止错误的示例代码: 只需将代码从 :parking_agreement_if_location 方法中取出并直接内联即可停止 SystemStackError.

validate :conditional_reservation_validation

def conditional_reservation_validation
  if created_by_admin?
    validates_presence_of :vehicle_location 
    validates_presence_of :pickup, :dropoff, :departure_date, :departure_time, :passengers
  else
    if active_or_parking?
      validates_presence_of :vehicle_location
      if vehicle_location
        locations = Location.where(require_parking: true)
        if locations.include?(vehicle_location)
          if parking_agreement == true
            # ok
          else
            self.errors.add :base, "Must read and understand parking instructions."
          end
          # validate :parking_agreement_if_location
        end
      end
    end

    if active_or_pickup?
      # These methods cause SystemStackError as well...
      validate :pickup_date_in_range
      validate :pickup_date_in_future
    end
  end
end

控制器更新动作:

def update

  params[:reservation][:status] = step.to_s
  params[:reservation][:status] = 'active' if step == steps.last

  case step
    when :parking
      @reservation.assign_attributes(reservation_params)
    when :pickup
      @reservation.assign_attributes(reservation_params)
    when :billing
      @reservation.assign_attributes(reservation_params)
  end
  render_wizard @reservation
end

您使用验证的方式有误。它们需要在 class 级别调用。

您需要改用条件验证:

validates_presence_of :vehicle_location, if: :created_by_admin?
validates_presence_of :pickup, :dropoff, :departure_date, :departure_time, :passengers, if: :created_by_admin?
validates_presence_of :vehicle_location, unless: :created_by_admin?, if: :active_or_parking?
validate :parking_agreement_if_location, unless: :created_by_admin?, if: :active_or_parking?