23

I am using Active Model Serializers 0.10.x with EmberCLI and Rails while trying to have the Json-Api as the Adapter. GET requests are working, but deserialization for the Active Model is not even though I tried to implement the rails strong_parameters solution described by jimbeaudoin here.

My latest attempt in saving a comment:

Payload:

{"data":{
   "attributes": {"soft_delete":false,"soft_delete_date":null,"text":"hjfgfhjghjg","hidden":false,"empathy_level":0},
   "relationships":{
     "user":{"data":{"type":"users","id":"1"}},
     "post":{"data":{"type":"posts","id":"1"}}},"type":"comments"}}

Console Output:

Completed 400 Bad Request in 13ms (ActiveRecord: 8.6ms)
ActionController::ParameterMissing (param is missing or the value is empty: data):

Comments Controller:

class Api::V1::CommentsController < MasterApiController
    respond_to :json
    ...
    def create
        render json: Comment.create(comment_params)
    end
    ...
    def comment_params
        #Deserialization issues... Waiting for #950 https://github.com/rails-api/active_model_serializers/pull/950
        params.require(:data).require(:attributes).permit(:text, :user_id, :post_id, :empathy_level, :soft_delete_date, :soft_delete, :hidden)
    end
end

Noting that if I set the parameters to only params.permit(...), the server saves it with everything null (I did not set any constraints on the comments model for now):

data: {id: "9", type: "comments",…}
attributes: {soft_delete: null, soft_delete_date: null, text: null, hidden: null, empathy_level: null}
id: "9"
relationships: {post: {data: null}, user: {data: null}}
type: "comments"

You can access the full code here.

Deovandski
  • 790
  • 1
  • 8
  • 22

4 Answers4

13

Update #2: For AMS >= 0.10.2, please check other answers.

Update #1: Answer is still valid for AMS 0.10.1.

If you use 0.10.0.rc4, you can now use the Deserialization implementation described on Active Model Serializers #1248.

def post_params
    ActiveModel::Serializer::Adapter::JsonApi::Deserialization.parse(params.to_h) 
    // or (params.to_unsafe_h) in some cases like in my example below...
end

Bonus: If you use Ember Data, then you can see an example implementation on my Fakktion Github repo.

Community
  • 1
  • 1
Deovandski
  • 790
  • 1
  • 8
  • 22
  • Hey @Deovandski, i'm facing problems related to handle dash. As you know ember sends params like `starts-at` and the rails api expects `stars_at`. Based on docs: https://github.com/rails-api/active_model_serializers/blob/v0.10.6/docs/general/deserialization.md#json-api – João Ramires Feb 16 '21 at 20:20
  • I tried to use the keys option like that: ```ruby ActiveModelSerializers::Deserialization.jsonapi_parse!(params, only: %i[name description type url continuous starts_at finishes_at], keys: { 'starts-at': :starts_at, 'finishes-at': :finishes_at }) ``` also I tried `params.to_unsafe_h` but still not working. Any idea? – João Ramires Feb 16 '21 at 20:22
  • Sorry for the poor formatted snippet. It seems that comments can't do better. – João Ramires Feb 16 '21 at 20:23
  • 1
    Howdy! Has been a few years since I last touched Ruby on Rails, or AMS, so I can't really help out anymore as I forgot most of it... AMS still seems to be alive with the latest release of v0.10.12, so perhaps you should create a new StackOverflow question, then an issue on AMS Github that links to it. That way you will you likely catch the attention of one of the AMS maintainers. – Deovandski Feb 17 '21 at 03:32
  • 1
    Hey man, thanks for answer back! I manage to solve it by chainning `to_unsafe_h` and `deep_transform_keys` :) – João Ramires Feb 17 '21 at 15:11
8

For AMS >= 0.10.2

In 0.10.2 there was a cleanup so after 0.10.2 use:

def post_params
   ActiveModelSerializers::Deserialization.jsonapi_parse(params)
end

Reference: https://github.com/rails-api/active_model_serializers/commit/252f9c4ae932e6280dfe68605d495b208fe22ba7

rolkos
  • 342
  • 3
  • 15
  • 1
    Ok, so this is deserializing, but is it actually doing a whitelist? I don't believe that it is. Isn't this bypassing the entire idea of strong paramters? – rmcsharry Sep 13 '16 at 15:57
  • 5
    There is a way to still achive whitelisting `ActiveModelSerializers::Deserialization .jsonapi_parse(document, only: [:title, :date, :author], keys: { date: :published_at }, polymorphic: [:author])` – donden1 Oct 16 '16 at 17:59
8

With AMS 0.10.2+

Use only hash to create a parameter whitelist,

def post_params
  ActiveModelSerializers::Deserialization.jsonapi_parse!(
    params, only: [:title, :author, :tags]
  )
end
XY L
  • 25,431
  • 14
  • 84
  • 143
4

For googlers:

If you have empty data payload, you need to add Mime support https://stackoverflow.com/a/32013294/2664779

When you want to access json-api formatted json, you should do it like this (in your controller)

def create   
  user = User.new(user_params)
...
end

private

  def user_params
    params.require(:data).require(:attributes).permit(:email, :password)
  end

When previously I would do it like this

private

def user_params
  params.require(:user).permit(:email, :password)
end
Community
  • 1
  • 1
qnsi
  • 370
  • 4
  • 14
  • 1
    Manually registering the Mime caused Rails to output "warning: already initialized constant Mime::JSON" and "warning: previous definition of JSON was here." on the terminal... Although rails stopped saying that Data was empty and started to accept the attributes parameters, all relationships parameters are not saved through. Do you know of a workaround for this issue? – Deovandski Oct 15 '15 at 18:43
  • 1
    @Deovandski Possibly a bit late for you, but this might be the workaround you were looking for (said Obi Wan): http://stackoverflow.com/questions/35733430/jsonapi-strong-params-with-rails-and-ember – rmcsharry Sep 13 '16 at 15:56