Skip to main content

0 Using VueJS with Rails: Using VueJS for Nested Forms in Rails: Part 2

General • Asked by Chris Oliver

I particularly like avoiding the extra complexity of a full-blown router-based SPA, especially when enhancing an existing Rails app. Thanks for the clear and concise walkthrough! It'll help me avoid several pitfalls that I suspect I'd have otherwise fallen into.

It worries me that the HTTP paths & verbs are hard-coded into the JS here. Would the next improvement be pulling those into data attributes, with values from the usual Rails URL helper methods? This might get us started down the road of reusability and decoupling, with the end goal perhaps being a gem that (like cocoon, or even the standard form builder) does some of the boilerplate for us.

<%= vue_form_with(model: @team) do %> ...

You can actually use rails form tags and put your vue element inside it and on submit, look up to the form for the url, the method, and csrf token.

The reason I didn't do that here is because the new Rails UJS library was throwing some JS errors for me because it was intercepting the button clicks inside the form. I didn't have time to figure that out so I just removed the form and did it manually. Meant to mention that in the video as that's the way I would ideally set it up.

I've had similar issues, there are several undocumented changes in UJS's behaviour. Had to listen for rails:attachBindings and directly modify the Rails.buttonClickSelector.selector in a 5.1 upgrade I have in progress. Also note that form_with is remote: true by default, that one bit me as well, along with the changes to the call signature for handleRemote and ajax:success handlers.

Yeah, some interesting changes in how forms work by default. I was disappointed to see that scaffolds don't submit forms with AJAX as that seems like one of the obvious places for them to change and show you how to submit and handle errors.

I'm planning on doing a deeper dive into Rails UJS to see all the new features soon. Seems like a lot has changed instead of it just being a direct port to remove jQuery like I thought it was supposed to.


Great stuff Chris, always manage to read my mind! Been playing around with Vue and Rails - definitely liking not having to go the full SPA route, for something that doesn't need to be one.

Really enjoyed this series, but I must say, I can't find any videos you did with a general Intro to Vue itself - just specific implementations. Could be useful for those Rails devs that haven't really dug much into what Vue can do for them (specifically I guess with a Rails context, as I know plenty of others out there with "Vue in 15 mins etc") - just a thought to round out the Vue series?

Cheers,

Nick

That's a fantastic idea Nick. I actually just dove kind of right into the deep end myself and it would be great to take a step back and show what it is and why you might want to use it. I'll definitely make a screencast on this!


This is a great mini-series on Vue.js. I had emailed you a while back that I was going with Ember but I am now 100% sold on Vue. This episode helped me apply all the Vue.js training I did through YouTube and Lynda.com to a rails app. Thanks Chris!


BTW, idea for a future episode with Vue would be two things: First, I would like to see how you would refactor this code. I assume you would put some of this into components if you were going to take this approach into production. Secondly, I haven't yet pushed a Rails / Vue project to production or anything with the new webpacker gem, so i would be curious to see you push one to production and see what changes would need to be made. I am still a little unclear about how the rails / vue / webpacker set up would be deployed. Thanks again!

Deploying Webpacker to production is as simple as making sure you have Yarn installed on the server. No other changes needed for it which is awesome! :D

Definitely will be doing more on Vue in the future.

Wow that's awesome, thanks Chris. BTW, any plans of tackling Turbolinks-ios in a mini-series? I am just diving into that myself. I am taking some swift app development courses to learn the basics of that side of things first. Thanks

I'd like to, although I don't know much Swift and so I don't know how well I'll be able to cover it.


Thanks Chris. The combo Rails+Vue goes a long way.


You can always just grab the url from the wrapper form. The reason I didn't do that in these episodes was the rails_ujs library was doing something weird with the button clicks and so I left it out. Normally I would just use Rails to render a form tag and then use Vue to make it work, so then on submission Vue can just simply grab the url from the form (and csrf token too).

I've deleted the old profile, just reposting my questions.
-------------
Great introduction series Chris.

If I'm adding Vue to my current rails app will I need to write at the js all the actions for each form everytime, specifying the routes, redirects, etc?

This would be a lot of re-writing logic that it's already on the controller and should not "live" (or be duplicated) at the view level, don't you think? Is there a way to have more reusability, as mentioned by @@inopinatus:disqus ?


If you ask for JS back and you're using Turbolinks, it will actually send back a Turbolinks.visit() to redirect you on success which is awesome and means everything is handled like a single page app. You still have to handle the JS side for failure, but there's some talk about having that automated as well with some changes to Turbolinks to replace the current page with the standard re-render on failure. For now you have to just insert errors on the page manually.

I've deleted the old profile, just reposting my questions.
-------------
I see... And how about redirecting?
When working with .json, should the server's response include a "redirect_to" key?

And how about returning .js? Should the server's response be a update.js.erb with `window.location = ...` and the Vue js run the .js file?


Yep. And here's the link to the redirect_to override from the gem: https://github.com/turbolin...

I've deleted the old profile, just reposting my questions.
-------------
So I could use `Turbolinks.visit()` inside a js.erb file and make all the flow control and redirects using code at server side, right?


I do what I can. :)

I've deleted the old profile, just reposting my questions.
-------------
Amazing! Wow you're super fast replying!


Stephen Miles MacLennan

Hey Chris, what actually controls the redirect after the team is created? Is is the window location in the js or the redirect_to in the controller html response? I'm using axios (as I believe vue-resource may not be supported going forward?) and disabled turbolinks. However, when I try to redirect to show my new item, it shows it loading in the logs, but the page doesn't change.

This line is what uses the JSON response and Turbolinks to redirect to the team page: https://github.com/gorails-...

And you should keep Turbolinks, it's awesome. :P

Stephen Miles MacLennan

Ok cool thanks. Decided to scrap Axios (been such a pain!!!!!) and going to implement Turbolinks. I'm done but I'm getting a weird error. The form isn't loading now, and I get an error in the console that states:

Uncaught TypeError: Cannot read property 'headers' of undefined
at HTMLDocument.eval (eval at <anonymous> (proposal.js:1393), <anonymous>:20:73)
at Object.t.dispatch (turbolinks.self-1d1fddf91adc38ac2045c51f0a3e05ca97d07d24d15a4dcbf705009106489e69.js:6)
at r.t.Controller.r.notifyApplicationAfterPageLoad (turbolinks.self-1d1fddf91adc38ac2045c51f0a3e05ca97d07d24d15a4dcbf705009106489e69.js:7)
at r.t.Controller.r.pageLoaded (turbolinks.self-1d1fddf91adc38ac2045c51f0a3e05ca97d07d24d15a4dcbf705009106489e69.js:6)
at turbolinks.self-1d1fddf91adc38ac2045c51f0a3e05ca97d07d24d15a4dcbf705009106489e69.js:6

What would cause that? I've double checked the X-CSRF-Token line and it's correct, and also I've included the TurbolinksAdapter

Just for reference this all got sorted out in Slack for anyone reading this later on: https://gorails.com/forum/h...


Thanks for this series! It gives a completely different view of Vue + Rails than most. It seems much more pragmatic than doing a SPA for part of a website.


Thanks! Super useful and easy to follow


Chris,

Can you give some ideas on how to deal with managing multiple Vue.js apps in a single application? For example what if the example rails app had other forms besides teams that need functionality (not necessarily nesting) and we want to develop that functionality using Vue.js as well.

Would you check for the existence of the html element and conditionally create Vue instances? For example, in hello_vue.js you write var element = document.getElementById("team-form"); if (element != null) { ... Would you just continue this pattern?

I have many js widgets and views in an existing Rails Application. These widgets get used on various views and sometimes more then once on a single view. Most of the time this javascript is enhancing an html element such as a table or input. My current js architecture is based on this article ( https://medium.com/@cblavie... ).

Would each of these widgets become a Vue app or is there another concept that I am missing?

Pretty much exactly what you mentioned. I am working on a video app that I'll be showing off more in the future, but it has a bunch of videos on the page and I wanted to use a Vue app for each one. I just selected all the elements that matched like ".video" and then looped over them and created a new Vue() app for each one. Works like a charm.

You won't need to check if the element exists in this case because it won't run the loop if there are no results so it may be a little more straightforward than selecting by ID which could return you null (and and why we have to check it).


Hm, that's cool, until you need to validate the form and show and handle all these nested validation errors. It requires much more efforts than the Rails nested_attributes.

And, as I see, Turbolinks doesn't allow you reuse the VUE form when you click the back button in browser, even if you use this TurbolinksVUE library. The form will be activated just once by VueJS, when the page was loaded. Check this out :)


Login or Create An Account to join the conversation.

Subscribe to the newsletter

Join 24,647+ developers who get early access to new screencasts, articles, guides, updates, and more.

    By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

    More of a social being? We're also on Twitter and YouTube.