ruby-on-railsenumsruby-on-rails-7ruby-on-rails-7.2

Ruby on Rails Enum ArgumentError


I was wondering if someone can see the obvious error I am making. I can't see it.

My Rails 7.2 application relies on an enum for :likelihood and :consequence. Unfortunately, in testing, I am getting an error.

I have followed this article exactly https://blog.saeloun.com/2021/02/26/rails-introduces-new-syntax-for-enum/ and can't see why i am getting the argumenterror.

I am sure I have made a simple error somewhere, but i just cant see it.

I have layed out the error, model, controller and form below. Let me know if you require more info.

thank you in advance

The Error

09:43:32 web.1    | Processing by PotentialHazardsController#create as TURBO_STREAM
09:43:32 web.1    |   Parameters: {"authenticity_token"=>"[FILTERED]", "potential_hazard"=>{"description"=>"test dws", "likelihood"=>"4", "consequence"=>"4", "procedure_id"=>"1"}, "commit"=>"Create Potential hazard"}
09:43:32 web.1    | Completed 500 Internal Server Error in 2ms (ActiveRecord: 0.0ms (0 queries, 0 cached) | GC: 0.2ms)
09:43:32 web.1    | 
09:43:32 web.1    | 
09:43:32 web.1    |   
09:43:32 web.1    | ArgumentError ('4' is not a valid consequence):
09:43:32 web.1    |   
09:43:32 web.1    | app/controllers/potential_hazards_controller.rb:24:in `create'

The Model

class PotentialHazard < ApplicationRecord
  belongs_to :procedure
  has_many :management_methods

  enum :likelihood, [ :rare, :unlikely, :possible, :likely, :almost_certain ], prefix: true, scopes: false
  enum :consequence, [ :insignificant, :minor, :moderate, :major, :catastrophic ], prefix: true, scopes: false
end 

The Controller

class PotentialHazardsController < ApplicationController
      before_action :set_potential_hazard, only: %i[ show edit update destroy ]
    
      # POST /potential_hazards or /potential_hazards.json
      def create
        @potential_hazard = PotentialHazard.new(potential_hazard_params)
    
        respond_to do |format|
          if @potential_hazard.save
            format.html { redirect_to @potential_hazard, notice: "Potential hazard was successfully created." }
            format.json { render :show, status: :created, location: @potential_hazard }
          else
            format.html { render :new, status: :unprocessable_entity }
            format.json { render json: @potential_hazard.errors, status: :unprocessable_entity }
          end
        end
      end
    
      # PATCH/PUT /potential_hazards/1 or /potential_hazards/1.json
      def update
        respond_to do |format|
          if @potential_hazard.update(potential_hazard_params)
            format.html { redirect_to @potential_hazard, notice: "Potential hazard was successfully updated." }
            format.json { render :show, status: :ok, location: @potential_hazard }
          else
            format.html { render :edit, status: :unprocessable_entity }
            format.json { render json: @potential_hazard.errors, status: :unprocessable_entity }
          end
        end
      end

      private
        # Use callbacks to share common setup or constraints between actions.
        def set_potential_hazard
          @potential_hazard = PotentialHazard.find(params[:id])
        end
    
        # Only allow a list of trusted parameters through.
        def potential_hazard_params
          params.require(:potential_hazard).permit(:description, :consequence, :likelihood, :procedure_id, :position)
        end
    end

The Form

<%= form_for @potential_hazard do |form| %>
            <% if @potential_hazard.errors.any? %>
                <div id="error_explanation">
                <h2><%= pluralize(@potential_hazard.errors.count, "error") %> prohibited this potential_hazard from being saved:</h2>

                <ul>
                <% @potential_hazard.errors.full_messages.each do |message| %>
                    <li><%= message %></li>
                <% end %>
                </ul>
                </div>
            <% end %>

            <div class="form-floating mb-3">
                <%= form.text_field :description, id: "description",class: 'form-control', placeholder: 'Describe the potential hazard' %>
                <label class="form-label" for="description">Description</label>
            </div>

            <div class="form-floating mb-3">
                <%= form.select :likelihood, options_for_select(PotentialHazard.likelihoods.map {|k, v| [k.humanize.capitalize, v]}), {include_blank: false }, {class: 'form-select'} %>
                <label class="form-label" for="description">Potential Hazard Likelihood</label>

            </div>

            <div class="form-floating mb-3">
                <%= form.select :consequence, options_for_select(PotentialHazard.consequences.map {|k, v| [k.humanize.capitalize, v]}), {include_blank: false }, {class: 'form-select'} %>
                <label class="form-label" for="description">Potential Hazard Consequence</label>

            </div>

            <%= form.hidden_field :procedure_id, value: procedure.id %>

            <div class="mb-3">
                <%= form.submit class: 'btn btn-primary' %>
            </div>
        <% end %>

The Migratrion/DB

create_table "potential_hazards", force: :cascade do |t|
    t.string "description"
    t.bigint "procedure_id", null: false
    t.integer "position"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.integer "likelihood", default: 0
    t.integer "consequence", default: 0
    t.index ["procedure_id"], name: "index_potential_hazards_on_procedure_id"
  end

Solution

  • You need to send value from enum's list

    Instead of 4 - send catastrophic