-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
root
key for :attributes adapter is pointless
#2350
Comments
Hi @LeKristapino that was unfortunate. but upgrading to the latest HEAD of the
This PR fixes the case: #2344 |
@LeKristapino I think I am wrong here. that PR does not fix the case yet! I see it now :( Actually that was kind of like a side-effect while implementing the can you please write a test for the scenario that you described, so that we can figure out an effective solution to avoid further side-effects related to this feature fix |
@wasifhossain I think it would take me some time to understand the differences in mechanics for calling |
@LeKristapino can you share some code to reproduce the fail case. Specifically how |
@LeKristapino If you're trying to serialize a primitive like a Hash, AMS will get confused. AMS is for models. There's no way AMS can know what to do with a Hash. I know this is documented both because I wrote it and because serializing Hashes comes up in issues periodically. When I've need to ensure that the thing I'm rendering doesn't use a serializer, I usually dump it to a string and pass that into the render arguments.
|
@LeKristapino as bf4 mentioned, can you try your issue on other AMS versions later than 0.10.5 but earlier than 0.10.10 and let us know how you found it? |
@wasifhossain The breaking change came after 0.10.9. As for the reason why I use AMS on a Hash - My DB JSON column has different key names as the API Response I am providing, but mostly it is so that I can create correctly formatted dates in the response instead of the plain format I have in my database JSON. Sometimes I need to improve my API response formatting with more accurate key names and such, and then it is far easier to do it through a serializer than to modify json in my DB to have the name corrected or improved. So I wouldn't say that there are no use-cases for Serializers being used on Hashes. Hope that helps |
@LeKristapino thanks for the insight. btw AMS should have already covered the case, like: formatting the attribute name or the value as needed by the api client, and that is exactly the role of the serializer instead of doing anywhere else for an api response; which you got right - to do it in the serializer. the only gotcha here is, if you need to change the name/value of a DB-backed field, then you can do it through your model instance, instead of passing it as a hash. docs/general/serializers.md#attributes lists down how to customize the behavior, in case you need it. Still if you find it hard to figure out, we would appreciate if you can provide some mock example of how the field(s) looks like in the DB and how do you like to serialize it. |
I guess a good example would be something like: DB has JSONB column a persisted
then
and
Maybe the particular example doesn't make sense with JSON column being used, but I hope you get my point. Of course I could make a separate model for the JSON column where I essentially would be doing the same things as in the serializer, but since all of these actions are pretty much for the API it makes more sense to do it straight in the serializer as putting this stuff in a model and then in a serializer just creates overhead. |
@LeKristapino Thanks The problem is that |
@bf4 Right now my example works just fine (minus the Wouldn't it be smarter to just support this use-case as well since it does not require any extra coding, just some tests which I could provide a PR with so that this functionality does not break with future impeovements |
@LeKristapino I'd be interested in see a PR with a Hash serializer, even if just as a test implementation for example, and not included in lib. It's been brought up before. I don't follow the case myself. |
I believe I am having the same issue. Definitely works with 0.10.9, does not work with 0.10.10. I am passing a hash, root is false, attributes adapter. I get NoMethodError (described in the conversation for #2223). |
I'm honestly surprised that a Hash works at all as an input or that it would ever be the intended input object. |
I've got the same problem going from |
We just took it back down to 0.10.9 |
@Loschcode @bmelton-mdsol I don't have a failing test to fix. Based on the discussion, looks like y'all were relying on some behavior that should never have existed in the first place, and I'm not even sure what that behavior is. Seems to me that the test case would be something like the below. Though why I'm trying to figure this out and not any of y'all is beyond me class AbstractHashSerializer < ActiveModel::Serializer
def self.attributes(*attrs)
super.tap do
attrs.each do |hash_key|
define_method(hash_key.to_sym) do
object[hash_key]
end
end
end
end
end
class MyHashSerializer < AbstractHashSerializer
attributes :name
end
object = { name: "Benjamin" }
serializer_instance = MyHashSerializer.new(object)
# 0.10.9
serializer_instance.as_json #=> { name: "benjamin" }
# 0.10.10
serializer_instance.as_json #=> NoMethodError
class MyRootlessHashSerializer < MyHashSerializer
def initialize(object, options = {})
super
self.root = ''
end
# or maybe `def json_key; nil; end` dunno
end
object = { name: "Benjamin" }
serializer_instance = MyHashSerializer.new(object)
# 0.10.9
serializer_instance.as_json #=> { name: "benjamin" }
# 0.10.10
serializer_instance.as_json #=> { name: "benjamin" } |
You can use this workaround: # config/initializers/fix_active_model_serializers.rb
# Remove `root` key for `attributes` adapter.
# Remove this monkey patch once the upstream codebase gets fixed.
# https://github.com/rails-api/active_model_serializers/issues/2350
module ActiveModel
class Serializer
def json_key
root || _type ||
begin
object.class.model_name.to_s.underscore
rescue ArgumentError, NoMethodError
'anonymous_object'
end
end
end
end |
@blackst0ne that is a dangerous fix for anything that might ever use another adapter as discussed above. you mention
has anyone proposed something? I'm just trying to garden here. |
as a workaround, we added
and all other serializers just inherit from it. |
I've just updated our app to rails 6 which meant also updating active_model_serializers and also came across this issue. In our case we have some collection serializers that serialize ActiveRecord::ActiveRecord_Relation objects and include custom fields e.g. class CustomCollectionSerializer < ActiveModel::Serializer
attributes :active_count, :entries
def active_count
object.sum(&:active_count)
end
def entries
object.map do |entry|
ActiveModelSerializers::SerializableResource.new(entry)
end
end
end The change introduced in #998 changed the way that the root was defined which now prevents non-AR models from working. If root isn't required for the attributes adapter this method should probably just check if root is even required and return early |
@JoeWoodward firstly, I agree with this issue which you're commenting on it's unclear to me what version of AMS you're upgrading since the commit you point to implies you're changing 'major' versions from 0.8 or 0.9, but your example demonstrates some work done in the 0.10 way, but your comment about preventing non-AR models from working ignores that most of the test suite runs non-AR models and support all-over-the-place for non-AR models, including a linter... so, again, I'm 👍 on someone fixing the Attributes adapter, but I'm not confident that's your precise issue. Hopefully my reply here helps pushing someone who isn't me to propose a PR. otherwise, we're all just agreeing. |
object.class.model_name.to_s is not likely to get def json_key
root || _type ||
begin
object.class.model_name.to_s.underscore
rescue ArgumentError
'anonymous_object'
end
end |
Before upgrading from 0.10.5 to 0.10.10 this line worked without any errors
Now it produces an error
undefined method 'model_name' for Hash:Class
.Adding a
root
parameter (for example..., serializer: SomeCustomSerializer, root: ''
fixes the issue.BUT from the documentation here I figure that
root
is not even used for:attributes
adapter.My question is, shouldn't it be ignored in the
Attribute
andJSON API
adapters, thus avoiding breaking the example serialization. Or have I missed some extra functionality thatroot
provides?The text was updated successfully, but these errors were encountered: