How to Replace jQuery with Vue.js in Ruby on Rails Apps

If you‘ve been developing Ruby on Rails applications for a while, chances are you‘re very familiar with using jQuery to power the front-end. jQuery has been the default JavaScript library in Rails for many years, included out-of-the-box and ready to use immediately.

It made sense at the time. jQuery was far and away the most popular JS library and made DOM manipulation and Ajax much simpler compared to plain JavaScript. Rails is all about convention over configuration, so having jQuery as a standard allowed developers to be instantly productive.

However, a lot has changed in the world of front-end development since the early days of Rails. The rise of modern JavaScript frameworks like React, Angular, and Vue.js has fundamentally changed best practices in front-end architecture. jQuery‘s declarative, HTML-first approach is showing its age compared to component-based architectures.

Replacing jQuery with Vue is increasingly a smart choice as client-side code in Rails apps grows in size and complexity. Vue is lightweight, easy to learn, and integrates well with the Rails way of doing things. In this post, we‘ll walk through the process of incrementally introducing Vue into a Rails app and strategies for a smooth transition away from jQuery.

Why Vue.js?

Vue.js has gained popularity in the Rails community as a simpler, lighter-weight alternative to React or Angular. Out of the modern front-end frameworks, Vue is the most similar to Rails in terms of favoring convention over configuration.

Some of the key advantages of Vue over jQuery in a Rails project include:

  • Components: Vue apps are built around reusable, composable components rather than direct DOM manipulation. This makes complex UIs much more manageable.
  • Declarative rendering: Vue‘s template syntax allows you to declaratively bind data to HTML. This is more readable and maintainable than jQuery‘s approach.
  • Reactive data: When data changes in a Vue component, the view automatically updates. No more fiddling with the DOM manually.
  • Virtual DOM: Vue uses a virtual DOM like React, only updating what has actually changed. This is a big performance boost over jQuery.
  • Computed properties and watchers: Vue provides convenient ways to create derived values and watch for changes, keeping logic out of your templates.
  • Custom directives: Directives are a powerful way to abstract DOM manipulation into reusable code.
  • Lifecycle hooks: Vue components have lifecycle methods that allow you to hook into key moments, like when a component is created, mounted, updated, or destroyed.

So while jQuery is great for simple things, Vue really shines as your front-end grows in complexity. It provides a more robust, maintainable foundation for building modern web interfaces.

Getting Started with Vue in Rails

The first step to replacing jQuery with Vue in a Rails app is to install Vue and set it up to work with the asset pipeline. With Rails 5.1+, this is incredibly simple thanks to webpack integration.

First, add Vue to your project via Yarn:

yarn add vue

Then enable webpack in your Rails project if you haven‘t already:

rails webpacker:install

Finally, configure Rails to use the Vue version of webpack:

rails webpacker:install:vue

This creates a hello_vue.js file in the app/javascript/packs directory. You can use this as a starting point or create a new pack file for your Vue code.

To use the Vue pack file in your Rails views, use the javascript_pack_tag helper:

<%= javascript_pack_tag ‘hello_vue‘ %>

Now you‘re all set to start writing Vue code in your Rails app!

Organizing Vue Code

As you begin to add more and more Vue code to your Rails project, you‘ll want to keep it organized in a sensible way. The recommended approach is to split your Vue code into single-file components.

Single-file components have a .vue extension and include the template, logic, and styles for a component in one file. Here‘s a simple example:

<template>
  <div>

    <button @click="reverseMessage">Reverse Message</button>
  </div>  
</template>

<script>
export default {
  data() {
    return {
      message: ‘Hello Vue!‘  
    }
  },
  methods: {
    reverseMessage() {
      this.message = this.message.split(‘‘).reverse().join(‘‘)
    }
  }
}
</script>

<style scoped>
h1 {
  color: #42b983;
}  
</style>

You can put your .vue files in the app/javascript directory, grouped into subdirectories as needed. For example:

app/javascript/
  components/
    MyComponent.vue
  pages/
    HomePage.vue
    AboutPage.vue  

Then you can import and register these components in your pack files:

import Vue from ‘vue‘
import MyComponent from ‘../components/MyComponent.vue‘

Vue.component(‘my-component‘, MyComponent)

document.addEventListener(‘DOMContentLoaded‘, () => {
  const app = new Vue({
    el: ‘#app‘
  })  
})

This keeps your Vue code modular and separate from your Rails views, while still being easy to integrate.

Replacing jQuery Code with Vue

Once you have Vue set up in your Rails project, you can start replacing your jQuery code with Vue components. The process usually looks like this:

  1. Identify a piece of jQuery functionality to replace, like a form or widget
  2. Create a new Vue component to handle that functionality
  3. Replace the jQuery code in your Rails view with the Vue component
  4. Repeat until all jQuery is gone!

Let‘s look at an example. Say you have a Rails view with a form that uses jQuery to show/hide a field when a checkbox is toggled:

<%= form_with(model: @user, local: true) do |form| %>
  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div class="field">
    <%= form.check_box :subscribe %>
    <%= form.label :subscribe, ‘Subscribe to newsletter‘ %>
  </div>

  <div id="frequency-field" style="display: none;">
    <%= form.label :frequency %>
    <%= form.select :frequency, options_for_select(User::FREQUENCY_OPTIONS) %>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

<script>
$(function() {
  $(‘#user_subscribe‘).change(function() {
    $(‘#frequency-field‘).toggle(this.checked);
  });
});  
</script>

To replace this with Vue, first create a new component:

<template>
  <div>
    <div class="field">
      <label>
        <input type="checkbox" v-model="subscribed" />
        Subscribe to newsletter
      </label>  
    </div>

    <div class="field" v-show="subscribed">
      <label for="frequency">Frequency</label>
      <select id="frequency" v-model="frequency">
        <option v-for="option in frequencyOptions" :value="option">
          {{ option }}
        </option>
      </select>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      subscribed: false,
      frequency: ‘weekly‘,
      frequencyOptions: [‘daily‘, ‘weekly‘, ‘monthly‘] 
    }
  }
}
</script>

Then update the Rails view:

<%= form_with(model: @user, local: true) do |form| %>
  <div class="field">
    <%= form.label :name %>
    <%= form.text_field :name %>
  </div>

  <div id="subscription-form">
    <subscription-form></subscription-form>
  </div>

  <div class="actions">
    <%= form.submit %>
  </div>
<% end %>

Finally, mount the Vue component:

import Vue from ‘vue‘
import SubscriptionForm from ‘../components/SubscriptionForm.vue‘

Vue.component(‘subscription-form‘, SubscriptionForm)

document.addEventListener(‘DOMContentLoaded‘, () => {
  const app = new Vue({
    el: ‘#subscription-form‘
  })  
})

Just like that, we‘ve replaced the jQuery code with a reusable Vue component. The form is now more declarative and easier to reason about.

We can use this same technique all over the Rails app, gradually replacing jQuery bits with Vue components until the transition is complete. Along the way, you‘ll likely find plenty of opportunities to refactor and improve old code.

Handling Data with Vue and Rails

Of course, forms aren‘t very useful if they don‘t submit data to the server. With Vue, you have a few options for handling data submission in a Rails app.

One approach is to use Vue‘s v-model directive to bind form fields to component data, then submit the form normally with Rails. The component data will be included in the form params.

For example, modifying the above component:

<template>
  <div>
    <div class="field">
      <label>
        <input type="checkbox" v-model="subscribed" name="user[subscribed]" />
        Subscribe to newsletter  
      </label>
    </div>

    <div class="field" v-show="subscribed">
      <label for="frequency">Frequency</label>
      <select id="frequency" name="user[frequency]" v-model="frequency">
        <option v-for="option in frequencyOptions" :value="option">
          {{ option }}
        </option>  
      </select>
    </div>
  </div>  
</template>

<script>
export default {
  data() {
    return {
      subscribed: false,
      frequency: ‘weekly‘, 
      frequencyOptions: [‘daily‘, ‘weekly‘, ‘monthly‘]
    }
  }  
}
</script>

Now when the form submits, the subscribed and frequency values will be included in the user params hash.

Another option is to submit the form data via Ajax using Vue‘s $http service or a library like Axios. This is handy if you want to handle the response in Vue rather than reloading the page.

For example:

<template>
  <form @submit.prevent="submitForm">
    <!-- form fields -->
    <button type="submit">Save</button>
  </form>
</template>

<script>
import axios from ‘axios‘

export default {
  data() {
    return {
      // ...    
    }
  },
  methods: {
    submitForm() {
      axios.post(‘/users‘, {
        user: {
          subscribed: this.subscribed,
          frequency: this.frequency  
        }
      })
      .then(response => {
        // handle success  
      })
      .catch(error => {
        // handle error  
      })  
    }
  }
}  
</script>

With this approach, you have full control over the request and response handling in your Vue code. Just make sure your Rails controllers are set up to handle the incoming params.

Wrapping Up

Replacing jQuery with Vue in a Rails app is a great way to modernize your front-end stack without ditching Rails altogether. By incrementally introducing Vue components, you can make the transition at your own pace while enjoying the benefits of a modern, component-based architecture.

Of course, this post only scratches the surface of what‘s possible with Vue in Rails. As your app grows, you may want to explore additional Vue features and best practices, such as:

  • Vuex for state management
  • Vue Router for client-side routing
  • Mixins and filters for reusable functionality
  • Lazy loading components for better performance
  • Server-side rendering with Ruby gems like Webpacker
  • Testing with tools like Vue Test Utils and RSpec

The beauty of adding Vue to a Rails app is you can take it as far as you want. Whether you just need a few simple components or want to build an entire SPA, Vue plays nicely with the Rails ecosystem.

So what are you waiting for? Start replacing that jQuery spaghetti with some clean, modular Vue components today! Your future self will thank you.

Similar Posts