Skip to content
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

Add support for deeply nested objects/hashes #69

Closed
DavidHooper opened this issue Mar 16, 2017 · 9 comments
Closed

Add support for deeply nested objects/hashes #69

DavidHooper opened this issue Mar 16, 2017 · 9 comments

Comments

@DavidHooper
Copy link

I'm almost sold on using this project for rapid prototyping. However one of the blockers is that there is currently no way to define nested attributes or deeply nested attributes.

Is deeply nested attributes suitable for this library and how might it be implemented if so?

@crismali
Copy link
Contributor

crismali commented Mar 16, 2017

This was a feature we had in the 0.X.X versions of the gem (README for the most recent version with this support). We dropped support for it because it got pretty complicated very quickly. There's a section in the upgrade guide about what the gem used to do and a bit about how you could go about implementing it. (Short version is that you'll end up making a class that behaves like an ActiveRecord::Type, then register it with ActiveRecord::Type, and then you should be able to do something like jsonb_accessor :data, foo: :my_awesome_nested_type. I imagine the fastest way would involve OpenStruct but if I remember right it won't give you NoMethodErrors.)

@DavidHooper
Copy link
Author

I was hoping to do through some sort of declarative syntax like:

jsonb_accessor :data, 
               foo: {
                 bar: [:integer, default: 0],
                 foobar: {
                   boofar: [:string, default: 'my default']
                 }     
               }

@crismali
Copy link
Contributor

The previous version worked similarly, it just became pretty cumbersome. I'm open to PRs that implement it in a clean way, but it isn't a particularly high priority at the moment.

@jrochkind
Copy link

I'm also interested in nested functionality -- but I think I'm fine with the "define a custom type" approach, maybe even prefer it, I like the idea of having explicit type classes for the nested objects.

Except I can't quite figure out how to do it. The upgrade guide has an example of the 'old way', and then just directs you to the ActiveRecord attribute class method doc for the 'new way', implying 'figure it out'. I am failing to figure it out from the docs. :)

Can you possibly provide a working example equivalent to or similar to the 'old way' example, but using the ActiveRecord::Type API? It would be super helpful.

@jrochkind
Copy link

I'm looking at AR/AS code, and getting some cool ideas. I'm going to try to work something up, maybe as a PR to this. Not sure how long it will take me. :) What you've done here is super powerful, thanks! I think it can be added to. Also considering ways to refactor it to add less of those dynamic methods to the model, and use more of the built-in Rails5 API, like store_accessor and more use of Types, and maybe provide an API that looks more like AR attribute.

This is really cool stuff, thanks so much for sharing, I think maybe it can be even cooler, I'll see how my experiment goes. :)

@jrochkind
Copy link

jrochkind commented May 16, 2017

So I started down the path of figuring out how to use nested objects here, and ended up just writing my own thing, deeply inspired by the awesome stuff you've done here, but pretty much rewritten from scratch, with different API and and internal implementation and somewhat different feature set. It's pretty much new code, but I couldn't have done it without seeing what you'd done here first.

Still currently an experimental work in progress.

https://github.com/jrochkind/json_attribute

@DavidHooper
Copy link
Author

Looks great @jrochkind, I like that you've used other classes to nest objects.

@mckramer
Copy link

This gem and json_attribute are great. I have been looking for a solution to deeply nest objects with proper validation/form support. I have used Mongoid for a while. I have a few use-cases where the Mongo documents are very valuable, but I think I could get by with relational for the majority, if I can reproduce some of the embedded behaviors using the jsonb columns.

  • Using ActiveModel modules for validation/serialization
  • embeds + embedded_in relations
  • Generating uuids for embedded collections/objects
  • Supporting dynamic form helpers in the views

I wanted to leave this here in case anyone had some additional thoughts on what embedded/deeply nested objects/collections behaviors might mean for jsonb + ActiveRecord.

@haffla haffla closed this as completed May 12, 2021
@jrochkind
Copy link

FWIW, my https://github.com/jrochkind/attr_json (metioned above as json_attribute, an older name) has been working out well, but there are some things it does not as consistently as I'd like with rails attributes.

I come back here to look at jsonb_accessor, and I can learn a lot from it, that I can use. Hooray for open source.

However. Despite the upgrade guide here suggesting:

If you need these sort of methods, you can create your own type class and register it with ActiveRecord::Type

In my attempts, there actually isn't any way to get that to work with jsonb_accessor. At least not with being able to mutate an object in place. After making any changes to a nested object, you would always have to call something like top_model.top_attr = top_model.top_attr to get the changes to be picked up. As suggested in this other issue comment here

But I think that workaround is always necessary, even if you do implement a custom type class suggested in the upgrade guide.

(If the nested objects were immutable, that would work fine, as you'd only be able to change them with the top-level setter!)

If anyone has been able to to get this approach working with jsonb_accessor, I'd love to see it!

(To be clear, my attr_json is working fine, but there are some things jsonb_accessor does better, and I was hoping to make my implementation more like jsonb_accessor's to be able to get the best of both worlds... but found I couldn't, jsonb_accessors implementation doesn't allow mutable nested objects, even with a custom type class -- as far as I can tell! If anyone has solved it, I'd love to hear about it!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants