#54 Gem VanillaNested by Ariel Juodziukynas (Cocoon successor without jQuery)

13/09/2021
Transcript
Hello. So today's going to be a special episode. We have a guest star, and this is Ariel, a creator of, uh, uh, new Ribbon Rails gem that should replace the Gem Cocoon. And the gem's name is Vanilla Nested. So Ariel, can you tell something about yourself? Sure. Great. Uh, thanks for having me here. Um, I'm Mariel, I'm from Argentina. I am a race developer since 2010, I think. And I've been doing mostly rub rice over the last 10 or year or 11 years. Um, and I remember at some point during my career, I had to start migrating off from jQuery on the project because we wanted to optimize and request times and those things, and we were using, using the Gem Cocoon. And I was really struggling to remove jQuery because I have all those gems with dependencies. And at that time, I couldn't find any replacement for Cocoon that will use just vanilla JavaScript. And I started just doing some things in-house for that. And over the years I found that it was an interesting idea to create the Gem to actually have that, uh, available for everyone and to also update with the more modern things in Ruby on Rails like I know, using Web Packer. Um, so yeah, I decided to a few years ago to create this gem. It will be like, uh, it's a, a similar gem to cocoon. It helps you add input fields dynamically or removing input fields dynamically for your nested forms. Um, but it uses vanilla JavaScript, so it has no extra dependencies and it's, it has some features that are different than Cocoon, I think more advanced feature, like undoing changes or some different events for the user to, to really, um, connect to different parts of the process to really customize the experience. Um, and yeah, I think a few weeks ago I released this, then I released a new version of the Jam. I fixed some bags that were there for a few, for some time. Uh, but I, I got the time to, to finish fixing those and release, uh, the new version. Yeah, actually I know Cocoon is, uh, one of the gems that I've been using in most of my, uh, applications. And, uh, well, uh, I really love the feature of being able to like dynamically add or remove fields inside, uh, form. And, uh, one thing that has been really holding me back, uh, since Route Six was released, so, uh, uh, now you really try to keep away from using Jake Ferry. And, uh, like when I Google something, I always start to find a solution that doesn't use Jake Ferry. And Kon has this jic very dependency. And, uh, I didn't like the idea of installing the J very just to use this jam. And, uh, like the, I, I remember Cocoon had a few, uh, issues about, uh, like open issues about, uh, uh, rewriting cocoon in, uh, vanilla and, uh, well, um, it's really quite an old gem, so it's really cool that, uh, now you've made some, uh, fresh, uh, vanilla code, uh, and, uh, we wouldn't be needing to use, uh, J vri anymore. So maybe let's have a look at the gem and, uh, how it works. Yeah, sure. Let me share my screen. Um, okay, so the, the gem, like in most modern rails, gem that needs some assets in JavaScript, it consists in two things. One thing is the gem, and there's also an old package for that. So it's all in the same re in the same package here. So, uh, you can use this gem if you are not using web package. You just use the gem, like gem inta, gem nester, and it works with sprockets out of the box. And if you want to use it with web packer, you also need to add the, the note package or using yarn. And right now it's pointing to my GitHub repo. It is not, um, in yarn packages.com. Um, it, and you need, you only need to add the import in your application JavaScript. Um, I think at some point I didn't know how to use to, to set up this thing to Web pack properly and you had to manually copy this, the JavaScript file in your JavaScript folders. But now it's just, uh, it's a hold package. It's work with all the rails version with sprockets or with newer version with, with Web packer. Cool. Um, so the gem consists in two parts. It includes helpers that you can use on your backend, and it includes some JavaScript that will connect your, uh, the, the tags that the helpers created with all the dynamic parts of it with in your client in the client side. Uh, so let me show you the part of the code here. So if you are familiar with Cocoon, it has two helpers. Basically, uh, you have the link to our association and the link to remove association. I had I I ins, I was inspired by that GEM and by the Rails cast, um, from Ryan, I don't remember the name. Yeah. By last name, Ryan Bates. Um, so we have similar method here. You have a link to add nested, and we have also link to remove nested. And there's a lot of things that we can pass here to customize the functionality of the, the customer, the, the style and the functionality. Um, the way this works basically is that it will, you will need a partial with the fields of your, do you want to add or remove dynamically. And it will render the partial as a string and it will add the string with all the HTML content as an data attribute of the, of the tag that we render there in the view. And then we also have the client side part of the gem that is this Java script file with all the, the data connect everything. So it will just, um, when, when the application runs, this is set up so it works with turbo links and without turbo links. So it works in both way. So it just, when the app start is reads all the vanilla nested special classes from those, uh, from those things, and then we connect all the JavaScript. Um, so every time you, you don't need to connect anything, it just, it just works. Uh, but you can connect to a lot of events that happens during the process of the, when you are using the mini, the mini the application. Um, so you even can connect to, I know an event when a field was added, when it was removed, when it was hidden from before undoing, because it, it give you more feature like undo and mm-hmm. Um, it reads, I know, uh, some advanced feature are like you can, it, it detects that you set a limit on your association and will trigger so events, so you can act on that. So I dunno, we can, I think we can, uh, if you want, we can check an application that's using the, the gem and see how it's set up and how it works. Yeah, absolutely. Sure. Okay. So in the same repo, I, I'm going to use the application that we have in the, in the repository, uh, that I'm using for the test of the app. Um, so the first things are that in the gem file, we add the gem. Right now I'm pointing, I'm pointing to the local version because this is the repository, but you, you wouldn't use this part. And then in the package dot Jason, we have the vanilla nested. I'm also pointing to the local file here, but it will point to my, uh, GitHub repo. And then we need, um, different models that we need to associate so we can nest nested forms and we can use this, this, this tool. So one requirement of the, of this two for, for this work is that we need to use the accepted nested attributes for helper that something rails needs. So the fields for are handled properly in a form when you do nested forms and when you submit the form rails will handle this, will handle everything for you. It will set up everything, it will handle the attributes and all the associations and deletion. Um, and we also have, uh, another model that is associated with that. Um, then in this case, we are going to have a user with many pets, for example. Mm-hmm. And you can see here I'm setting a limit of three and that this is a feature of rails, um, that if we validate that you are only that number associations and in pan eselle, when that number is rich, it will trigger an event. So you can react to that, for example, and this the button or show a warning or maybe remove the oldest one. I know you, you can do whatever you want with that. Yeah, I didn't want to add any, the default value. Uh, one option was to disable that when you reach the limit, but I didn't want to force a fear, a fear a behavior. I just want to, I just meet an event and somebody can listen to that and react and do something. Um, so yeah, I actually didn't know that you can set a limit. Oh yeah, it's, uh, I, when I was, uh, doing the research for this gem, I was trying to do to check what are all the features that you can use for accept that use for, and what can I automate for that? And yeah, if you set, if you don't set the limit, you can do anything. But if you set the limit, I know you can say, I want only three pets here. Uh, if you try to save a record with more than three, it will fail. So I wanted to automate that in the gem in the gsu. Um, so this is a test application. So it has many cases use cases. So if you go to the app, it, it has, uh, test for, uh, basic usage is here, but it can also, it, it showcase how to use custom tags by default. It creates, uh, an anchor tag, an A tag, but you can change that to be a button, um, an a span, uh, ad, whatever you want. And it also includes an undo feature. So if you by mistake, delete something, you, you have some time to undo it. Uh, but it's also configurable by default. It doesn't have an feature, but you can set up some time out there. Uh, so let's see. I have this, um, basic form and when I click add pet, it will add more fields to the thing and we don't need to, to, to do a request, right? Um, so that's the, that's the functionality of the gem. When you click DX here, it will remove that. And for these things to work, um, let me inspect this button. So you can see here in this, in the button, we have all the HTML that is being added. Every time you click, it's in the data attribute. So this, this is device area of how it works. Um, let me go back to the code to show you how this is actually set up. So if you have, you have your form, right? It's a basic rails form, and at some point you have to call the helper. That's called link to add nested. And you, you have to set up the, the arguments are the actual form builder yous in here, the name of the association of symbol and the IV of the, of the element where you are going to insert the, the new fields, right? So these are the, the form come from here. This is the name of the association, and this IV is the one I have here in the IV equal parts. Um, this, it's you, you can put any content you want here. You can add a blog if you want to make some complex stuff here, or you can add, um, there, there's a property link text that, uh, an attribute that you can use linked, um, argument that you can do, I know, like add, and you don't need to add a block. So you have the possibility of add more, only a string or more complex, um, content. Mm-hmm. And this is, uh, uh, ba basic rail feature. This is not anything related to the jam, but we need to use fields for the fields for helper. This is connected with accept natural attributes for, uh, we need both working at the same time. So this works, and you just add the name association and it will give you a form builder for the association for one el, each element of association. Of the association. And then we are rendering, um, partial with that, uh, with that object. One thing to consider is that the gem by default will fall back to this, to this name, the name of association under fields. But you can also customize that if you have, let me give you, show you another example. If you have this, uh, a different name for the partial, you'll need to add a partial argument to the helper and you can just use a different name. So you don't, you the by the default is the association in singular under score fields, but you can customize that if it doesn't fit your, your space. Um, we do need the, the partial because it what we use in the helper to, to render this in the data attribute. So we need a partial for that. And the partial will just include your form information, the Oreo form fields, and we need to add this helper to remove the association, right? It is the same, I'm just adding thing here because this is for the test application, but we can also have link text here and say X and that's it. But sometime you want to render an icon, a image style or whatever, and you can customize that here. Um, one important thing is that this helper must be a child of this type because this uses, uh, JavaScript closest method and it take, it, it checks for a parent with some, uh, iv. So it needs to be a children of that element. If you put this outside, it won't work, but you don't need in, it doesn't need to be a direct children. It can be a, a nested children and it will work anyway. Um, so that's the basic setup. We have the, the form rendering a partial, and in those, in these two places, we need to add the, to, to call the helper, the add to nested to create the add button and then remove for link to remove nested to create the X button. Um, okay, so after that's, that's connected, we have, for example, here, when I click this button, it will read the HTML from the data attribute, and it will inject that in the inside this, um, inside this, the element with that id, in this case it's ID pets. So I do that, I add more things, and when I get to the limit that it was reported by in, it was set up in the model, it will trigger an event. Um, by default it's just triggering the event. So I am in this test application. I connected, I'm connected to that event to render this message. So I can show you how to connect to events so you can react and do whatever you need to. Right? So if you go to your JavaScript, I am importing the vanilla nester jam. And then in the document object, you can listen to all the events that vanilla nester is triggering, and it, every, every event will be, will start with this namespace pan nested colon, and then the name of the event. And for each event, you will have information that you can use in, if you have your event ob your event object here, you can inspect that and we'll give you the name of the, the, the actual element that was added or removal, the what thing you click, any information related to that event. Um, there are many events that we can listen to. So for example, let's go back to the rhythmic, no, this is not the rhythm, this is the, so let's see in GI Hub because it looks better. Um, so here in the remi we have all those things that I show you is how to set up the accept nest attributes for the oh one thing. One important thing is with any rails nest cell form, you have to, um, permit the name of the association in plural attributes. This is rails, nested forms, um, a requirement for them and also for with the, you need to add the underscore destroy. Um, you need to allow this, if you want to remove things from your form, then it shows you how to use the, the, the links helpers. And then we have all the, the options we can pass to the, uh, to the helpers. We can set up a different text classes. We can say if we want to add the, the new fields at the top or at the bottom of the list. So we have the instrumental, we can do prepend or append, we can change the motor partial, we can, um, if in our partial the variable is called FF instead of form or whatever name, you can just change that in the, uh, also as a variable because sometimes you need to adapt to a form parcel that's already there. So you can customize the name of the parcel and the name of the variable that that holds the form builder. This is somewhat new feature, uh, even the name of the to render, yeah, you need to always render an A tag. You can render a span, you can render a button, you can render any tag. And I have a, an idea of a next feature that you can also pass attributes for that tag. So if you want to, I know if you have a, a tag and you want to pass, I know, um, a tag index or if you have an, if you are have a button and you want to provide a name attribute, you can do that here, but it's not, it's not there yet. Um, and you can also add content as a block and not as a string. If you need to add more complex stuff like, uh, uh, like tags just text. And you have similar things for the, uh, link to remove nested. So we have the same link text or block classes. Um, oh, sorry, my dog is barking. Yeah. Um, that's nice if you, if if you want by, by default, the way this works is it will, it will use the name of the association underscore fields to detect what's the con the wrapper of your fields. But you can also customize that maybe if you depend on a form, uh, if of a par on a partial that's already built. You don't you want to say, okay, this is the, uh, the selector I want to use, for example mm-hmm. And not add hashtag i some id. Mm-hmm. Um, then let me see, uh, it also has a, a tag, and this is, uh, I think it's a interesting feature that you can undo the deletion. So if you set up the undo link timeout and the link text, you can actually undo the, the removal before that time, time happens. So let me go back to the, to examples here. So there's an example with an undo. Yeah, so when I click here, it will give me an undo. Oh, it's, it's too fast. Um, right now it's set up, let me change that. So it's, uh, with undo, it's too fast right now. So let's do five seconds. So if I open the up and I click here, I have five seconds to undo this thing, and when I click it, it goes back. So if you click by mistake this button, you can, you can, you can revert that, it's not a problem. Uh, you can also connect to the events to prevent the click if you don't want, if you want to show a warning or an alert or whatever. Um, and you can also, you can customize the time and you can customize this string. By default it says undo, but mm-hmm. You can, the, you, you can use an icon, I dunno, a recycle icon or whatever. Um, and what else? Let me see. Oh, and then we have all the events. So for each event that happens during the use of the, of the tool, you will have different events on the document object. So you can have, um, when something is added, you will have this event and with this information, so you can get the name, the container, the, the link that you click. So sometime you may have different, uh, forms in the same page. So you, you want to know which one was the one that you clicked. Um, you also have, uh, fields limit reached. So if you get to the limit, it will send the event. It won't do anything more than send the event. So if you click more times, it will add more fields and, and emit more events. So this is not limiting you, it's just sending an event the same you have for fields removed. So when you click the X, it will trigger this event and you have the information of the thing that was removed. And if you set up an end undo time, it will first tie the element, so you have an, um, event for that. And when that gets removed, it will call this event too. So you can connect to those two steps during the, the removal. Uh, if you undo the hiding, you can also have this event. So if you click undo, you also have an event for that and you can redo something that you did when you click the removal. Um, yeah, I think those are all the features for the, for the Gem. Yeah, actually, um, there is one of, uh, my main applications that, uh, is still running Rails five. And, uh, like I went to the Gem file and uh, uh, made kind of a plan of things that needs to be, um, changed to use, uh, the Gem with Rail six. And uh, some things were like, uh, the Gem was using Bootstrap three and uh, I wanted to use Bootstrap, uh, uh, five and it requires like, uh, some different gems and uh, then, uh, it wouldn't require Jake theory. Also, uh, uh, I didn't want to use Cocoon and uh, like keeping Jake Fury inside the application because of, uh, cocoon was also kind of holding me, me back. So I mean, I'm really looking forward, uh, to trying to replace Cocoon in an existing application with, uh, vanilla Nest and seeing how it goes. Yeah. Hopefully the change is not that different because I am, I was inspired on that gem. On that gem. So it's using similar helpers and the basic idea of having partials nested forms certain strategy for is the same in both. So hopefully it's just replacing the gem adapting a little bit of the, of the code, but it shouldn't be that, that hard. Yeah, I mean, uh, I like the idea that, uh, it's, uh, a new gem. It, uh, was built based on, uh, the existing knowledge. And it doesn't use Jake very, so Oh, and, uh, and I love the and Undo feature. Yeah, that was something I was, I, I had to implement at that point using Cocoon, and I had to listen to the events that Cocoon was triggering to add some thing, but I had to do some hacky stuff, like listen to the, and undo say that information somewhere, then delete set information, and then adding that thing on my CI wanted to have that in this jam because I think it's super related to that, right? It's, uh, it's something you would expect on this thing to handle because you are removing that and you want everything there. Uh, but it's optional. It by default it's not doing that. So, um, it's, it's more versatile. Yeah. And, uh, is your first gem or have you created gems before? Um, I did some gems in the past where I were mainly hacky stuff that I needed for work, maybe extracted something to, uh, weird gem that I only knew how that worked and shared that with my other project. There was no documentation, no anything. Uh, this is the first one that is actually made to be a gem for the public to use with real research on how to do use it, how to do it properly, how to connect with different rail version, how to support different things. And it's uploaded to Rabbit Gems. Um, so this is the, the first time I do that. Um, I'm currently working on a different gem. It's not related to this thing, but it's uh, it's like a, we start, uh, interactive rails, new command that lets you add a lot of tools. Um, I know you can run this command and it will ask you, I know you want to use some, um, template handler and you say, I want RBM handle or slim, do you want to use, um, I dunno, r spec or mini test, do you want to use simple code, yes or no? So it asks you a lot of questions of different popular tools, and it will create a new risk application with all those tools set up for you. This is it, it's working, it's there in, in my GitHub account. Uh, I haven't published that yet in Ruby Gems or like pub on Twitter or anywhere because it's something I want more people to test before doing a real announcement. But yeah, I think it's, um, it's like a better, a better version of the jump. Yeah, actually, I just remember like, uh, a year and a half ago or so I was reading, uh, uh, forum post on the, uh, Ruby Forum and there was this discussion about making the rails new command, uh, more interactive. So I mean, by default you can just say, uh, uh, the name of the app, the name of the database, and uh, uh, which, uh, uh, like if you want to include, uh, or don't want to include some kind of like action mailbox or action text or something like that. So I, I guess that were like a few tools that was spun out of that, uh, forum. Like there was, uh, rails, Neo io then, uh, that there's this jam, uh, boring generators that, uh, just has some templates on, like, you just run the name of template and it installs device or something like that. And, uh, then like Rubidium and, uh, rails, bytes, so kind of couple of, uh, public places where you can host your, um, template scripts and run them in an application. So, uh, your tool would be like, uh, uh, similar, but uh, with the rails new command. Yeah, it's, um, It's, it, it, the idea of the gym is to give you all the functionalities of the, to set up the flags for the rails new command, but also give you more things that are outside of the basic rails new command. Uh, let me show you right now. It's so better that I don't even have a name. It's called Raise New app. Um, so right now it's, it gives you all these different things. So if you want to set up different gems, different advertis, this is just setting the flag from the raise new command. But then I know if you want to use our spec, simple Code, factory, boat, and faker, it will also add your, those gems for you. So it will ask you during the wizard step by step what do you want to add and what do you want we don't need. And these are all the things that it's already supporting. So you can set up different tools for your test, different template tensions, different form helpers, different pagination, he jams. This is also setting just one flag for, uh, for the raise, new command. Uh, you can add authorization with Pan or can, can can, you can add authentication with device. You can set up different links. And one thing that I always have to do when I start re application is I have to add a remote that I have on GitHub. And I, I usually like to change, use main, like we have on GI A right now, that's the default. So I added this thing that will also make a, your first new commit, change the name of the branch and add the remote for you. So you don't need to do those state manually. It will just ask you during the, the process, you just press enter at the end and you see doing a bunch of stuff, adding gems, doing everything, and you are there with your unit application with all these tools set up for you is the basic set up. Then you have to customize and add more things, but at least you have the bare bones working. Yeah, Azure, like this, uh, idea of, uh, like, um, setting flags, uh, then join your rails new command, but not, uh, I mean not, not starting with some kind of uh, uh, just template, uh, that you've created, uh, a year or two years ago. Uh, or some kind of random template from the internet or let's say, uh, uh, just, just finding some kind of a script on, uh, how somebody wants installed device. So I mean, looks, uh, kind of promising to me. I mean, uh, it's got, uh, tests, it's got, uh, what, what do I need most? I would need, uh, like a Rubin, so like robocop, ivid, guess, then pec, uh, uh, I guess stimulus. And, uh, I, I like the last one. So GI at remote, at branch name and so on. Yeah. And some things I want to add to this is, for example, to already set up your Desire CI file, I know, or Adobe a container. So you don't need to create a new, I know GitHub actions file configuration. It will read your setup and will just add the commands you want on GitHub on ci. Yeah, I shall, I like That for GitHub actions. Yeah. So will like all this ven, when, uh, I install robocop, uh, the next step is, uh, setting up GitHub actions for robocop. So it, uh, I mean, uh, I think it's a must have. Yeah. Uh, but yeah, this is a better thing if people is interested into trying this and give some feedback. That's great. Um, for me, I've used that and it's working, but I haven't tested that in too many places and I developed this on Linux, so I don't, I haven't tested that on Windows, for example. So yeah, if people is interested on this, that's great. Uh, you can see that in my, in my GitHub repo. Cool. Uh, Val. Okay, Ariel, uh, thanks a lot for sharing, uh, IL and nested with me and, uh, with me today and with the world on GitHub. And, uh, yeah, I'm really looking forward to trying to implement it, uh, locally and trying to replace, uh, cocoon in running application with vanilla and nested. Great. Thank you. Thank you for having me here. Yeah. Um, I, I love to talk about all these things. So I think it's really directing to, to be able to show the code and see the reason why I did something. Because, uh, sometimes it's, I, I like this idea of when I read, when I see a new gem, I sometimes I don't understand what's going on, I just use the gem. But I think it's interesting to know why the gem works and how it's done. I mean, the, like, I, I could just, uh, do it on my own. I mean, I would just open the jam, look at the rhythm, try to implement it, uh, locally and I know record a video. But, uh, I mean it's, uh, in my opinion, 1000 times more valuable if like, I have the opportunity to speak to you and, you know, well the way you wrote the code better than anybody, and then you go through and explain it and the features of the jump. So thanks for that. Yeah, that's great. That's a really good idea to have, uh, developers talking about their, their creations. Yeah. Okay. So then cheers. Great, thank you.
0
Join the conversation
Sign in to access PRO lessons, access private repos, leave comments, create watch lists.
We collect your email address, name and username to create your account. We do not share your email address with anyone else.