Search code examples
ruby-on-railsember.jsstrong-parametersactive-model-serializersjson-api

Emberjs PATCH and POST to Rails unpermitted parameters


So I've got an EmberJS and Rails API going.

I am using Active Model Serializer.

I have the following Active Model Serializer intializer config:

active_model_serializer.rb

ActiveModelSerializers.config.adapter = :json_api

api_mime_types = %W(
  application/vnd.api+json
  text/x-json
  application/json
)
Mime::Type.register 'application/vnd.api+json', :json, api_mime_types

At the moment, my Ember app is able to fetch data from my Rails API fine.

It is having problem sending updated user info to my Rails server however.

I am getting an error on my Rails server log:

Unpermitted parameters: data, id, user

My ember appears to be sending the paramters:

{
    "data"=>{
        "id"=>"2",
        "attributes"=>{
            "first-name"=>"James",
            "last-name"=>"Raynor",
            "username"=>"Jimobo",
            "email"=>"jim@gmail.com",
            "photo"=>{
                "photo"=>{
                    "url"=>nil
                }
            }
        },
        "type"=>"users"
    },
    "id"=>"2",
    "user"=>{

    }
}

Note: I only changed the username from Jimo to Jimobo.

When I was building my Rails API, I was using Active Model Serializer and the strong parameters looks something like:

Strong Parameters

def user_params
  params.permit(:first_name, :last_name, :username, :email, :password, :password_confirmation, :photo, friend_ids: [])
end

Do I really have to go through every one of my strong parameter declarations and modify them to be like this:

params.require(:data).require(:attributes).permit(...);

Or is there some magical solution I am not doing correctly?

In this Github discussion https://github.com/rails-api/active_model_serializers/issues/1027#issuecomment-126543577, a user named rmcsharry mentioned he didn't really need to modify anything and it worked out of the box......although he didn't show what his strong parameters looked like.


Solution

  • I think I finally got it working :D

    Documenting this for my future self.

    config/initializers/active_model_serializer.rb

    ActiveModelSerializers.config.adapter = :json_api
    
    ActiveModelSerializers.config.key_transform = :unaltered
    

    config/initializers/mime_types.rb

    # Be sure to restart your server when you modify this file.
    
    # Add new mime types for use in respond_to blocks:
    Mime::Type.register "text/richtext", :rtf
    api_mime_types = %W(
        application/vnd.api+json
        text/x-json
        application/json
    )
    
    Mime::Type.unregister :json
    Mime::Type.register 'application/json', :json, api_mime_types
    

    Controllers strong parameters

    // no need to include :id
    params.require(:data).require(:attributes).permit(...)
    

    I also need to generate a serializer on my Ember side following this guide: https://github.com/rails-api/active_model_serializers/blob/master/docs/integrations/ember-and-json-api.md

    ember generate serializer application
    

    app/serializer/application.js

    import DS from 'ember-data';
    import Ember from 'ember';
    var underscore = Ember.String.underscore;
    
    export default DS.JSONAPISerializer.extend({
      keyForAttribute: function(attr) {
        return underscore(attr);
      },
    
      keyForRelationship: function(rawKey) {
        return underscore(rawKey);
      }
    });
    

    Funny thing is, the guide is basically telling Ember to use underscore for multiple word attributes but JSON API spec uses dashes instead of underscore. So these changes will make Ember and Rails happy but it's not really JSON API compliant from what I can see.

    Now I need to go back and fix all my other controllers and tests to cater for the new :data and :attributes strong parameters :(

    Update

    I manage to stumble upon this...why did it take so long for me to discovered it?

    http://kyleshevlin.com/all-the-steps-needed-to-get-active-model-serializers-to-work-with-jsonapiadapter-and-jsonapiserializer-in-ember/

    An even better way to do the strong parameters is something like this:

    ActiveModelSerializers::Deserialization.jsonapi_parse(params, only: [:first_name, :last_name, :email, :password, :password_confirmation])
    

    Doing it this way means we don't need to manually specify

    params.require(:data).require(:attributes)
    

    It's probably doing that behind the scenes anyways but since it aligns with the other article by the Active Model Serializer people, I guess using the Deserialization method of AMS would be the recommended way.