Search code examples
ruby-on-railsrubyserializationruby-on-rails-6

Convert a returning Hash of a Model's method to a serializable_hash (for as_json)


My Modelclass has a method, that returns some calculated data in form of a Hash. In the Controller I want to use this data, but want to include only some parts of the Hash.

My first idea was, to use the method inside :include in the to_json-options instead of the :methods field. But this will end in an undefined method 'serializable_hash'-Error.

Model:

class Family < ActiveRecord::Base

  def child_data
    {
      gender: self.child_gender,
      first_name: self.child_first_name,
      last_name: self.child_last_name,
      email: self.child_email,
      phone: self.child_phone
    }
  end

end

Controller:

class Api::V5::Private::FamilyController < Api::V5::PrivateController

  def index

    render json: Family.all.to_json({
      only: [ :id, :last_name ],
      # methods: [ :child_data ], <-- WOULD WORK
      include: {
        child_data: {
          only: [ :first_name, :gender ]
        }
      }
    })

  end

end

How can I use the returning Hash of the method "child_data" inside to_json/as_json, but use :only and :except to filter the Hash?


Solution

  • Found two solutions for this:

    1. Use a module with method "serializable_hash" and extend the Hash with this module:
    module Serializable
      
      def serializable_hash opts
        self.as_json(opts)
      end
      
    end
    

    and

    def child_data
       {
          gender: self.child_gender,
          first_name: self.child_first_name,
          last_name: self.child_last_name,
          email: self.child_email,
          phone: self.child_phone
    
       }.extend(Serializable)
    end
    
    1. Extend Ruby's Hash Class inside the "initializers/" by reopening the Class and add the method:

    config/initializers/hash_extensions.rb

    class Hash
      def serializable_hash opts
        self.as_json(opts)
      end
    end
    

    I'll leave this here for anybody, who also got into this problem.