Last active
August 29, 2015 14:21
-
-
Save pdobb/d4f0b2375bdc210d24e6 to your computer and use it in GitHub Desktop.
Custom API Responder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/models/api_v2_responder.rb | |
# This approach was heavily inspired by | |
# http://josephhsu.com/post/32746478033/rails-responders-api-versioning. | |
# Overriding the #to_json method wasn't right though, as it removed half of the | |
# awesome functionality of respond_with. | |
# | |
# @see https://github.com/rails/rails/blob/v3.2.17/actionpack/lib/action_controller/metal/responder.rb | |
class ApiV2Responder < ActionController::Responder | |
# Override the original `#display` method to wrap the passed in resource in | |
# the correspondingly named Presenter. | |
def display(resource, given_options = {}) | |
controller.render given_options.merge!(options).merge!(format => present(resource)) | |
end | |
private | |
# Present the resource, or resources, if possible. | |
def present(model_or_models) | |
presenters = Array.wrap(model_or_models).map do |model| | |
if (presenter = determine_presenter(model)) | |
presenter.new(model) | |
else | |
model | |
end | |
end | |
# Ensure that an array of presenters is returned for :index pages, even if | |
# only one presented resource exists. | |
return presenters if options[:template] == "index" || presenters.many? | |
presenters.first | |
end | |
# Try and find a correspondingly named presenter class for the passed in | |
# resource. | |
def determine_presenter(model) | |
"Api::V2::#{model.class.name}Presenter".constantize | |
rescue NameError | |
nil | |
end | |
end | |
# app/models/api_presenter_delegator.rb | |
# Facilitates the Presenter objects in use by the API. | |
# | |
# @see http://devblog.avdi.org/2012/01/31/decoration-is-best-except-when-it-isnt/ | |
# When to use Presenters | |
class ApiPresenterDelegator < SimpleDelegator | |
# Redefine `#to_json` so that calling `#to_json` on a Presenter object will | |
# call the presenter's version of `#as_json` instead of simply delegating to | |
# the presented model's version of `as_json`. | |
def to_json(*args) | |
as_json.to_json(*args) | |
end | |
def presented? | |
true | |
end | |
end | |
# app/presenters/api/v2/foo_report_presenter.rb | |
module Api | |
module V2 | |
class FooReportPresenter < ApiPresenterDelegator | |
def as_json(options = {}) | |
{ | |
root_obj_name: { | |
id: id, | |
user: { | |
id: user_id | |
}, | |
} | |
}.deep_merge(options) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment