ruby-on-railsruby-on-rails-6contact-form

ActionController::ParameterMissing in StaticPagesController#contact (Ruby on Rails 6)


How to solve this missing params?

StaticPagesController:

class StaticPagesController < ApplicationController
  def home
  end

  def about
    @hero_title = 'about_us'
  end

  def services
    @hero_title = 'services'
  end
  
  def contact
    @hero_title = 'contact'
    
    @contact = Contact.new(contact_params)
    if @contact.save 
      # flash[:success] = "Message sent!"
      redirect_to contact_url(locale: I18n.locale)
    else
      render 'contact'
    end
  end

  def gallery
    @hero_title = 'gallery'
  end

  private

    def contact_params
      params.require(:contact).permit(:name, :email, :subject, :message)
    end
end

ApplicationController:

class ApplicationController < ActionController::Base
  around_action :switch_locale

  def switch_locale(&action)
    locale = params[:locale] || I18n.default_locale
    I18n.with_locale(locale, &action)
  end
  
  def default_url_options
    { locale: I18n.locale }
  end
end

contact.html.erb:

<form action="<%= contact_path %>" accept-charset="UTF-8" method="post">
            <%= hidden_field_tag :authenticity_token, form_authenticity_token %>
            <div class="row g-3">
              <div class="col-md-6">
                <div class="form-floating">
                  <input type="text" class="form-control" id="name" name="contact[name]" placeholder="Your Name">
                  <label for="name">Your Name</label>
                </div>
              </div>
              <div class="col-md-6">
                <div class="form-floating">
                  <input type="email" class="form-control" id="email" name="contact[email]" placeholder="Your Email">
                  <label for="email">Your Email</label>
                </div>
              </div>
              <div class="col-12">
                <div class="form-floating">
                  <input type="text" class="form-control" id="subject" name="contact[subject]" placeholder="Subject">
                  <label for="subject">Subject</label>
                </div>
              </div>
              <div class="col-12">
                <div class="form-floating">
                  <textarea class="form-control" placeholder="Leave a message here" id="message" name="contact[message]" style="height: 100px"></textarea>
                  <label for="message">Message</label>
                </div>
              </div>
              <div class="col-12">
                <button class="btn btn-primary w-100 py-3" type="submit">Send Message</button>
              </div>
            </div>
          </form>

routes:

Rails.application.routes.draw do
  scope "(:locale)", locale: /en|id/ do
    root 'static_pages#home'
    get  '/about',    to: 'static_pages#about'
    get  '/services', to: 'static_pages#services'
    get  '/contact',  to: 'static_pages#contact'
    post  '/contact',  to: 'static_pages#contact'
    get  '/gallery',  to: 'static_pages#gallery'
  end
end

error: ActionController::ParameterMissing (param is missing or the value is empty: contact):

app/controllers/static_pages_controller.rb:27:in contact_params' app/controllers/static_pages_controller.rb:16:in contact' app/controllers/application_controller.rb:6:in `switch_locale'

def contact_params
    params.require(:contact).permit(:name, :email, :subject, :message)
end

Please help me to fix this error

I expect contact form is not error anymore


Solution

  • I think your Problem is that you don't know the rails Syntax. Yes you can put new and show on the same route but why? You should do multiple Routes (CRUD), and then you don't get your contact_params error. Because your code tries in the new method to input contact_params. But you haven't contact_params at the first time when you open the page.

    So please make multiple Routes like this: Static Pages Controller:

      def contact
        @hero_title = 'contact'
    
        @contact = Contact.new()
      end
    
      def contact_show
        @contact = Contact.find(params[:id])
        render json: @contact, status: :ok
      end
    
      def contact_create
    
        @contact = Contact.new(contact_params)
        if @contact.save
          # flash[:success] = "Message sent!"
          redirect_to contact_show_url(@contact, locale: I18n.locale)
        else
          render 'contact'
        end
      end
    

    Routes:

      scope "(:locale)", locale: /en|id/ do
        get  '/contact',  to: 'static_pages#contact'
        post  '/contact_create',  to: 'static_pages#contact_create'
        get  '/contact_show/:id',  to: 'static_pages#contact_show'
      end
    

    Like I mentioned before you can put show and new in the same method /route but you should have another route for create.