diff --git a/lib/action_controller/serialization.rb b/lib/action_controller/serialization.rb index 3097cdc4..e8d5a420 100644 --- a/lib/action_controller/serialization.rb +++ b/lib/action_controller/serialization.rb @@ -30,8 +30,8 @@ module ActionController options[:adapter] = false end serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options) - serializable_resource.serialization_scope ||= serialization_scope - serializable_resource.serialization_scope_name = _serialization_scope + serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope } + serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope } # For compatibility with the JSON renderer: `json.to_json(options) if json.is_a?(String)`. # Otherwise, since `serializable_resource` is not a string, the renderer would call # `to_json` on a String and given odd results, such as `"".to_json #=> '""'` diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index e8607845..c3193120 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -96,16 +96,18 @@ module ActiveModel end end - def self._serializer_instance_method_defined?(name) - _serializer_instance_methods.include?(name) + # rubocop:disable Style/ClassVars + def self.method_added(method_name) + @@_serializer_instance_methods ||= Hash.new { |h, k| h[k] = Set.new } + @@_serializer_instance_methods[self] << method_name end - # TODO: Fix load-order failures when different serializer instances define different - # scope methods - def self._serializer_instance_methods - @_serializer_instance_methods ||= (public_instance_methods - Object.public_instance_methods).to_set + def self._serializer_instance_method_defined?(name) + @_serializer_instance_methods ||= (ActiveModel::Serializer.public_instance_methods - Object.public_instance_methods).to_set + @_serializer_instance_methods.include?(name) || + @@_serializer_instance_methods[self].include?(name) end - private_class_method :_serializer_instance_methods + # rubocop:enable Style/ClassVars attr_accessor :object, :root, :scope diff --git a/test/action_controller/serialization_scope_name_test.rb b/test/action_controller/serialization_scope_name_test.rb index 5ad7251b..ca1ff22f 100644 --- a/test/action_controller/serialization_scope_name_test.rb +++ b/test/action_controller/serialization_scope_name_test.rb @@ -158,8 +158,6 @@ module SerializationScopeTesting assert_equal expected_json, @response.body end end - # FIXME: Has bugs. See comments below and - # https://github.com/rails-api/active_model_serializers/issues/1509 class NilSerializationScopeTest < ActionController::TestCase class PostViewContextTestController < ActionController::Base serialization_scope nil @@ -171,12 +169,15 @@ module SerializationScopeTesting render json: new_post, serializer: PostSerializer, adapter: :json end - # TODO: run test when - # global state in Serializer._serializer_instance_methods is fixed - # def render_post_with_passed_in_scope - # self.current_user = User.new(id: 3, name: 'Pete', admin: false) - # render json: new_post, serializer: PostSerializer, adapter: :json, scope: current_user, scope_name: :current_user - # end + def render_post_with_passed_in_scope + self.current_user = User.new(id: 3, name: 'Pete', admin: false) + render json: new_post, serializer: PostSerializer, adapter: :json, scope: current_user, scope_name: :current_user + end + + def render_post_with_passed_in_scope_without_scope_name + self.current_user = User.new(id: 3, name: 'Pete', admin: false) + render json: new_post, serializer: PostSerializer, adapter: :json, scope: current_user + end private @@ -194,8 +195,6 @@ module SerializationScopeTesting assert_nil @controller.serialization_scope end - # TODO: change to NoMethodError and match 'admin?' when the - # global state in Serializer._serializer_instance_methods is fixed def test_nil_scope if Rails.version.start_with?('4.0') exception_class = NoMethodError @@ -210,21 +209,34 @@ module SerializationScopeTesting assert_match exception_matcher, exception.message end - # TODO: run test when - # global state in Serializer._serializer_instance_methods is fixed - # def test_nil_scope_passed_in_current_user - # get :render_post_with_passed_in_scope - # expected_json = { - # post: { - # id: 4, - # title: 'Title', - # body: "The 'scope' is the 'current_user': true", - # comments: [ - # { id: 2, body: 'Scoped' } - # ] - # } - # }.to_json - # assert_equal expected_json, @response.body - # end + def test_serialization_scope_is_and_nil_scope_passed_in_current_user + get :render_post_with_passed_in_scope + expected_json = { + post: { + id: 4, + title: 'Title', + body: "The 'scope' is the 'current_user': true", + comments: [ + { id: 2, body: 'Scoped' } + ] + } + }.to_json + assert_equal expected_json, @response.body + end + + def test_serialization_scope_is_nil_and_scope_passed_in_current_user_without_scope_name + get :render_post_with_passed_in_scope_without_scope_name + expected_json = { + post: { + id: 4, + title: 'Title', + body: "The 'scope' is the 'current_user': true", + comments: [ + { id: 2, body: 'Scoped' } + ] + } + }.to_json + assert_equal expected_json, @response.body + end end end