Search code examples
ruby-on-railsangular4-forms

ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError)


I have come across so many questions on this, but I could not find a solution from them. The customers_controller.rb is like so:

def create
@customers = Customer.new(params)
respond_to do |format|
  if @customers.save
    format.json { render json: @customers.to_json }
  else
    format.json { render json: @customers.errors,
      status: :unprocessable_entity }
  end
end
end

class Customer < ActiveRecord::Base
end

The models/customer.rb is like so:

class Customer < ActiveRecord::Base
end

params = ActionController::Parameters.new({
  customer: {
    first_name: "Godson",
    last_name:  "Chukwu",
    username:   "Son",
    email:      "[email protected]"
 }
})
permitted = params.require(:customer).permit(:first_name, :last_name,                  :username, :email)
permitted
permitted.permitted?
Customer.first.update!(permitted)

The front end side with packs/customers.js angular 4 code is like so:

import "hello_angular/polyfills";
import { Component, NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
import { Http,Response, HttpModule, Headers, RequestOptions } from     "@angular/http";
import                        "rxjs/add/operator/map";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

   var CustomerFormComponent = Component({
     selector: "shine-customer-form",
     template: '<header class="panel-heading">
       <h1 class="h3">
         Customer 
       </h1>
     </header>
     <section class="panel-body">
       <div class="container">
         <form novalidate #customerRef="ngForm"  (ngSubmit)="submit(customerRef.value)">
          <div class="row">
            <div class="col-md-3 form-group">
              <label class="sr-only" for="first-name">
                First Name 
              </label> 
              <input type="text" class="form-control" name="first_name" 
                     placeholder="First name" ngModel #first_nameRef="ngModel"> 
            </div>
            <div class="col-md-3 form-group">
              <label class="sr-only" for="last-name">Last Name</label>
              <input type="text" class="form-control" name="last_name"
                        placeholder="Last name" ngModel #last_nameRef="ngModel">
            </div>
            <div class="col-md-3 form-group">
              <label class="sr-only" for="username">Username</label>
              <input type="text" class="form-control" name="username" 
                        placeholder="Username" ngModel #usernameRef="ngModel">
            </div>
            <div class="col-md-3 form-group">
              <label class="sr-only" for="email">Email</label>
              <input type="text" class="form-control" name="email" 
                      placeholder="Email" ngModel #emailRef="ngModel">
            </div>
          </div>
          <button type="submit" class="btn btn-primary">Submit</button>
        </form>
        <pre>{{customerRef.value | json }}<`enter code here`/pre>
      </div>
    </section>
    '
    }).Class({
    constructor: [
      Http,
      function(http) {
        this.keywords = null;
        this.customer = null;
        this.http      = http;
      }
    ],
    submit: function(customer, value){
    var headers = new Headers('authentication', `wsWPhTlJAmt1IcyNq1FCyivsAVhHq1iDCKRXOgOQock`);
      var headers = new Headers({ 'Content-Type': 'application/json'} );
      var options = new RequestOptions({ headers: headers});
      var body = JSON.stringify(customer);

      //var options = new RequestOptions({headers: headers});

      var create = {};
      //var body = JSON.stringify(customer);
      //create[customer] = value;
      this.http.post(
        "/customers", body, options
      )
      .map(function(Response){
        this.Response.json();
      })
      .subscribe(
        function(response) {
          this.response.json();
          console.log('receive response');
        },

        function(response) {
          window.alert(response);
        }
      );
    }
});

var CustomerAppModule = NgModule({
imports:      [ BrowserModule,
                FormsModule,
                HttpModule
             ],
declarations: [ CustomerFormComponent ],
bootstrap:    [ CustomerFormComponent ]
})
.Class({
constructor: function() {}
});

platformBrowserDynamic().bootstrapModule(CustomerAppModule);

Below is an output in my console:

16:18:20 rails.1   | app/controllers/customers_controller.rb:27:in `create'
16:30:55 rails.1   | Started GET "/customers" for 127.0.0.1 at 2017-08-10 16:30:55 +0100
16:30:56 rails.1   | Processing by CustomersController#index as HTML
16:30:57 rails.1   |   Customer Load (28.9ms)  SELECT  "customers".* FROM "customers" ORDER BY "customers"."id" ASC LIMIT $1  [["LIMIT", 1]]
16:30:57 rails.1   |    (0.3ms)  BEGIN
16:30:57 rails.1   |    (0.4ms)  COMMIT
16:30:57 rails.1   |   Rendering customers/index.html.erb within layouts/application
16:30:57 rails.1   |   Rendered customers/index.html.erb within layouts/application (72.5ms)
16:30:57 rails.1   | Completed 200 OK in 786ms (Views: 329.2ms | ActiveRecord: 99.1ms)
16:30:57 rails.1   | 
16:30:57 rails.1   | 
16:32:56 rails.1   | Started POST "/customers" for 127.0.0.1 at 2017-08-10 16:32:56 +0100
16:32:56 rails.1   | Processing by CustomersController#create as HTML
16:32:56 rails.1   |   Parameters: {"first_name"=>"Dan", "last_name"=>"Nwa", "username"=>"Sola", "email"=>"[email protected]", "customer"=>{"first_name"=>"Dan", "last_name"=>"Nwa", "email"=>"[email protected]", "username"=>"Sola"}}
16:32:56 rails.1   | Can't verify CSRF token authenticity.
16:32:56 rails.1   | Completed 500 Internal Server Error in 1ms (ActiveRecord: 0.0ms)
16:32:56 rails.1   | 
16:32:56 rails.1   | 
16:32:56 rails.1   |   
16:32:56 rails.1   | ActiveModel::ForbiddenAttributesError (ActiveModel::ForbiddenAttributesError):
16:32:56 rails.1   |   
16:32:56 rails.1   | app/controllers/customers_controller.rb:27:in `create'

The network preview request parameter in firefox browser is like so:

Request

Parameters:

{"first_name"=>"Dan", "last_name"=>"Nwa", "username"=>"Sola", "email"=>"[email protected]", "customer"=>{"first_name"=>"Dan", "last_name"=>"Nwa", "email"=>"[email protected]", "username"=>"Sola"}}

Where am I getting it wrong?


Solution

  • Because you are submitting this from 'Angular' you are not passing a Cross-Site Request Forgery (CSRF) token.

    You can fix this many ways, but two options are.

    In your application_controller.rb add

    class ApplicationController < ActionController::Base
      protect_from_forgery with: :null_session
    end
    

    Or in your customer_controller.rb add

    skip_before_action :verify_authenticity_token
    

    If you only need to skip Cross-Site Request Forgery (CSRF) for create you can do this.

    skip_before_action :verify_authenticity_token, only: :create