-
Notifications
You must be signed in to change notification settings - Fork 35
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
Serialization/Deserialization Requirements & Implementation #96
Comments
@ajjahn - I think I understand how this would work:
So we would add HashReactSerializer, etc to react.rb (Hash may be the only one needed actually) And ReactiveRecord would add ActiveRecordReactSerializer... okay so far? Assuming so, then I have two questions:
|
I'm going to stream of conscience pseudo code this, so it doesn't have to look exactly like this. We provide the simplest serializer. It simply relies on ActiveSupport which will call class BaseSerializer
def initialize(value)
@value = value
end
def to_json
# ActiveSupport already knows how to handle built in collections and value objects.
ActiveSupport::JSON.encode(@value)
end
# Could be handy to make the serializer callable.
def call
to_json
end
end Let's say we have a plain old ruby object we'd like to serialize: class Car
attr_accessible :make, :year
end
class CarSerializer < BaseSerializer
def to_json
{ make: make, year: year }.to_json # or whatever custom serialize logic you want.
end
end Pretty much the same for ActiveRecord models: class Employee
belongs_to :company
end
class EmployeeSerializer < BaseSerializer
def as_json
@value.as_json(only: [:name, :email], include: [:company])
end
end
When we # somewhere in the render helper
serializer = begin
"#{object.class.name}Serializer".constantize
rescue
BaseSerializer
end
# Serialize it
serializer.new(object).to_json
Pass an explicit serializer as an option to render component: Employee, employee: @employee, serializer: EmployeeWithTitleSerializer
It doesn't really make sense to have an 'ActiveRecord' serializer. Data serialization is a domain concern. If you wanted a serializer that serialized all the attributes of an ActiveModel object, the base serializer would do the trick since After typing all this out... I don't see any reason we can't just lean on something like ActiveModelSerializers outright. It already solves this problem for us, not to mention it is part of JSON-API, which is now merged in to Rails 5. We probably should implement react.rb's render helper as a true ActionController::Renderer. I'm sure we could easily offload the serialization to Anyway, does that help illustrate where I was going with this? |
Yes the basics of what you outlined were exactly what I was figuring. My questions still stand however. RE: "When we render :component in a controller or view, we can select the correct serializer based on the class of the passed in object. No need to traverse trees, just stick to a convention." But that means that if I design a serializier for a base class ( RE: And if you have two objects being passed? How does it know which object that serializer goes with? RE: It doesn't really make sense to have an 'ActiveRecord' serializer. Data serialization is a domain concern. If you wanted a serializer that serialized all the attributes of an ActiveModel object, the base serializer would do the trick since as_json does that be default. This is the exact problem that got us into this... people do override as_json for whatever purpose. If we could count on "as_json" working, then we don't need any of this, and could just call the objects as_json method... Another Side Topic Related Right now we are determining the "type" based on the optional "type" of the param macro. This has already caused several new users to stumble, as its optional, but not really if you are passing data from the server, that needs serialization. Perhaps we should pass the serializer class name as part of the top level params. In otherwords the render method would call the serializer, and then as part of the params to the "TopLevelComponent" would pass the list of serializer classes used. The TopLevelComponent would then do the deserialization before calling the actual component. |
I'm sort of re-emerging here so forgive the lack of context, but is this meant to be done in a "reactive record" gem or in the (simple) Opal wrapper around React? I would certainly say serialization should not be a part of the basic GEM. Putting aside which GEM it belongs in, for my application, I've just done a fairly simple setup where I whitelist a few serializable attributes for a class and then override React (on opal) never has to know about any of this except for 1 base 'Store' component that deserializes the JSON (which is my initial state) using There is no serialization back to the server in my case (wouldn't want to anyways due to security issues with deserializing on my machine). |
Its not just applicable to reactive-record (although reactive-record certainly needs some mechanism) The intention here is to provide some standard mechanism so that things "just work" in an obvious way, and that gems like reactive-record can use it as well. When I say obvious way, I mean if I pass some structure as a param from the server, I expect it to appear reconstituted on the client (assuming the class is isomorphic.) So I do think there needs to be some built-in mechanism to take care of the deserialization. The more I think about it, the better I like the idea of making this the responsibility of However that leaves us with the issue of how to declare the serializer/deserializers. The code currently is basically as @wied03 describes it above except for the method names. @ajjahn proposed using separate serialization classes, which seems great, but there were a few pending questions above. |
I should add that I never send ActiveRecord models to the client. In my view they are too mutable and complex to work well with the React/Redux/GrandCentral architecture. I build "view models" and those are what I serialize with Rails and deserialize with the approach I noted above. |
So this is blocking cleaning up PropsWrapper which is blocking context support, so it would be good to wrap this up. I think the best approach is to get this out of the base react.rb param mechanism, and move it to the Again that proposal is to have anything calling the The question still remains how to specify the serialization/deseralization methods. There are two proposals: Separate classes that use a naming convention, and providing an class level deserializer method, and instance level serialization method. I am fine with either one, but lean towards the latter approach (which also seems to be the way @wied03) is doing it. |
OK. I have no opinions about how some of this works since I won't use it. As long as a lot of this caching code, etc. (assuming caching was created for serialization as @ajjahn explained) is moved to |
@ajjahn - RE: your comments over on #134 - I want to be sure we are on the same page here just we don't get confused. This has nothing to do with reactive-record. I simply believe that there needs to standardized way to pass data from server to client, and have the data arrive in the opal component in the same form as it left the client. I.e. serialized then deserialized. This is a function of the code being isomorphic, thus anybody getting into react.rb will likely have an expectation that if I do something like this:
that inside the component Foo, @wied03 - I think the direction is to move |
Since I've been harping on this subject and recently some related issues (#94, #95) have been opened, it seems like a good time to get a discussion regarding where we'd like to see serialization for passing objects into the pre-rendering system to go and how we'd like it to work.
Here are my initial thoughts:
react_serializer
and_react_param_conversion
. I believe those to be an anti-pattern. We'd be much better suited using composition than extending the responsibilities of classes. A hash shouldn't care about the details of how it converts to a transport format and back. Building simple classes like,HashSerializer
,ArraySerializer
, etc, would separate concerns, and allow for serializers to be swapped out with custom objects.MyFancyHashThingSerializer
for example.BlogPostSerializer
for example.SimpleObjectSerializer
that can be instructed which methods/attributes of a custom class should be serialized and deserialized without needing to define a custom serializer.Question: What are some other scenarios and uses cases we should be taking into account?
The text was updated successfully, but these errors were encountered: