0

In my Comments controller, I serialize the comments. When I put a belongs_to :post_id in my serializer, every comment has a post with it, but since all of these comments come from the same post, it is redundant. I know I can use the post serializer with a has_many comments, but since I'm n the comments controller that doesn't seem idiomatic. How would I achieve this?

Hoping for: { comments: { ... }, post: { ... } }

David
  • 7,028
  • 10
  • 48
  • 95

1 Answers1

1

If you want to prevent redundant inclusion of associations, set embed:

embed :objects               # Embed associations as full objects
embed :ids                   # Embed only the association ids
embed :ids, :include => true # Embed the association ids and include objects in the root

So

class Comments < ActiveModel::Serializer
  embed :ids, include: true
end

will include the post only once at the top level:

{
  comments: [
    {
      id: 1,
      text: "Foo",
      post_id: 1
    },
    {
      id: 2,
      text: "Bar",
      post_id: 1
    }
  ],
  posts: [
    {
      id: 1,
      title: "Lorem ipsum"
    }
  ]
}

If you want to include or leave out associations completely depending on the situation, this wonderful StackOverflow answer has a nifty solution for that by (ab)using eager loading:

class Comments < ActiveModel::Serializer
  attributes :id, :text, :poster_id

  belongs_to :poster

  def include_poster?
    object.association(:poster).loaded?
  end

  def include_poster_id?
    !include_poster?
  end
end

Now by clearing the post association you can prevent it from being included at all:

@comments = @post.comments
@comments.post.reset

respond_with @comments

In reverse, explicitly eager loading an association will include it:

@comments = Comment.includes(:poster).order(id: :asc).limit(10)
respond_with @comments
Community
  • 1
  • 1
janfoeh
  • 10,243
  • 2
  • 31
  • 56
  • How would this apply if I get comments like such `@comments = @post.comments`? I already have the post. It is a matter of getting it included. A quick hack is to just include it in the meta, but I'm not too keen on that. – David Feb 20 '15 at 09:02
  • @David I think I see what you mean, except for the meta part? – janfoeh Feb 20 '15 at 09:06
  • @David `embed include: true` should do the trick. Regarding `@comments = @post.comments`, you can unload an association by calling `.reset` on it. `@comments = @post.comments ; @comments.post.reset` will leave the `post` unhydrated. – janfoeh Feb 20 '15 at 09:15
  • This is a very _pro_ topic, and for the same reason I didn't get it.. It seems. :-( – Arup Rakshit Feb 20 '15 at 09:19
  • @janfoeh Thanks for your willingness. First let me know if it is Rails out of the box functionality ? – Arup Rakshit Feb 20 '15 at 09:27
  • Ohkay! This is a very good learning for me.. Thanks.. Hope I'll learn more from you. I never saw this stuff in my 7 months career. :) – Arup Rakshit Feb 20 '15 at 09:41
  • friend +1, for this extensive explanation. – Arup Rakshit Feb 20 '15 at 09:48