Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveModel Serializers: has_many with condition at run-time?

I use rails (5.0.1) and active_model_serializers (0.10.2). I would like to somehow conditionally serialize the has_many associations:

class Question < ApplicationRecord
    has_many :responses, :inverse_of => :question
end

class Response < ApplicationRecord
    belongs_to :question, :inverse_of => :responses
end

class QuestionSerializer < ActiveModel::Serializer
  attributes :id, :title, :created_at, :updated_at
  has_many :responses
end

class ResponseSerializer < ActiveModel::Serializer
  attributes :id, :title
end

I use jsonapi and querying http://localhost:3000/api/questions/1 I get this response:

Response-1:

{
  "data": {
    "id": "1",
    "type": "questions",
    "attributes": {
      "title": "First",
      "created-at": "2017-02-14T09:49:20.148Z",
      "updated-at": "2017-02-14T13:55:37.365Z"
    },
    "relationships": {
      "responses": {
        "data": [
          {
            "id": "1",
            "type": "responses"
          }
        ]
      }
    }
  }
}

If I remove has_many :responses from QuestionSerializer I get this:

Response-2:

{
  "data": {
    "id": "1",
    "type": "questions",
    "attributes": {
      "title": "First",
      "created-at": "2017-02-14T09:49:20.148Z",
      "updated-at": "2017-02-14T13:55:37.365Z"
    }
  }
}

How do I conditionally get either Response-1 or Response-2 at run time? I tried all the recommendations found - neither works with AMS 0.10.2. Currently, the condition works only this way:

class QuestionSerializer < ActiveModel::Serializer
  attributes :id, :title, :created_at, :updated_at
  has_many :responses if true
end

OR:

class QuestionSerializer < ActiveModel::Serializer
  attributes :id, :title, :created_at, :updated_at
  has_many :responses if false
end

In these 2 cases I really get either Response-1 or Response-2. But this is hard-coded and I would like to maybe pass a param into the serializer or do some similar thing.

What should I do?

like image 410
prograils Avatar asked Feb 15 '17 08:02

prograils


1 Answers

I think you've kind of answered your own question. If you look into the AMS documentation for associations it says that conditionals are supported.

From what I can tell you're just a typo away

class QuestionSerializer < ActiveModel::Serializer
   has_many :responses, if: false
end

The attributes method also supports the if option, as described here.

What's your active_model_serializers version?

EDIT: I have an error in my answer too. I'm using active_model_serializers (0.10.3) and I'm able to do

class QuestionSerializer < ActiveModel::Serializer
   has_many :responses, if: -> { false }
end

The if option works with either methods, procs or strings. I think you can decide at runtime by providing a method as the conditional.

class QuestionSerializer < ActiveModel::Serializer
  attr_writer :should_render_association
  has_many :responses, if: -> { should_render_association }
end
# Usage: 
serializer = QuestionSerializer.new(question)
serializer.should_render_association = false
serializer.to_json
# => no "responses" key
like image 154
gkats Avatar answered Nov 07 '22 15:11

gkats