Migrating Active Model Serializer from 0.8 to 0.10 rc2 - active-model-serializers

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

Related

Spring Session with Hazelcast 4

I'm trying to upgrade to Hazelcast 4.0 in our Spring Boot 2.2.1 application.
We use the #EnableHazelcastHttpSession annotation, which pulls in HazelcastHttpSessionConfiguration, which pulls in HazelcastIndexedSessionRepository from the spring-session-hazelcast jar.
However, this class won't compile because it imports Hazelcast's IMap which has moved to a different package in Hz 4.0.
Is there any way to fix this so that Spring Session works with Hazelcast 4?
I just copied the HazelcastIndexedSessionRepository into my own source code, changed the import from com.hazelcast.core.IMap to com.hazelcast.map.IMap, and swapped the sessionListenerId from String to UUID. If I keep it in the same package, then it loads my class instead of the one in the jar, and everything compiles and works fine.
Edit: We no longer get the SessionExpiredEvent, so something's not quite right, but manual testing shows us that our sessions do time out and force the user to log in again, even across multiple servers.
I found the cause of the error, you must look that the session repository is created by HazelcastHttpSessionConfiguration, in the class it checks wich version of hazelcast is in the classpath, when hazelcast4 is true then it instantiates Hazelcast4IndexedSessionRepository that doesn't use 'com.hazelcast.core.IMap' and you don't get the class not found exception.
Code of class HazelcastHttpSessionConfiguration
#Bean
public FindByIndexNameSessionRepository<?> sessionRepository() {
return (FindByIndexNameSessionRepository)(hazelcast4 ? this.createHazelcast4IndexedSessionRepository() : this.createHazelcastIndexedSessionRepository());
}
Remove the usage of HazelcastIndexedSessionRepository replace it with Hazelcast4IndexedSessionRepository or remove the code and let spring autoconfiguration do the job by HazelcastHttpSessionConfiguration

Dynamically generate Flask-RESTPlus routes

I am trying to abstract away some of the route class logic (i.e. I am looking to dynamically generate routes). api.add_resource seemed like the right place to do this.
So this is what I am trying to do:
# app.py
from flask import Flask
from flask_restplus import Api, Resource, fields
from mylib import MyPost
# Define my model
json_model = api.schema_model(...)
api.add_resource(
MyPost,
'/acme',
resource_class_kwargs={"json_model": json_model}
)
And then in mylib:
# mylib.py
def validate_endpoint(f):
def wrapper(*args, **kwargs):
return api.expect(json_fprint)(f(*args, **kwargs))
return wrapper
class MyPost(Resource):
def __init__(self, *args, **kwargs):
# Passed in via api.add_resource
self.api = args[0]
self.json_model = kwargs['json_model']
# I can't do this because I don't have access to 'api' here...
# #api.expect(json_model)
# So I am trying to make this work
#validate_endpoint
def post(self):
return {"data":'some data'}, 200
I don’t have access to the global api object here so I can’t call #api.expect(json_model). But I do have access to api and json_model inside of the post method. Which is why I am trying to create my own validate_endpoint decorator.
This does not work though. Is what I am trying to do here even possible? Is there a better approach I should be taking?
Stop using flask-restplus. Thats the most valuable answer I can give you (and anyone else).
Ownership is not there
Flask-restplus is a fork of flask-restful. Some engineers started developing features that suited them. The core guy has ghosted the project so its been officially forked again as Flask-Restx.
Poorly designed
I used to love flask when I was a yout’. I’ve realized since then that having global request, application, config that all magically update is not a good design. Their application factory pattern (to which flask-restplus conforms) is a style of statefully mutating the application object. First of all, Its hard to test. Second of all, it means that flask-restplus is wrapping the app and therefore all of the requests/handlers. How can anyone thing thats a good thing? A library whose main feature is endpoint documentation has its filthy hands all over every one of my requests?? (btw, this is whats leading to your problem above) Because my post is serious and thoughtful I’m skipping my thoughts on the Resource class pattern as it would probably push me into the waters of ranting.
Random Feature Set
A good library has a single purpose and it does that single thing well. Flask-restplus does 15 things (masking, swagger generation, postman generation, marshaling, request arg validation). Some features you can’t even tell are in the libraries code by reading the docs.
My solution to your problem
If you want to document your code via function decorators and models use a tool that does that alone and does it well. Use one that won’t touch your handlers or effect your actual request decorators. Use oapispec for swagger generation. For the other features of flask-restplus you’ve got marshmallow for marshaling request/response data, pydantic for validating request objects and args, and so on.
btw, I know all this because I had to build an api with it. After weeks of fighting the framework I forked it, ripped it apart, created oapispec, and trashed it from the project.

Add renderer in #view_config from configuration?

How do I supply a configured value to a #view_config-decorated function or class?
E.g.
#view_config(route_name='example', renderer=some_config['template.name'])
class MyClass(BaseView):
...
Or
#view_defaults(route_name='example', renderer=some_config['template.name2'])
class MyClass2(BaseView):
...
Or
#view_config(route_name='example', renderer=some_config['template.name3'])
def method3(request):
...
It's very hard to know where to start, as I'm trying to edit a pyramid plugin, which pulls together its config in an includeme function, so it doesn't have anything obvious that I can include, and it's hard to know what's available to the #view_config decorator.
You can add views using declarative configuration (what you are doing now using #view_config or alternatively using imperative configuration by calling config.add_view() method.
In this case, as you need to access the Pyramid registry and settings file, it is easier to do adding the views imperatively.
In your __init__.py you can do:
settings = config.registry.settings
# You need to call config.add_route("foobar") to map view to URL also
config.add_view('views.MyClass', route_name="foobar", renderer=settings['template.name3'])
Then in your views.py:
class MyClass(BaseView):
pass
#view_config() and add_view() arguments are equal.
I thin kyou can also mix view_config and add_view() arguments for the same view, but I am not sure aobut this. Hope this helps.

SearchDomainFactory.Instance is obsolete: 'Inject me!' ( Can't find out how to create instance)

I'm in the process of trying to migrate a R# extension project from R# 6 to R# 8. (I've taken over a project that someone wrote, and I'm new to writing extensions.)
In the existing v6 project there is a class that derives from RenameWorkflow, and the constructor used to look like this;
public class RenameStepWorkflow : RenameWorkflow
{
public RenameStepWorkflow(ISolution Solution, string ActionId)
: base(Solution, ActionId)
{
}
This used to work in R# SDK v 6, but now in V8, RenameWorkflow no longer has a constructor that takes Solution and actionId. The new constructor signature now looks like this;
public RenameWorkflow(
IShellLocks locks,
SearchDomainFactory searchDomainFactory,
RenameRefactoringService renameRefactoringService,
ISolution solution,
string actionId);
now heres my problem that I need help with (I think)
I've copied the constructor, and now the constructor of this class has to satisfy these new dependancies. Through some digging I've managed to find a way to satisfy all the dependencies, except for 'SearchDomainFactory'. The closest I can come to instantiating via the updated constructor is as follows;
new RenameStepWorkflow(Solution.Locks, JetBrains.ReSharper.Psi.Search.SearchDomainFactory.Instance, RenameRefactoringService.Instance, this.Solution, null)
All looks good, except that JetBrains.ReSharper.Psi.Search.SearchDomainFactory.Instance is marked as Obsolete, and gives me a compile error that I cannot work around, even using #pragma does not allow me to compile the code. The exact error message I get when I compile is Error 16 'JetBrains.ReSharper.Psi.Search.SearchDomainFactory.Instance' is obsolete: 'Inject me!'
Obvious next question..ok, how? How do I 'inject you'? I cannot find any documentation over this new breaking change, in fact, I cannot find any documentation (or sample projects) that even mentions DrivenRefactoringWorkflow or RenameWorkflow, (the classes that now require the new SearchDomainFactory), or any information on SearchDomainFactory.Instance suddenly now obsolete and how to satisfy the need to 'inject' it.
Any help would be most appreciated! Thank you,
regards
Alan
ReSharper has its own IoC container, which is responsible for creating instances of classes, and "injecting" dependencies as constructor parameters. Classes marked with attributes such as [ShellComponent] or [SolutionComponent] are handled by the container, created when the application starts or a solution is loaded, respectively.
Dependencies should be injected as constructor parameters, rather than using methods like GetComponent<TDependency> or static Instance properties, as this allows the container to control dependency lifetime, and ensure you're depending on appropriate components, and not creating leaks - a shell component cannot depend on a solution component for instance, it won't exist when the shell component is being created.
ReSharper introduced the IoC container a few releases ago, and a large proportion of the codebase has been updated to use it correctly, but there are a few hold-outs, where things are still done in a less than ideal manner - static Instance properties and calls to GetComponent. This is what you've encountered. You should be able to get an instance of SearchDomainFactory by putting it as a constructor parameter in your component.
You can find out more about the Component Model (the IoC container and related functionality) in the devguide: https://www.jetbrains.com/resharper/devguide/Platform/ComponentModel.html

How to override url_for_event in Apotomo to always include a parameter?

To get to run Cucumber with my app and subdomains, I read that I should add default parameters to the default_url_options.
However, I can't seem to find a way to add default parameters to the url_for_event helper that Apotomo gives. I believe this would be the first (if not the only) step to getting integration tests, Apotomo, and subdomains to work.
I got an answer from Paul Hagstrom in the Apotomo mailing list:
class YourBaseWidget < Apotomo::Widget
def default_url_options
...
end
end
class YourOtherWidgets < YourBaseWidget
...
end
This works a lot like how most of your Rails controllers inherit from ApplicationController. Thus, anything you apply to ApplicationController will apply, by inheritance, to your child controllers.

Resources