acts_as_tree and active_model_serializer - active-model-serializers

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

Related

Inheriting from both ABC and django.db.models.Model raises metaclass exception

I am trying to implement a Django data model class, which is also an interface class, using Python 3. My reason for doing so is, I'm writing a base class for my colleague, and need him to implement three methods in all of the classes he derives from mine. I am trying to give him a simplified way to use the functionality of a system I've designed. But, he must override a few methods to supply the system with enough information to execute the code in his inherited classes.
I know this is wrong, because it's throwing exceptions, but I'd like to have a class like the following example:
from django.db import models
from abc import ABC, abstractmethod
class AlgorithmTemplate(ABC, models.Model):
name = models.CharField(max_length=32)
#abstractmethod
def data_subscriptions(self):
"""
This method returns a list of topics this class will subscribe to using websockets
NOTE: This method MUST be overriden!
:rtype: list
"""
I understand I could avoid inheriting from the ABC class, but I'd like to use it for reasons I won't bore you with here.
The Problem
After including a class, like the one above, into my project and running python manage.py makemigrations I get the error: TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases. I have searched Stack Overflow, but have only find solutions like the following one:
class M_A(type): pass
class M_B(type): pass
class A(metaclass=M_A): pass
class B(metaclass=M_B): pass
class M_C(M_A, M_B): pass
class C:(A, B, metaclass=M_C): pass
I've read the following posts:
Using ABC, PolymorphicModel, django-models gives metaclass conflict
Resolving metaclass conflicts
And I've tried many variations of those solutions, but I still get the dreaded metaclass exception. Help me Obi-Wan Kenobi, you're my only hope. :-)
I had the same need and found this. I've altered the code for clarity and completeness. Basically you need an extra class which you can use for all your model interfaces.
import abc
from django.db import models
class AbstractModelMeta(abc.ABCMeta, type(models.Model)):
pass
class AbstractModel(models.Model, metaclass=AbstractModelMeta):
# You may have common fields here.
class Meta:
abstract = True
#abc.abstractmethod
def must_implement(self):
pass
class MyModel(AbstractModel):
code = models.CharField("code", max_length=10, unique=True)
class Meta:
app_label = 'my_app'
test = MyModel(code='test')
> TypeError: Can't instantiate abstract class MyModel with abstract methods must_implement
Now you have the best of both worlds.
I found a solution that worked for me, so thought I would post it here in case it helps someone else. I decided to not inherit from the ABC class, and instead just raise an exception in the "abstract" methods (the ones the derived class must implement). I did find helpful information in the Django docs, describing using Django data models as an Abstract base class and also Multi-table inheritance.
Django Data Model as an Abstract Base Class
Quoted from the docs:
Abstract base classes are useful when you want to put some common information into a number of other models. You write your base class and put abstract=True in the Meta class. This model will then not be used to create any database table. Instead, when it is used as a base class for other models, its fields will be added to those of the child class.
An example:
from django.db import models
class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
class Meta:
abstract = True
class Student(CommonInfo):
home_group = models.CharField(max_length=5)
The Student model will have three fields: name, age and home_group.
The CommonInfo model cannot be used as a normal Django model, since it
is an abstract base class. It does not generate a database table or
have a manager, and cannot be instantiated or saved directly.
Fields inherited from abstract base classes can be overridden with
another field or value, or be removed with None.
Multi-table Inheritance with a Django Data Model
My understanding of "multi-table inheritance" is, you can define a data model and then also use it as a base class for a second data model. The second data model will inherit all the fields from the 1st model, plus its own fields.
Quoted from the docs:
The second type of model inheritance supported by Django is when each
model in the hierarchy is a model all by itself. Each model
corresponds to its own database table and can be queried and created
individually. The inheritance relationship introduces links between
the child model and each of its parents (via an automatically-created
OneToOneField). For example:
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
All of the fields of Place will also be available in Restaurant,
although the data will reside in a different database table. So these
are both possible:
>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

ActiveModel Serializer JSONAPI included resource

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'

Generating the otherEntityField From Modelio using jhipster-uml on a one-to-many relationship

I am trying to generate a Jhipster(2.27.0) application from Modelio(3.4.1) model with JHipster-UML(1.6.0).
On this example I have a one-to-many relationship between 2 entities (assessment and answer).
I want to generate the 'otherEntityField' allowing to browse the relation through text and not ID.
The only way I manage to do that was to setup a bidirectional one-to-many relationship like this:
Image one-to-many Modelio relationship
And after jhipster-uml generate the code, I have to change the generated entity "Assessment.java".
The #OneToMany annotation should use "assessment" mappedBy parameter and not "assessment(entity)".
Before changes:
#OneToMany(mappedBy = "assessment(entity)")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Answer> answers = new HashSet<>();
After changes:
#OneToMany(mappedBy = "assessment")
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Answer> answers = new HashSet<>();
After that, it works.
Is this a bug from jhipster-uml or is there a way to generate directly the "otherEntityField" ?
In more concise question : How do you manage a bidirectional one-to-many relationship jhipster-uml generation with "otherEntityField" ?
This issue was a bug in jhipster-uml.
Issue:
https://github.com/jhipster/jhipster-uml/issues/132
Will be corrected in version 1.6.1.

Spring Data Mongo: mapping objects using Jackson annotations

I'm using spring-data Mongo (1.3.3) as a mechanism for accessing Mongo.
My domain objects are written in Groovy and I use Jackson annotations to define properties and names:
#JsonProperty('is_author')
boolean author = false
#JsonProperty('author_info')
AuthorInfo authorInfo
When I persist one of my domain objects to Mongo, the JsonProperty annotation is ignored and the field is persisted using the standard object's field name.
By digging in the Spring Data Mongo documentation, I found out that the library expects a #Field annotation to modify the actual field's name in Mongo.
Is there a way to use only the Jackson annotations instead of using two annotations to achieve the same results. Maybe a "customized" version of MappingMongoConverter?
Since my application is in Groovy, I have used the new #AnnotationCollectorAST Transformation (http://blog.andresteingress.com/2013/01/25/groovy-2-1-the-annotationcollector-annotation/) to "merge" the Jackson and the Spring Data Mongo annotations. Here is how it looks like: simple and effective!
package com.someapp
import com.fasterxml.jackson.annotation.JsonProperty
import groovy.transform.AnnotationCollector
import org.springframework.data.mongodb.core.mapping.Field
#AnnotationCollector([Field, JsonProperty])
public #interface JsonMongoProperty {}
And here is how it is used:
#JsonMongoProperty('is_author')
boolean author = false
#JsonMongoProperty('author_info')
AuthorInfo authorInfo

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