Daniel Bonnell
Daniel Bonnell

Reputation: 4997

ActiveModel::Serializer has_many hash of objects

I've got an ActiveModel::Serializer question for the experts. Lets say I have the following JSON output where the root element is a SurveyInvite object. Currently the question_answers hash key is just an array of QuestionAnswer objects. How can I make it so that question_answers is a hash of QuestionAnswer objects where the keys are QuestionAnswer.question.id?

{
    id: 1,
    email: "[email protected]",
    status: "Submitted",
    created_at: "10:57AM Sep 1, 2015",
    date_submitted: "10:58AM Sep 1, 2015",
    survey_response: {
        id: 1,
        survey_invite_id: 1,
        name: "Foo Bar",
        title: "Ninja",
        published: true,
        created_at: "10:58AM Sep 1, 2015",
        updated_at: " 3:42PM Sep 2, 2015",
        question_answers: [
            {
                id: 1,
                survey_response_id: 1,
                mini_post_question_id: 20,
                answer: "What is the answer?",
                created_at: "2015-09-14T14:59:39.599Z",
                updated_at: "2015-09-14T14:59:39.599Z"
            },
            {
                id: 2,
                survey_response_id: 1,
                mini_post_question_id: 27,
                answer: "What is the answer?",
                created_at: "2015-09-15T20:58:32.030Z",
                updated_at: "2015-09-15T20:58:32.030Z"
            }
        ]
    }
}

Here is my SurveyResponseSerializer:

class SurveyResponseSerializer < ActiveModel::Serializer
    attributes :id, :survey_invite_id, :name, :title, :published, :created_at, :updated_at
    has_many :question_answers

    def created_at
        object.created_at.in_time_zone("Eastern Time (US & Canada)").strftime("%l:%M%p %b %w, %Y")
    end

    def updated_at
        object.updated_at.in_time_zone("Eastern Time (US & Canada)").strftime("%l:%M%p %b %w, %Y")
    end
end

Basically, I want the question_answers key value to be a hash of QuestionAnswer objects where the keys are the question id QuestionAnswer.question_id. I've looked through the docs and haven't turned up any examples of what I'm trying to do.

Update with solution:

So I came up with a solution that works for what I need, but I'd still like to know if there is a better way to do what I need. I wrote a method to generate the structure I need.

def question_answers
    hash = {}
    object.question_answers.each do |answer|
        hash[answer.mini_post_question_id] = answer
    end
    hash
end

That yields the following:

question_answers: {
    20: {
        id: 1,
        survey_response_id: 1,
        mini_post_question_id: 20,
        answer: "Test?",
        created_at: "2015-09-14T14:59:39.599Z",
        updated_at: "2015-09-14T14:59:39.599Z"
    },
    27: {
        id: 2,
        survey_response_id: 1,
        mini_post_question_id: 27,
        answer: "Blarg!",
        created_at: "2015-09-15T20:58:32.030Z",
        updated_at: "2015-09-15T20:58:32.030Z"
    }
}

Upvotes: 2

Views: 741

Answers (1)

ahmacleod
ahmacleod

Reputation: 4310

I don't think ActiveModelSerializers has an idiomatic way to present a has_many association as a hash, but you can do it with a one-liner:

def question_answers
    object.question_answers.index_by(&:id)
end

Upvotes: 3

Related Questions