How to Run Vue in a Rails App

I recently saw an amazing way to integrate Vue into a Rails project, and I wanted to share it here! It's a super easy method that makes it dead-simple to pass data from Rails views into Vue componnets. Not only that, but it only requires that you have a single pack entrypoint for all of your Vue components!

Vue Setup in Rails

So how does this method work? Well the trick is in binding a Vue component to a root element of your DOM so that Vue will process everything else in your HTML as Vue code:

// app/javascript/packs/vue-root.js
import Vue from 'vue/dist/vue.esm'

// Repeat the two lines below for each root-level component you
// want to make available to your Rails views.
import AlphaBox from '../components/alpha-box.vue'
Vue.component('vue-alpha-box', AlphaBox)

document.addEventListener('DOMContentLoaded', () => {
  const vueRoot = new Vue({
    el: '[data-behavior="vue"]',
  })
})

So what is this code doing? Two things mainly: binding a Vue instance to any DOM element with its data-behavior attribute set to "vue", and loading up some Vue components and specifying what tags they should replace.

The line below specifies that the new Vue instance should mount on an element with data-behavior="vue":

el: '[data-behavior="vue"]',

And the lines below load the Vue component in the file ../components/alpha-box.vue, as AlphaBox and install them in the DOM wherever a <vue-alpha-box> tag is seen. Obviously, these two lines should be repeated for however many root Vue components you want to be able to insert into your Rails views.

import AlphaBox from '../components/alpha-box.vue'
Vue.component('vue-alpha-box', AlphaBox)

To use this in a Rails view, we just need to set the data-behavior of an element to "vue" and place the javascript_pack_tag:

<!-- app/views/layouts/application.html.erb -->

<!DOCTYPE html>
<html>
  <head>
    <title>TestApp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all' %>
    <%= javascript_include_tag 'application' %>
    <%= javascript_pack_tag 'vue-root' %> # <!-- INSERT THIS LINE -->
  </head>

  <body data-behavior="vue"> <!-- MODIFY THIS LINE -->
    <%= yield %>
  </body>
</html>

And that's it. There's not much to the setup is there?

Vue inserted in a Rails View

Now we just have to use our Vue components! This is the fun part. Imagine our Vue component is set to mount on <alpha-box> tags takes in one prop called cartId and we already have that available in Rails land as @cart.id. How can we pass that value form Rails to Vue? It's easy!

-# app/views/whatever/whatever.html.haml
%alpha-box{ ":cart-id" => @cart.id.to_json }

This HAML just builds the HTML...

<alpha-box :cart-id="42"></alpha-box>

Which Vue then turns into a component and loads the props in automatically. This works with any props you want to pass as long as they can be serialized and deserialized with JSON!

With the setup in the first half of the blog, we can now pretty much just use our Vue components in our Rails views the same way we'd use them in another Vue component! Amazing!

I originally saw this idea on GoRails and it was just too cool not to share. If you get a chance, I recommend you watch just the first 3 or 4 minutes of the video in the GoRails link at the beginning of this paragraph. It helps to explain everything I talk about in this post a little bit better. (But you can totally skip the rest of the video. He just talks about other, not so good ways to do the same thing.)

Photo by Josh Calabrese