Skip to content

Commit

Permalink
Utilise ActiveModel::Serializers::JSON in Her models
Browse files Browse the repository at this point in the history
This makes as_json and to_json behave like they do under ActiveRecord,
excluding associations unless they are explicitly included. This is
necessary to avoid infinite loops.

Unfortunately this caused Her's include_root_in_json code to collide
with ActiveModel's include_root_in_json code. I removed Her's
getter/setter method in favour of ActiveModel's class attribute but
also provided a compatibility fix.
  • Loading branch information
chewi committed Apr 16, 2018
1 parent 6f10981 commit 8b31447
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 31 deletions.
4 changes: 3 additions & 1 deletion lib/her/model.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require "active_model"
require "her/model/base"
require "her/model/deprecated_methods"
require "her/model/http"
Expand All @@ -7,9 +8,9 @@
require "her/model/parse"
require "her/model/associations"
require "her/model/introspection"
require "her/model/serialization"
require "her/model/paths"
require "her/model/nested_attributes"
require "active_model"

module Her
# This module is the main element of Her. After creating a Her::API object,
Expand All @@ -33,6 +34,7 @@ module Model
include Her::Model::HTTP
include Her::Model::Parse
include Her::Model::Introspection
include Her::Model::Serialization
include Her::Model::Paths
include Her::Model::Associations
include Her::Model::NestedAttributes
Expand Down
22 changes: 2 additions & 20 deletions lib/her/model/parse.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def to_params(attributes, changes={})

embed_params!(attributes, filtered_attributes)

if include_root_in_json?
if include_root_in_json
if json_api_format?
{ included_root_element => [filtered_attributes] }
else
Expand Down Expand Up @@ -101,18 +101,6 @@ def embed_params!(read_attributes, write_attributes)
Thread.current[:her_embedded_params_objects] = nil if first
end

# Return or change the value of `include_root_in_json`
#
# @example
# class User
# include Her::Model
# include_root_in_json true
# end
def include_root_in_json(value, options = {})
@_her_include_root_in_json = value
@_her_include_root_in_json_format = options[:format]
end

# Return or change the value of `parse_root_in_json`
#
# @example
Expand Down Expand Up @@ -176,7 +164,7 @@ def root_element_included?(data)

# @private
def included_root_element
include_root_in_json? == true ? root_element : include_root_in_json?
include_root_in_json == true ? root_element : include_root_in_json
end

# Extract an array from the request data
Expand Down Expand Up @@ -234,12 +222,6 @@ def request_new_object_on_build?
superclass.respond_to?(:request_new_object_on_build?) && superclass.request_new_object_on_build?
end

# @private
def include_root_in_json?
return @_her_include_root_in_json unless @_her_include_root_in_json.nil?
superclass.respond_to?(:include_root_in_json?) && superclass.include_root_in_json?
end

# @private
def parse_root_in_json?
return @_her_parse_root_in_json unless @_her_parse_root_in_json.nil?
Expand Down
49 changes: 49 additions & 0 deletions lib/her/model/serialization.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module Her
module Model
module Serialization
extend ActiveSupport::Concern
include ActiveModel::Serializers::JSON

def serializable_hash(options = nil)
options = options.try(:dup) || {}

options[:except] = Array(options[:except]).map(&:to_s)
options[:except] |= self.class.association_names.map(&:to_s)

super(options)
end

included do
# Rails 3 defaulted to true but Her has always defaulted to
# false. This can be dropped when Rails 3 support is dropped.
self.include_root_in_json = false

# Rails creates include_root_in_json as a class attribute but
# Her previously had its own implementation combining the
# getter and setter. This monstrosity tries to achieve
# compatibility in the simplest way possible.
class << self
realias = proc do
alias_method :include_root_in_json_getter, :include_root_in_json

def include_root_in_json(value = nil)
if value.nil?
include_root_in_json_getter
else
self.include_root_in_json = value
end
end
end

realias.call
alias_method :include_root_in_json_without_realias, :include_root_in_json=

define_method :include_root_in_json= do |value|
include_root_in_json_without_realias value
realias.call
end
end
end
end
end
end
5 changes: 0 additions & 5 deletions spec/support/extensions/array.rb

This file was deleted.

5 changes: 0 additions & 5 deletions spec/support/extensions/hash.rb

This file was deleted.

0 comments on commit 8b31447

Please sign in to comment.