This is a very helpful tool. Unfortunately the underlying design has some major flaws. You run serialization in the context of the class rather than the instance, which prevents memoization and adds awkwardness of having to define blocks rather than methods. Your README demonstrates this adding another layer of awkwardness by using concerns completely unnecessarily. E.g.

module AvatarHelper
extend ActiveSupport::Concern

class_methods do
def avatar_url(user)
user.image.url
end
end
end

class UserSerializer
include FastJsonapi::ObjectSerializer

This should just be:

module AvatarHelper
def avatar_url(user)
user.image.url
end
end

class UserSerializer
extend(FastJsonapi::ObjectSerializer)

I solved the problem, avoiding defining methods on the class, while also managing to Prefer Composition over Inheritance as follows:

class PortalFileSerializer
include(FastJsonapi::ObjectSerializer)

def initialize(file_record)
super(Presenter.new(file_record))
end
attribute(:contents) do |file_record|
file_record.rows.map do |row|
field_name = row.fetch('0')
{
name: field_name,
value: row.fetch('1'),
masked?: file_record.masks.include?(field_name),
}
end
end
# http://wiki.c2.com/?CompositionInsteadOfInheritance
class Presenter < SimpleDelegator
def rows
rows_including_empty_last_row.tap(&:pop)
end

def rows_including_empty_last_row
portal_file.contents_as_json.fetch(:rows)
end
# Yay, I got memoization back!
def masks
@masks ||= portal_file
.meta_data.fetch('masks')
.select { |mask| mask.fetch('fulfilled') }
.map { |mask| mask.fetch('key') }.to_set
end
end

Advocate of Score Voting and Approval Voting. Software engineer. Father. Husband. American.