ruby-on-railsrubywicked-gem

Ruby on Rails SystemStackError stack level too deep validate Wicked gem


Calling validate :method_name causes an infinite loop SystemStackError.

Doing the validation directly inline allows the validation to pass without error.

There must be something I'm overlooking or doing wrong...

The validations worked fine when doing them directly in the model instead of within the conditional_reservation_validation.

Example code that causes SystemStackError stack level too deep

The basic process has been built following this example: Building Partial Objects Step by Step

I know this needs to be refactored / cleaned up.

Snippet from model:

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

Calling validate :parking_agreement_if_location triggers a SystemStackError

Example code that stops the error: Just taking the code out of the :parking_agreement_if_location method and putting it directly inline stops the 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

Controller update action:

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

Solution

  • You are using validations wrong way. They need to be invoked on class level.

    You need to use conditional validations instead:

    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?