Integrate Vue.js with Rails 5 application

A quick start on how to integrate Vue.js with Rails 5 applications

Sanketkumar Karve

4 minute read

To start with Vue.js and Rails 5 integration let have a quick overview of what we are going to do.

Rails works on Model-View-Controller (MVC) Architecture. Here we will focus on View(V) part of rails. By default, rails support HTML, CSS, and JS but we want to integrate responsive framework to leverage its benefit and make our view more component based. Vue.js will only take care of your view layer.

To demonstrate Vue.js and Rails 5 integration on an existing application I have created sample rails application. You can check it on HERE

We are going to use webpacker gem to install the Vue.js. To install the Webpacker there are few prerequisites like :

  • Ruby 2.2+
  • Rails 4.2+
  • Node.js 6.0.0+
  • Yarn 0.25.2+

For demo purpose, I have created a sample where the user can Sign up and Sign in. Have index article. (NOTE: You can use Devise gem for that and modify the devise view section) View structure of Rails application looks like:

views
  |-articles
  | |-index.html.erb
  |-layouts
  | |-application.html.erb
  | |-_navbar.html.erb
  |-sessions
  | |-new.html.erb
  |-users
    |-new.html.erb

Let get started by installing the webpacker gem:

Add webpacker gem to Gemlfile. You can check https://github.com/rails/webpacker for an updated version of gem

  gem 'webpacker', '~> 3.5'

Then install the bundle by bundle install

To install the webpack

  bundle exec rails webpacker:install

Webpacker does multiple things for you like add yarn, package.json, webpack-dev-server and javascript folder and application.js file in a pack which resides in the newly created javascript folder.

Lets test if web pack is working by adding bellow tag in application.html.erb

  <%= javascript_pack_tag 'application' %>

Run Rails server rails s and webpack server ./bin/webpack-dev-server

If you are able to see Hello World from Webpacker in a console then you have successfully installed the webpack and ready to install Vue.

Now install Vue

  bundle exec rails webpacker:install:vue

This will install vue, vue-loader, and vue-template-compiler. It will also create a sample hello world program. If you add <%= javascript_pack_tag 'hello_vue' %> you can see Hello Vue! message on the screen.

Before moving forward let me explain how the thing works with Vue and rails. In rails application.html.erb file, when we call <%= javascript_pack_tag 'hello_vue' %> webpacker hunt for hello_vue.js file in app/javascript/pack folder.

In hello_vue.js, It will import Vue.js packages and addEventListener will create a div with id hello.

When new.Vue is called a Vue instance is been created and it searches for div with id="hello" and render the App component.

Let’s do similar with some less code. In users/new.html.erb

<div id="users-new-view">
  <users-new-view>
  </users-new-view>
</div>

<%= javascript_pack_tag 'users/new'%>

In javascript/pack create users/new.js file.

import Vue from 'vue/dist/vue.js';
import UsersNewView from 'views/users/new';

new Vue({
  el: '#users-new-view',
  components: {
      'users-new-view': UsersNewView
  }
});

Also, create view/users/new.vue in javascript folder

<template>
  <form method="post" action="/users">
    <input type="hidden" name="authenticity_token" :value="csrf">
    <div class="field">
      <label class="label">Name</label>
      <input type="name" class="input" name="name">
    </div>

    <div class="field">
      <label class="label">Email</label>
      <input type="email" class="input" name="email">
    </div>

    <div class="field">
      <label class="label">Password</label>
      <input type="password" class="input" name="password">
    </div>

    <div class="field">
      <label class="label">Confirm Password</label>
      <input type="password" class="input" name="password_confirmation">
    </div>

    <div class="field">
      <button type="submit">Submit</button>
    </div>
  </form>
</template>

<script>
export default {
  data: function() {
    return ({
       csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content')
    })
  }
}
</script>

<style scoped>

</style>

You may have noticed in above code that I have explicitly added csrf token as a hidden tag in form. The reason behind is in rails form by default search for csrf token and add in the form which is not in the case in normal form. And rails take the name as authenticity_token.

How do I pass data from Rails to Vue?

Vue deals components and to pass any data to component we use props. So you can convert the data in JSON and pass it as props.

Let say I have current_user and I have pass current_user data in Vue

<div id="layouts-navbar-view">
  <layouts-navbar-view
    :_current_user = "<%= current_user.to_json %>">
  </layouts-navbar-view>
</div>

<%= javascript_pack_tag 'layouts/navbar' %>

You can pass multiple props. We can do same with instance variable by converting it into JSON.

Now in Vue, we handle the current_user details and store in vue data.

<template>
  <div v-if="current_user">
    Signed in as {{ current_user.name }}
    <a href="/logout">Logout</a>
  </div>
  <div v-else>
    <a href="/login">Login</a>
    <a href="/signup">Signup</a>
  </div>
</template>

<script>
export default {
  data: function() {
    return ({
      current_user: null
    })
  },
  props: {
    _current_user: {}
  },
  mounted: function() {
    this.current_user = { ...this._current_user };
  }
}
</script>

<style scoped>

</style>

We are receiving props and when the component is mounted we store current_user details in Vue data.

For reference, you can find the Vue and rails integrated demo project HERE.

comments powered by Disqus