nebulab / simple_command

A simple, standardized way to build and use Service Objects (aka Commands) in Ruby
http://nebulab.it
MIT License
624 stars 55 forks source link

Make Errors render the same as ActiveModel::Errors #25

Open bmorrall opened 4 years ago

bmorrall commented 4 years ago

I looked into Issue #24 to determine why the Errors object was behaving differently from "ActiveSupport::Errors".

From what I've found, Rails will render the Errors using Hash#as_json as implemented by ActiveSupport, instead of Hash#to_json as included with base Ruby.

I wrote a work around that will provide an as_json method when Hash#as_json has been provided by ActiveSupport (i.e. every Rails project), and will raise an error when it is not provided.

I also included some test coverage to ensure to_json works as expected, to avoid any regressions.

thlmenezes commented 1 year ago

Looking in active_model/serializers/json.rb there's a root options that I think it could be useful here, because of the recurring pattern of wrapping the json results in a errors key; so the code could be modified to something like

def as_json(options = nil)
  root = if options && options.key?(:root)
    options[:root]
  else
    true
    # could be modified to use an initializer var,
    # like active record has ActiveRecord::Base.include_root_in_json = true
  end

  json = Hash.new.tap do |output|
    raise NotImplementedError.new unless output.respond_to?(:as_json)

    self.each do |field, value|
      output[field] ||= []
      output[field] << value
    end
  end.as_json(options)

  if root
    root = :errors if root == true
    { root => json }
  else
    json
  end
end

with root being a boolean value or a string to be the key of the generated json