Question

In a Ruby 2/Rails 4 app, I am trying to use acts-as-taggable-on in conjunction with active_model_serializers in order to create a JSON API that would output my tags along with other model parameters.

First some background/motivation for this issue: The JSON is being fed into ember/ember-data, which as of the time of this writing has removed support for embedded records in JSON. There is a supposed fix in the documentation about this, but I find it clumsy and also haven't actually gotten it to work. Since I'm an Ember newbie and am a little more comfortable with Rails, I figure I'll try to solve the problem another way, by sideloading the tag record alongside the document record. I like this solution better because it makes more sense for my application, but I can't get this to work either.

Here's an example: Let's say I have a Document model that is using acts-as-taggable-on:

class Document < ActiveRecord::Base
  acts_as_taggable
  # other code omitted

I've set up the database with one document with one tag. Now we consider the following cases:

1. Full Object Embed: With the following serializer:

class DocumentSerializer < ActiveModel::Serializer
  attributes :id
  has_many :tags

My JSON has the following format (using Rails 4 UUIDs):

{
  "documents": [
    {
      "id": "c41460fa-2427-11e3-8702-0800270f33f4",
      "tags": [
        {
          "id": "a33fc396-2428-11e3-8eeb-0800270f33f4",
          "name": "test"
        }
      ]
    }
  ]
}

2. ID Embed: Using the serializer

class DocumentSerializer < ActiveModel::Serializer
  attributes :id
  has_many :tags, embed: :id

My JSON now looks like:

{
  "documents": [
    {
      "id": "c41460fa-2427-11e3-8702-0800270f33f4",
      "tag_ids": [
        "a33fc396-2428-11e3-8eeb-0800270f33f4"
      ]
    }
  ]
}

3. ID Embed with Tags Sideloaded: According to active_model_serializers documentation, I should be able to do

class DocumentSerializer < ActiveModel::Serializer
  attributes :id
  has_many :tags, embed: :id, include: true

but this doesn't work. Instead, I get a NoMethodError:

undefined method `object' for #<ActsAsTaggableOn::Tag:0x007f258cf1db38>

I've tried searching for this problem but haven't found anything useful so far. I also couldn't find any documentation on either gem regarding usage with the other gem. My suspicion right now that it has something to do with how acts-as-taggable-on is implemented, that it's not a straightforward has_many relationship? Is anybody able to offer some input on this issue? Thanks in advance!

Was it helpful?

Solution

Fixed! Turns out to sideload the tags, the corresponding serializer must be defined. I did not know this, because the documentation seems to imply that having a serializer is optional, and some default will be used in the absence of one. Apparently this is not the case if you wish to use the include: true option. Key in sight came from here, thanks very much!

For completeness, I'll show what I did. I created tag_serializer.rb with the following code:

module ActsAsTaggableOn
  class TagSerializer < ActiveModel::Serializer
    attributes :id, :name
  end
end

and now my JSON:

{
   "tags": [
      {
         "id": "a33fc396-2428-11e3-8eeb-0800270f33f4",
         "name": "test"
      }
   ],
   "documents": [
      {
         "id": "c41460fa-2427-11e3-8702-0800270f33f4",
         "tag_ids": [
            "a33fc396-2428-11e3-8eeb-0800270f33f4"
         ]
      }
   ]
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top