Is ActiveModelAdapter not a direct replacement for RESTAdapter?


#1

I have a Rails app using the ActiveModel Serializer gem and an Ember frontent. Until now I have been using the RESTAdapter and manually performing the renaming of keys in the models serializers. However, I just started working on persisting records to the backend, and I realized that I can’t use the RESTAdapter anymore. What happens is that the Rails controller permits only the book_id and status parameters, not the book or user. The RESTAdapter does not convert these automatically:

Started POST "/notes" for 127.0.0.1 at 2014-05-02 19:09:43 +0100
Processing by NotesController#create as JSON
  Parameters: {"note"=>{"status"=>"to read", "book"=>"25", "user"=>nil}, "auth_token"=>"[FILTERED]"}
  User Load (0.7ms)  SELECT  "users".* FROM "users"  WHERE "users"."remember_token" = '[FILTERED]' LIMIT 1
Unpermitted parameters: book, user
   (0.3ms)  BEGIN
   (0.3ms)  ROLLBACK
Completed 422 Unprocessable Entity in 11ms (Views: 0.4ms | ActiveRecord: 1.3ms)

So I discovered the ActiveModelAdapter and added it to the app like this:

App.ApplicationAdapter = DS.ActiveModelAdapter.extend({});

The adapter correctly maps the book and book_id parameters. The rails controller therefore accepts the request:

Started POST "/notes" for 127.0.0.1 at 2014-05-02 19:14:42 +0100
Processing by NotesController#create as JSON
  Parameters: {"note"=>{"status"=>"to read", "book_id"=>"25", "user_id"=>nil}, "auth_token"=>"[FILTERED]"}
  User Load (0.7ms)  SELECT  "users".* FROM "users"  WHERE "users"."remember_token" = '[FILTERED]' LIMIT 1
Unpermitted parameters: user_id
   (0.3ms)  BEGIN
  SQL (0.5ms)  INSERT INTO "notes" ("book_id", "created_at", "updated_at", "user_id") VALUES ($1, $2, $3, $4) RETURNING "id"  [["book_id", 25], ["created_at", "2014-05-02 18:14:42.961100"], ["updated_at", "2014-05-02 18:14:42.961100"], ["user_id", 1]]
   (21.2ms)  COMMIT
  [...]
Completed 201 Created in 48ms (Views: 7.2ms | ActiveRecord: 23.6ms)

So this works well, but after changing the adapter, the relationships are no longer loaded into the store correctly. None of the relationships defined in the models work.

This is an example of the json with a book-belongsTo-author relationship, which fails to be loaded into the Ember store.

{
  "authors": [
    {
      "id": 2,
      "name": "Pam Conrad"
    }
  ],
  "books": [
    {
      "id": 2,
      "title": "Pedro's Journal: A Voyage with Christopher Columbus, August 3, 1492-February 14, 1493",
      "author": 2
    }
  ]
}

Ember version:

DEBUG: ------------------------------- dependencies.js:6630
DEBUG: Ember      : 1.7.0-beta.1+canary.d02aa7f4 dependencies.js:6630
DEBUG: Ember Data : 1.0.0-beta.7+canary.20adb1d5 dependencies.js:6630
DEBUG: Handlebars : 1.3.0 dependencies.js:6630
DEBUG: jQuery     : 2.1.0 dependencies.js:6630
DEBUG: ------------------------------- 

#2

Hi… while we really should try to keep the discussion more about Ember rather than Rails, this particular question is perhaps something I can help with, so I will…

I’m using the same versions of things as you (and the REST adapter, slightly modified from the original beta 1 of Ember Data). It sounds a bit like you’re not doing the strong parameters dance perhaps?

This is what my controller looks like: def create @tag = Tag.new(filtered_params)

    respond_to do |format|
      if @tag.save
        format.html { redirect_to tag_path(@tag), notice: 'Tag was successfully created.' }
        format.json { render json: @tag, status: :created, location: designer_tag_path(@tag) }
      else
        format.html { render action: "new" }
        format.json { render json: @tag.errors, status: :unprocessable_entity }
      end
    end
  end

and then below, in the same controller’s private block:

  private

  def filtered_params
    f_params = Hash.new
    f_params[:host_item_id] = params[:tag][:host_item]
    f_params[:name] = params[:tag][:name]
    parameters = ActionController::Parameters.new(f_params)
    permittable = parameters.keys
    parameters.permit(*permittable)
  end

Note I’m transforming the keys manually, and telling the (rails) controller that those particular keys are fine to use. and I’m using these filtered_params to create/update my records, not the standard params.

Am I barking up the wrong tree? Sorry if I am, just trying to help :smile:


#3

@pedrokost I’d definitely advise using the ActiveModelAdapter if rails is your backend. If you do, you don’t need any of the customizations that @JulianLeviston shows above.

Instead you just need to make sure that your JSON is correct. The relationship keys need to be different - in your json for your book you have author key, this needs to be author_id - in fact, this is what Active Model Serializers should use by default so I’m surprised that you have this issue. In any case, singular foreign keys now need to end in _id, and plural foreign keys now need to end in _ids - so author_id for a belongsTo relationship, or author_ids for a hasMany relationship.

Hope this helps, Alex


#4

Interesting @alexspeller - how does Rails know to authorize the keys? Wasn’t that the actual problem he was having? (little confused).

I guess the only thing you don’t need is the translation? I should probably use the active model adapter… I didn’t even know about it until about 2 weeks ago, though :slight_smile:

[ edit ] ah, yeah I re-read the initial message and you’re spot on (of course!) :wink: apologies.


#5

He said:

Not sure what that has to do with params on the rails side?


#6

It doesn’t have anything to do with params on the rails side. Sorry I didn’t realise we’d isolated that as the only change! :slight_smile: all good then.

[ edit ] re-read the initial message and now I understand. He was doing key manipulation in the adapter on the ember side. I didn’t quite understand that until that point. Great. LoL. It’d help if I read things a bit better, or something (self.annoyed) :slight_smile:


#7

Alex, thank you. You inspire me to be better.


#8

https://meta.wikimedia.org/wiki/Cunningham’s_Law

Not that your answer was wrong, I think you were just answering a different question!


#9

@alexspeller, you were right. I was manually rewriting the key in the serializers like this: has_one :author, key: :author. Removing the last part serialized the relationship attributes ending with '_id'.


#10

@alexspeller I’ve been adapting to using ActiveModelAdapter and everything’s going okay, except I’m now using the links option… (so I don’t have ridiculously long ids like this one (truncated beacuse OH MY LORD it was long before)…

http://www.flutesandflutists.net/designer/blocks?ids[]=1&ids[]=59&ids[]=61&ids[]=39&ids[]=60&ids[]=758&ids[]=11&ids[]=12&ids[]=671&ids[]=3&ids[]=63&ids[]=62&ids[]=64&ids[]=393&ids[]=615&ids[]=541&ids[]=666&ids[]=491&ids[]=46&ids[]=4&ids[]=482&ids[]=800&ids[]=38&ids[]=37&ids[]=34&ids[]=161&ids[]=526&ids[]=35&ids[%

…etc.

Question is, am I doing it right like this:

      def links
        {
          "child_blocks" => child_blocks_designer_block_url(object.id, format: :json) # "/blocks/#{object.id}/child_blocks"
        }
      end

… because it seems to be that ember isn’t loading data properly for the child_blocks… (I’ve definitely got the URL helper correct, it’s just a matter of if the links format is right according to what Ember Data / ActiveModel Adapter is expecting… from the serializer)