In my controller I still want to render an arbitrary Hash as json with an option to set response status. So, while in one action I'd like to use AMS implicitly with render json: @object , I'd still like to use something like render json: { message: message }, status: status without hitting the AMS.
(e.g., detailed walkthrough, runnable script, example application)
def some_action
...
message = 'Incorrect URL'
status = :bad_request
render json: { message: message }, status: status
end
ActiveModelSerializers Version (commit ref if not on tag): 0.10.4
Output of ruby -e "puts RUBY_DESCRIPTION": ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin15]
OS Type & Version: Mac OS X 10.11.6
Integrated application and version (e.g., Rails, Grape, etc): Rails 5.0.1
Default adapter.
(e.g., provide any applicable backtraces from your application)
[active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.14ms)
I'd need to run some benchmark to determine if it actually slows down the response significantly or not.
@januszm yeah, this is an annoying issue we need to fix. In the meantime, you should be able to render json: { message: message }.to_json, status: :bad_request
I don't think it actually is doing any transformation, just checking if it can find a serializer, and then returning the value when it can't, but it goes through the logger when doing that leaving that annoying message
@bf4 one other issue though is that when specifying adapter: false # or nil, SerializableResource still tries to fetch a serializer whereas it should not.
@bf4 thanks actually to_json was not needed after that hash. It's working fine as render json: { message: message }, status: status
Anyway, looks like the Null serializer is used >only< here, in the logger:
lib/active_model_serializers/logging.rb:85: serializer: serializer || ActiveModel::Serializer::Null
I've just tried a short circuit in LogSubscriber#render and removing the Null serializer , helped but I'm not sure where else you use that Null serializer.
def notify_render_payload
{
serializer: serializer, # don't use Null serializer
adapter: adapter || ActiveModelSerializers::Adapter::Null
...
class LogSubscriber < ActiveSupport::LogSubscriber
def render(event)
return unless event.payload[:serializer] # render nothing
...
We could mention that in the docs (eg. 'When you serialize a "hash" you'll see Null serializer mentioned in the logs').
Also, it feels like it shouldn't hit the SerializableResource unless the serialized resource is a model or association.
@januszm this should probably not appear in AMS logs or should appear as something like rendered without AMS: no serializer found. That is way clearer than specifying rended with Null serializer and mention it in the docs. There are some fixes to be done here.
@groyoh yes I agree, that's why I tried the patch above which removes the message from the logs entirely (notice return unless event.payload[:serializer]). I also agree that there are some fixes to be done, that's what I mentioned that in my last phrase, I wouldn't touch the SerializableResource class unless the object that we want to serialize is somehow related to ActiveModel / ActiveRecord.
this should probably not appear in AMS logs
@groyoh yes, it's an undesired effect of a change (bug fix) in how serializable resource works in the controller...
as https://github.com/rails-api/active_model_serializers/issues/2024#issuecomment-271719008
specifying adapter: false # or nil, SerializableResource still tries to fetch a serializer
warn 'ActionController::Serialization#use_adapter? has been removed. '\
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
options[:adapter] = false
yeah, I guess get_serializer could return early for that... code design...
# 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 #=> '""'`
serializable_resource.adapter.is_a?(String) ? serializable_resource.adapter : serializable_resource
might want to check if adapter is an adapter, instead...
Does anyone know has a fix been identified for this issue yet? Or a work around? Looks like it's ready for PR for a couple of months now 🤔
@travega Not fixed. Not one's done it :)
I have these notes in my initializer that might be helpful. If you're using an exceptions_app that inherits from action controller, you may need to set serialization_scope :view_context # so ActiveModelSerializers doesn't call current_user
ActiveSupport.on_load(:action_controller) do
require 'active_model_serializers/register_jsonapi_renderer'
ActiveModelSerializers.eager_load! if Rails.env.production?
ActiveModelSerializers::Adapter::JsonApi.eager_load! if Rails.env.production?
require 'active_model/serializer/null'
ActiveModel::Serializer::Null
# https://github.com/rails-api/active_model_serializers/blob/a032201a91cbca407211bca0392ba881eef1f7ba/lib/active_model_serializers/logging.rb#L83-L87
# def notify_render_payload
# {
# serializer: serializer || ActiveModel::Serializer::Null,
# adapter: adapter || ActiveModelSerializers::Adapter::Null
# }
# end
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/active_model_serializers-0.10.2/lib/active_model_serializers/logging.rb:85:in `notify_render_payload'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/active_model_serializers-0.10.2/lib/active_model_serializers/logging.rb:78:in `notify_render'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/active_model_serializers-0.10.2/lib/active_model_serializers/logging.rb:21:in `block (2 levels) in instrument_rendering'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/active_model_serializers-0.10.2/lib/active_model_serializers/logging.rb:97:in `tag_logger'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/active_model_serializers-0.10.2/lib/active_model_serializers/logging.rb:20:in `block in instrument_rendering'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/activesupport-4.2.7.1/lib/active_support/callbacks.rb:81:in `run_callbacks'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/active_model_serializers-0.10.2/lib/active_model_serializers/logging.rb:68:in `block (2 levels) in notify'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.7.1/lib/action_controller/metal/renderers.rb:116:in `block in <module:Renderers>'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/active_model_serializers-0.10.2/lib/action_controller/serialization.rb:53:in `block (2 levels) in <module:Serialization>'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.7.1/lib/action_controller/metal/renderers.rb:45:in `block in _render_to_body_with_renderer'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.7.1/lib/action_controller/metal/renderers.rb:41:in `_render_to_body_with_renderer'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.7.1/lib/action_controller/metal/renderers.rb:37:in `render_to_body'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.7.1/lib/action_controller/metal/instrumentation.rb:43:in `render'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/remotipart-1.2.1/lib/remotipart/render_overrides.rb:14:in `render_with_remotipart'
# /srv/rails_server/app/controllers/exception_handler/exception_controller.rb:21:in `block (2 levels) in show'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.7.1/lib/action_controller/metal/mime_responds.rb:217:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/actionpack-4.2.7.1/lib/action_controller/metal/mime_responds.rb:217:in `respond_to'
# /srv/rails_server/app/controllers/exception_handler/exception_controller.rb:20:in `show'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/lograge-0.4.1/lib/lograge/rails_ext/rack/logger.rb:15:in `call_app'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/railties-4.2.7.1/lib/rails/rack/logger.rb:22:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/rack-1.6.4/lib/rack/sendfile.rb:113:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/skylight-1.0.0/lib/skylight/middleware.rb:61:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/railties-4.2.7.1/lib/rails/engine.rb:518:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/railties-4.2.7.1/lib/rails/application.rb:165:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/puma-3.5.2/lib/puma/configuration.rb:225:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/puma-3.5.2/lib/puma/server.rb:569:in `handle_request'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/puma-3.5.2/lib/puma/server.rb:406:in `process_client'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/puma-3.5.2/lib/puma/server.rb:271:in `block in run'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/puma-3.5.2/lib/puma/thread_pool.rb:116:in `call'
# /srv/rails_server/vendor/bundle/ruby/2.2.0/gems/puma-3.5.2/lib/puma/thread_pool.rb:116:in `block in spawn_thread't
end
I have the same problem. When I use AMS implicitly with render json: @data, it's work perfect. But when I use it in hash:
def json_response messages, data, status = :ok
render json: {
messages: messages,
data: data
}, status: status
end
I got error: Rendered ActiveModel::Serializer::Null with Hash.
Does anyone solve it ?
Call to_json on your hash
B mobile phone
On Aug 9, 2017, at 8:44 PM, Tran B. V. Son notifications@github.com wrote:
I have the same problem. When I use AMS implicitly with render json: @data, it's work perfect. But when I use it in hash:
def json_response messages, data, status = :ok
render json: {
messages: messages,
data: data
}, status: status
end
I got error: Rendered ActiveModel::Serializer::Null with Hash.
Does anyone solve it ?—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
@bf4 It doesn't work :(
def json_response messages, data, status = :ok
render json: {
messages: messages,
data: data
}.to_json, status: status
end
Well, without any more details on how it doesn't work I don't have anything tp add except don't serialize hashes... uses either records or strings
B mobile phone
On Aug 9, 2017, at 9:20 PM, Tran B. V. Son notifications@github.com wrote:
@bf4 It doesn't work :(
def json_response messages, data, status = :ok
render json: {
messages: messages,
data: data
}.to_json, status: status
end
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
Actually to_json worked for me while sending hash in render render json: @status.to_json and i didn't get any message like Rendered ActiveModel::Serializer::Null with Hash after rendering but it should not be use to_json like that
@sree300994
after rendering but it should not be use to_json like that
Strongly disagree. AMS by design ignores any string, such as the result of to_json. So, this is a natural way to skip AMS. AMS doesn't serialize a Hash because it's a primitive, not a model. Discussed in readme.
yaa its correct maybe their might be change in naming convention of serializer. what i mean is if the controller in normal controllers folder and the serializer might be created in versioning means it will through this error. The example is class UsersController < ApplicationController this is how i created controller but the serializer i created is like class Api::V1::UserSerializer < ActiveModel::Serializer by creating like this it thrown me error, after changing serializer to class UserSerializer < ActiveModel::Serializer this, my error disappeared
yaa its correct maybe their might be change in naming convention of serializer. what i mean is if the controller in normal controllers folder and the serializer might be created in versioning means it will through this error. The example is
class UsersController < ApplicationControllerthis is how i created controller but the serializer i created is likeclass Api::V1::UserSerializer < ActiveModel::Serializerby creating like this it thrown me error, after changing serializer toclass UserSerializer < ActiveModel::Serializerthis, my error disappeared
When serializing a model inside a namespace, such as Api::V1::Post, ActiveModelSerializers will expect the corresponding serializer to be inside the same namespace (namely Api::V1::PostSerializer).