28

This question pertains to AMS 0.8

I've got two models:

class Subject < ActiveRecord::Base
  has_many :user_combinations
  has_ancestry
end

class UserCombination < ActiveRecord::Base
  belongs_to :stage
  belongs_to :subject
  belongs_to :user
end

And two serializers:

class UserCombinationSerializer < ActiveModel::Serializer
      attributes :id
      belongs_to :stage
      belongs_to :subject
end

class SubjectSerializer < ActiveModel::Serializer
  attributes :id, :name, :description, :subjects

  def include_subjects?
    object.is_root?
  end

  def subjects
    object.subtree
  end
end

When a UserCombination is serialized, I want to embed the whole subtree of subjects.

When I try to use this setup I get this error:

undefined method `belongs_to' for UserCombinationSerializer:Class

I tried changing the UserCombinationSerializer to this:

class UserCombinationSerializer < ActiveModel::Serializer
  attributes :id, :subject, :stage
end

In this case I get no errors, but the subject is serialized in the wrong way - not using the SubjectSerializer.

My questions:

  1. Shouldn't I be able to use a belongs_to relation in the serializer?
  2. If not - how can I get the wanted behaviour - embedding the subject tree using the SubjectSerializer?
Jesper
  • 4,535
  • 2
  • 22
  • 34

3 Answers3

42

This is not really elegant but it seems to be working :

class UserCombinationSerializer < ActiveModel::Serializer
  attributes :id, :stage_id, :subject_id

  has_one :subject
end

I don't really like calling has_one whereas it's actually a belongs_to association :/

EDIT: Disregard my comment about has_one/belongs_to ambiguity, the doc is actually pretty clear about it: http://www.rubydoc.info/github/rails-api/active_model_serializers/frames

pjam
  • 6,356
  • 5
  • 30
  • 40
  • 4
    Okay, yeah, this works. I think I understand the `has_one` method better now. In a `Serializer`, the only thing that is interesting is whether a method returns one or many objects. So distinguishing between has_one and belongs_to isn't interesting. It's a kinda suboptimal that the wording coincides with ActiveRecord-terminology, since the terms do not mean the same thing. – Jesper Oct 30 '12 at 12:28
  • I ran into this same problem just recently. Yes, using the has_one :attribute works for me. – Kurt Mueller Aug 09 '13 at 14:04
  • 11
    The documentation for `ActiveModel::Serializer` explictly states: "Serializers are only concerned with multiplicity, and not ownership. belongs_to ActiveRecord associations can be included using has_one in your serializer." – awendt Feb 26 '14 at 11:23
  • @awendt May I ask where this is explicitly stated? I can't seem to find that. I'm not saying you are wrong, I am still new to the rails/ruby world and am not too great and quick at finding docs as well as I can with Java. Which leads me to the real point, it isn't explicit if it isn't obvious. – Andy Nov 17 '14 at 22:10
  • @Andy I found it there: http://www.rubydoc.info/github/rails-api/active_model_serializers/frames – pjam Nov 17 '14 at 23:44
  • @pjam thanks! Is this where I should expect to find docs for a lot of the third party gem docs for rails? – Andy Nov 17 '14 at 23:52
  • 2
    @Andy From my experience there's sadly no central location to find documentation. A lot of them have docs on ruby docs, a lot have them on github, and sadly a lot also don't really have any. Most of the time I end up spending a lot of time on google. – pjam Nov 18 '14 at 15:32
6

In Active Model Serializer 0-10-stable, belongs_to is now available.

belongs_to :author, serializer: AuthorPreviewSerializer
belongs_to :author, key: :writer
belongs_to :post
belongs_to :blog
def blog
  Blog.new(id: 999, name: 'Custom blog')
end

https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/general/serializers.md#belongs_to

So you could do:

class UserCombinationSerializer < ActiveModel::Serializer
  attributes :id
  belongs_to :stage, serializer: StageSerializer
  belongs_to :subject, serializer: SubjectSerializer
end
MicFin
  • 2,431
  • 4
  • 32
  • 59
4

What if you try with something like this:

class UserCombinationSerializer < ActiveModel::Serializer
  attributes :subject,
             :stage,
             :id

  def subject
    SubjectSerializer.new(object.subject, { root: false } )
  end

  def stage
    StageSerializer.new(object.stage, { root: false } )
  end
end
Heriberto Magaña
  • 882
  • 10
  • 11