Search code examples
ruby-on-railsrubysavesimple-formform-for

Unpermitted parameters: :email, :address


I need a button such that when I click it, the name attribute must be be updated in user table and an address must be saved in address table. address table belongs to user table. Now my error is that when I click submit button i am not able to save the address but my name gets updated in the user table. Can anyone help with it?

Controller Code

class ProfileController < ApplicationController
  before_action :set_user, only: %i[index update_profile]

  def index; end

  def create
      @address = Address.new(address_params)
      respond_to do |format|
        puts'-=-==-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-='
        if @address.save
          format.html { redirect_to profile_index_path, notice: 'Address was successfully created.' }
        else
          format.html { render :new }
        end
      end
    end

  def update_profile
    respond_to do |format|
      if @user.update(user_params)
        format.html { redirect_to profile_index_path, notice: 'Profile was successfully updated.' }
      else
        format.html { render :index }
      end
    end
  end

private

  def set_user
    @user = User.find(current_user.id)
    @user.address || @user.build_address
  end

  def user_params
    params.require(:user).permit(:name, address_attributes: %i[area state country])
  end

  def address_params
     params.require(:address).permit(address: %i[area state country])
   end
end

Model

address.rb

class Address < ApplicationRecord
  belongs_to :user
end

user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_one :address, dependent: :destroy

  validates :name, presence: true
  def admin?
    true
  end
end

View Code

<%= form_for(@user, url: { action: 'update_profile' }, html: { class: 'm-form m-form--fit m-form--label-align-right' } ) do |f| %>
  <% if @user.errors.any? %>
    <h4><%= pluralize(@user.errors.count, "error") %>
      prohibited this profile from being saved:</h4>
    <ul>
      <% @user.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
    </ul>
  <% end %>
  <div class="form-group m-form__group row">
    <label for="name" class="col-2 col-form-label">
      Name
    </label>
    <div class="col-7">
      <%= f.text_field :name, class: 'form-control m-input', placeholder: 'Full Name' %>
    </div>
  </div>
  <div class="m-form__seperator m-form__seperator--dashed m-form__seperator--space-2x"></div>
  <%= f.fields_for @user.address do |a| %>

  <div class="form-group m-form__group row">
    <label for="example-text-input" class="col-2 col-form-label">
      Address
    </label>
    <div class="col-7">
      <%= a.text_field :area, class: 'form-control m-input', placeholder: 'Address' %>
    </div>
  </div>
  <div class="form-group m-form__group row">
    <label for="example-text-input" class="col-2 col-form-label">
      City
    </label>
    <div class="col-7">
      <%= a.text_field :city, class: 'form-control m-input', placeholder: 'City' %>
    </div>
  </div>
  <div class="form-group m-form__group row">
    <label for="example-text-input" class="col-2 col-form-label">
      State
    </label>
    <div class="col-7">
      <%= a.text_field :state, class: 'form-control m-input', placeholder: 'State' %>
    </div>
  </div>
<% end %>
<%= f.submit 'Save Changes', class: 'btn btn-accent m-btn m-btn--air m-btn--custom' %>
&nbsp;&nbsp;
<%= link_to 'Back', root_path, class: 'btn btn-secondary m-btn m-btn--air m-btn--custom' %>

routes.rb

resources :profile do
    collection do
      patch 'update_profile'
      get 'update_profile'
    end
  end

Terminal log

Started PATCH "/profile/update_profile" for 127.0.0.1 at 2018-05-07 12:33:15 +0530
Processing by ProfileController#update_profile as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"AJZaELC5GwhOsBCKRZMQMpKySMxNpIIHgNpFBuS1KbBFSs61ByG7RAxVXV8Rd7QXaQ7Htzgyty4Z1uclocXOhQ==", "user"=>{"name"=>"Karthi", "email"=>"suriya@gmail.com", "address"=>{"area"=>"L1, 54th St. & 9th Ave. Ashok Nagar", "city"=>"Chennai", "state"=>"Tamil Nadu", "country"=>"India", "postcode"=>"600083"}}, "commit"=>"Save Changes"}
  User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 7 ORDER BY `users`.`id` ASC LIMIT 1
  User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1
  Address Load (0.3ms)  SELECT  `addresses`.* FROM `addresses` WHERE `addresses`.`user_id` = 7 LIMIT 1
Unpermitted parameter: :address
   (0.1ms)  BEGIN
   (0.2ms)  COMMIT
Redirected to http://localhost:3000/profile
Completed 302 Found in 7ms (ActiveRecord: 1.2ms)


Started GET "/profile" for 127.0.0.1 at 2018-05-07 12:33:15 +0530
Processing by ProfileController#index as HTML
  User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 7 ORDER BY `users`.`id` ASC LIMIT 1
  User Load (0.2ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 7 LIMIT 1
  Address Load (0.2ms)  SELECT  `addresses`.* FROM `addresses` WHERE `addresses`.`user_id` = 7 LIMIT 1
  Rendering profile/index.html.erb within layouts/application
  Rendered profile/_profile_card.html.erb (0.3ms)
  Rendered profile/_profile_detail.html.erb (1.7ms)
  Rendered profile/index.html.erb within layouts/application (3.4ms)
  Rendered layouts/_web_font.html.erb (0.3ms)
  Rendered layouts/_google_analytics.html.erb (0.2ms)
  Rendered layouts/_header.html.erb (1.8ms)
  Rendered layouts/_alerts.html.erb (0.4ms)
Completed 200 OK in 32ms (Views: 28.7ms | ActiveRecord: 0.7ms)

Solution

  • I have omitted a few methods unrelated to the error and made some changes to the controller:

    class ProfileController < ApplicationController
      def create
        @address = Address.new(address_params)
        respond_to do |format|
          if @address.save
            format.html { redirect_to profile_index_path, notice: 'Address was successfully created.' }
          else
            format.html { render :new }
          end
        end
      end
    
      def update_profile
        respond_to do |format|
          if @user.update(user_params)
            format.html { redirect_to profile_index_path, notice: 'Profile was successfully updated.' }
          else
            format.html { render :index }
          end
        end
      end
    
      private
    
      def user_params        
        # changed `address_attributes` to `address` as the params in request contains key `address`
        params.require(:user).permit(:name, address: %i[area state country])
      end
    
      def address_params
        # permit the attributes directly instead of nesting them under another `address` key
        params.require(:address).permit(*%i[area state country])
      end
    end
    

    Let me know if it doesn't work.