ActiveModel Serializer JSONAPI included resource - active-model-serializers

I am working with ActiveModel Serializer's JSONAPI adapter and I'm trying to include a "user" resource when I serialize a "video" resource. Currently my video serializer looks something like this:
class VideoSerializer < ActiveModel::Serializer
attributes :id, :uploaded_at, :title, :description
belongs_to :user
has_many :comments
included :user
end
I've spent some time looking through the recently closed issues here: https://github.com/rails-api/active_model_serializers/issues and it looks like this feature should be complete in the latest release I just can't seem to get it to work. Does anyone see what I might be doing wrong?

There is no included method defined in the serializer DSL. There is, though, an included adapter option, that allows one to specify which related resources should be included in the response document.
In your case (in your controller):
render json: videos, adapter: :json_api, include: 'user'

Related

Pyramid routing to class methods

From the pyramid documentation, there exists an attr argument on configurator's add_view that states:
The attr value allows you to vary the method attribute used
to obtain the response. For example, if your view was a
class, and the class has a method named index and you
wanted to use this method instead of the class' __call__
method to return the response, you'd say attr="index" in the
view configuration for the view.
With this in mind, I'd like to route all requests under /myrequest to the class MyRequest. Given the following class:
#view_defaults(renderer='json')
class MyHandler(object):
def __init__(self, request):
self.request = request
def start(self):
return {'success': True}
def end(self):
return {'success': True}
It would seem the way to do this would be in the configuration, add these lines:
config.add_view(MyHandler, '/myrequest', attr='start')
config.add_view(MyHandler, '/myrequest', attr='end')
and so on, for all the methods I want routed under MyHandler. Unfortunately this doesn't work. The correct way to do this appears to be:
config.add_route('myroutestart', '/myroute/start')
config.add_route('myrouteend', '/myroute/end')
config.add_view(MyHandler, attr='start', route_name='myroutestart')
config.add_view(MyHandler, attr='end', route_name='myrouteend')
This seems like an awful lot of boilerplate. Is there a way to bring this down to 1 line per route? Or more ideally, 1 line per class?
Example #4 in the Route and View Examples from The Pyramid Community Cookbook v0.2, Pyramid for Pylons Users, offers the following.
# Pyramid
config.add_route("help", "/help/{action}")
#view_config(route_name="help", match_param="action=help", ...)
def help(self): # In some arbitrary class.
...
Although this cookbook recipe mentions pyramid_handlers as one option to do this, the article "Outgrowing Pyramid Handlers" by one of the maintainers of Pyramid encourages the use of Pyramid's configuration.

How do I structure my Django view classes?

I and a friend are about working on a project. I have a structure for working with my views. If I'm working with the User model, and I want to write code for CRUD operation, I write using four different classes. One for each like so:
class CreateUser(FormView):
<code here>
class ReadUser(DetailView):
<code here>
class UpdateUser(UpdateView):
<code here>
class DeleteUser(DeleteView):
<code here>
Each has a respective URL pattern:
urlpatterns = [
path("auth/users/create-user/", CreateUser().as_view(), name="create_user"),
path("auth/users/<int:pk>", ReadUser().as_view(), name="user_detail"),
path("auth/users/<int:pk>/update", UpdateUser().as_view(), name="update_user"),
path("auth/users/<int:pk>/delete/", DeleteUser().as_view(), name="delete_user")
]
He proposes that instead, all functionalities should be in one class and performed by methods, like so:
class UserView(View):
<class variables>
def post(self, request):
<code here>
def get(self, request):
<code here>
def patch(self, request):
<code here>
def delete(self, request):
<code here>
And the urlpatterns be:
urlpatterns = [
path("auth/users/", UserView.as_view(), name="user")
]
The questions I have are which is better:
Django-wise;
Generally;
When rendering from server side in django;
When writing APIs in django
The first or the second one?
I think your friend's proposal goes the right way and I would go a little bit further.
I recommend you using Django Rest Framework. It already has Class-based views that can save you a lot of time of coding.
Depending on the degree of customization you want to introduce you may choose between:
API Views or Generics Classes with Mixins
Also, I will be careful about mixing user registration and user authentication. It is quite usual to keep the resource "user(s)" and "auth" apart.
As a last advice, I will recommend you to avoid building the registration and authentication process by yourself - although it is a good learning exercise and go for an existing solution, either by public repositories or the wide variety of libraries out there that can provide you with token generation, OAUTH2, social register and authentication (Social Django f.i.) and many more.

Migrating Active Model Serializer from 0.8 to 0.10 rc2

We've got an API built with Grape and Active Model Serializers 0.8. Now we would like to use all the caching goodness from 0.10, so a migration to the new backwards-incompatible version is in progress.
There are currently two issues right now:
It doesn't seem possible to redefine the root key with self.root= inside serializers. E.g. we've got SimpleUserSerializer and we want the root key to user instead of simple_user. A solution is to specify the root when rendering the serializer, but then we need to make the change in many places. Is there a way to redefine the root key for this serializers regardless of where/how it's rendered?
embed :ids, include: true option is not supported and should probably be implemented through an adapter. Are there any plans on releasing or maintaining 0.8-compatible adapter for legacy projects?
Any guidance about the migration would be helpful as I couldn't find any official documentation.
The first issue can be resolved by defining class method root_name which returns the root key. This can be seen in fixtures in AMS tests.
Still working on the second issue.
the official guide can be helpful:
https://github.com/rails-api/active_model_serializers/blob/0-10-stable/docs/howto/upgrade_from_0_8_to_0_10.md
If it does not help, try this:
In the previous version, we would specify the root as follows:
class UserSerializer < ActiveModel::Serializer
self.root = "application_user"
end
or:
class UserSerializer < ActiveModel::Serializer
root "application_user"
end
They both stopped working after the upgrade and we had to change it to:
class UserSerializer < ActiveModel::Serializer
type "application_user"
end
And this:
Root key not included in JSON
To fix that we had to configure json as the adapter (the new library default is attributes).
ActiveModelSerializers.config.adapter = :json
The full upgrade guide here:
http://engineering.liefery.com/2017/11/07/upgrading-active-model-serializers-from-0-8-to-0-10.html

acts_as_tree and active_model_serializer

Currently I'm building an API where I have a model functioning as a category. The category has possible subcategories and/or a single parent category created using the acts_as_tree gem. I wish to serialize the category model and it's relations to itself using active_model_serializers gem.
Note: active_model_serializer uses the :json_api adapter
class NutritionCategory < ActiveRecord::Base
has_many :nutritions
acts_as_tree
end
class NutritionCategorySerializer < ActiveModel::Serializer
attributes :id, :name, :description
has_many :nutritions, embed: :ids
end
Since acts_as_tree does all the 'magic' I can't seem to find a way to serialize this relationship properly. How do I define the relationship in the serializer?
I'm using Ruby 2.2.1 with the following gems:
Rails (4.2.1)
acts_as_tree (2.1.0)
active_model_serializers (0.10.0.pre)
Try adding to your serializer:
has_many :children, embed: :ids

Error with associations using Active Model Serializers

When rendering the json of a model with nested associations I get the following error:
undefined method `serializable_hash' for #<ActiveModel::ArraySerializer:0x007fe761592d88>
This is my code:
class EventSerializer < ActiveModel::Serializer
attributes :id, :name, :date
has_many :markets
end
class MarketSerializer < ActiveModel::Serializer
attributes :id, :bet_limit_time
has_many :options
end
class OptionSerializer < ActiveModel::Serializer
attributes :id, :name, :odds
end
The error appears when rendering the options association.
It's a pretty simple case, but I have found no issue about it.
I think it's a problem with having an attribute named options. See https://stackoverflow.com/a/16005874/157943:
"It turns out that using :option as a property name was causing conflicts. There are probably other conflicting names as well. Gotta be careful about the namespace!"
Not sure how to fix it other than renaming the options association (possibly you could build it manually by overriding #attributes and constructing the hash manually?)

Resources