From 0d3b56e9cf40966301ac0cf6c8dcf4263e61c2ea Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Wed, 3 Jul 2013 14:21:16 -0700 Subject: [PATCH] Implement AC integration --- lib/action_controller/serialization.rb | 71 ++++++++ lib/active_model_serializers.rb | 13 ++ .../action_controller/serialization_test.rb | 172 ++++++++++++++++++ test/test_helper.rb | 22 ++- 4 files changed, 274 insertions(+), 4 deletions(-) create mode 100644 lib/action_controller/serialization.rb create mode 100644 lib/active_model_serializers.rb create mode 100644 test/integration/action_controller/serialization_test.rb diff --git a/lib/action_controller/serialization.rb b/lib/action_controller/serialization.rb new file mode 100644 index 00000000..25decc32 --- /dev/null +++ b/lib/action_controller/serialization.rb @@ -0,0 +1,71 @@ +require 'active_support/core_ext/class/attribute' + +module ActionController + # Action Controller Serialization + # + # Overrides render :json to check if the given object implements +active_model_serializer+ + # as a method. If so, use the returned serializer instead of calling +to_json+ on the object. + # + # This module also provides a serialization_scope method that allows you to configure the + # +serialization_scope+ of the serializer. Most apps will likely set the +serialization_scope+ + # to the current user: + # + # class ApplicationController < ActionController::Base + # serialization_scope :current_user + # end + # + # If you need more complex scope rules, you can simply override the serialization_scope: + # + # class ApplicationController < ActionController::Base + # private + # + # def serialization_scope + # current_user + # end + # end + # + module Serialization + extend ActiveSupport::Concern + + include ActionController::Renderers + + included do + class_attribute :_serialization_scope + self._serialization_scope = :current_user + end + + def _render_option_json(resource, options) + serializer = build_json_serializer(resource, options) + + if serializer + super(serializer, options) + else + super + end + end + + private + + def default_serializer_options + {} + end + + def serialization_scope + _serialization_scope = self.class._serialization_scope + send(_serialization_scope) if _serialization_scope && respond_to?(_serialization_scope, true) + end + + def build_json_serializer(resource, options) + options = default_serializer_options.merge(options || {}) + + serializer = + options.delete(:serializer) || + resource.respond_to?(:active_model_serializer) && + resource.active_model_serializer + + options[:scope] = serialization_scope unless options.has_key?(:scope) + + serializer.new(resource, options) + end + end +end diff --git a/lib/active_model_serializers.rb b/lib/active_model_serializers.rb new file mode 100644 index 00000000..3f9c8873 --- /dev/null +++ b/lib/active_model_serializers.rb @@ -0,0 +1,13 @@ +require 'newbase/active_model/serializer' +require 'newbase/active_model/serializer_support' + +begin + require 'action_controller' + require 'newbase/action_controller/serialization' + + ActiveSupport.on_load(:action_controller) do + include ::ActionController::Serialization + end +rescue LoadError + # rails not installed, continuing +end diff --git a/test/integration/action_controller/serialization_test.rb b/test/integration/action_controller/serialization_test.rb new file mode 100644 index 00000000..16477c16 --- /dev/null +++ b/test/integration/action_controller/serialization_test.rb @@ -0,0 +1,172 @@ +require 'newbase/test_helper' +require 'newbase/active_model_serializers' + +module ActionController + module Serialization + class ImplicitSerializerTest < ActionController::TestCase + class Model + include ActiveModel::SerializerSupport + + def initialize(hash={}) + @attributes = hash + end + + def read_attribute_for_serialization(name) + @attributes[name] + end + end + + class ModelSerializer < ActiveModel::Serializer + attributes :attr1, :attr2 + end + + class MyController < ActionController::Base + def render_using_implicit_serializer + render :json => Model.new(attr1: 'value1', attr2: 'value2', attr3: 'value3') + end + end + + tests MyController + + def test_render_using_implicit_serializer + get :render_using_implicit_serializer + assert_equal 'application/json', @response.content_type + assert_equal '{"attr1":"value1","attr2":"value2"}', @response.body + end + end + + class ImplicitSerializerScopeTest < ActionController::TestCase + class Model + include ActiveModel::SerializerSupport + + def initialize(hash={}) + @attributes = hash + end + + def read_attribute_for_serialization(name) + @attributes[name] + end + end + + class ModelSerializer < ActiveModel::Serializer + attributes :attr1, :attr2 + + def attr2 + object.read_attribute_for_serialization(:attr2) + '-' + scope + end + end + + class MyController < ActionController::Base + def render_using_implicit_serializer_and_scope + render :json => Model.new(attr1: 'value1', attr2: 'value2', attr3: 'value3') + end + + protected + + def current_user + 'current_user' + end + end + + tests MyController + + def test_render_using_implicit_serializer_and_scope + get :render_using_implicit_serializer_and_scope + assert_equal 'application/json', @response.content_type + assert_equal '{"attr1":"value1","attr2":"value2-current_user"}', @response.body + end + end + + class ExplicitSerializerScopeTest < ActionController::TestCase + class Model + include ActiveModel::SerializerSupport + + def initialize(hash={}) + @attributes = hash + end + + def read_attribute_for_serialization(name) + @attributes[name] + end + end + + class ModelSerializer < ActiveModel::Serializer + attributes :attr1, :attr2 + + def attr2 + object.read_attribute_for_serialization(:attr2) + '-' + scope + end + end + + class MyController < ActionController::Base + def render_using_implicit_serializer_and_explicit_scope + render json: Model.new(attr1: 'value1', attr2: 'value2', attr3: 'value3'), scope: current_admin + end + + private + + def current_user + 'current_user' + end + + def current_admin + 'current_admin' + end + end + + tests MyController + + def test_render_using_implicit_serializer_and_explicit_scope + get :render_using_implicit_serializer_and_explicit_scope + assert_equal 'application/json', @response.content_type + assert_equal '{"attr1":"value1","attr2":"value2-current_admin"}', @response.body + end + end + + class OverridingSerializationScopeTest < ActionController::TestCase + class Model + include ActiveModel::SerializerSupport + + def initialize(hash={}) + @attributes = hash + end + + def read_attribute_for_serialization(name) + @attributes[name] + end + end + + class ModelSerializer < ActiveModel::Serializer + attributes :attr1, :attr2 + + def attr2 + object.read_attribute_for_serialization(:attr2) + '-' + scope + end + end + + class MyController < ActionController::Base + def render_overriding_serialization_scope + render json: Model.new(attr1: 'value1', attr2: 'value2', attr3: 'value3') + end + + private + + def current_user + 'current_user' + end + + def serialization_scope + 'current_admin' + end + end + + tests MyController + + def test_render_overriding_serialization_scope + get :render_overriding_serialization_scope + assert_equal 'application/json', @response.content_type + assert_equal '{"attr1":"value1","attr2":"value2-current_admin"}', @response.body + end + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 59932deb..f5b1f10e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,5 +1,19 @@ -ENV['RAILS_ENV'] = 'test' - require 'bundler/setup' -require 'rails' -require 'rails/test_help' +require 'newbase/active_model_serializers' +require 'test/unit' + +module TestHelper + Routes = ActionDispatch::Routing::RouteSet.new + Routes.draw do + get ':controller(/:action(/:id))' + get ':controller(/:action)' + end + + ActionController::Base.send :include, Routes.url_helpers +end + +ActionController::TestCase.class_eval do + def setup + @routes = TestHelper::Routes + end +end