i blog about: Software Development | Jeeps | Family | Health

Rails MVC to Vue JS Part 1

i have used 'web packer' and 'foreman' gems. Then used npm to get through various packages to get TypeScript and Vue working in the asset pipeline. i am not covering this as the topic is well covered and the situations are plenty. i will say with my inexperience with these tools and solutions that it took me quite a bit to understand mainly webpacker and its "gems". If you are thinking in terms of gems, then think npm install. Also, it is configuration over convention so get ready for the config tedium that you aren't used to using Rails.

Ok, so I purposely built short posts, blog posts and a work log tracking tool using Rails MVC specifically for the purpose of converting these solutions to using Vue. I chose view because it seems like a good choice when deciding to keep Rails.

The general approach here will be to target existing forms and markup with new Vue components. If you were starting with Vue and no implementations you would create button components, form UI components etc and the solution would be more Vue/JS centric. I am attempting to use Vue and preserve a document that can be easily crawled, thus preserving SEO.

Let's start with the simplest implementation, short posts, which you can see from the overview page. Here is the form to create them using Rails MVC.



  <div class="row">
    <div class="col col-sm-12 col-md-3">
      <div class="form-group">
        <label for="post">post</label>
        <input type="text" class="form-control" id="post" name="post" placeholder="all things wonderful">
      </div>
    </div>
  </div>

  <button type="submit" class="btn btn-primary">post</button>


i create a Vue instance like so...


import Vue from 'vue'
import AdminShortPosts from '../components/admin-short-posts.ts'

document.addEventListener('DOMContentLoaded', () =&gt; {
    new Vue({
        el: '#vue_admin_app',
        data: {
        },
        components: {
            'admin-short-posts': AdminShortPosts
        }
    })
})

This will be my admin app that registers all my admin based components. As i create more i will import them here and add them to the components list.

Then in my Rails view i add this html.


<div id="vue_admin_app">
  <admin-short-posts></admin-short-posts>
</div>

Now, I need to create the admin-short-posts component like so...


import Vue from 'vue'
import Component from 'vue-class-component'
import Alerts from '../components/alerts.ts'

@Component({
    template: `
        <div class="admin-short-posts">
            <alerts v-bind:alerts="alerts"></alerts>
            <div class="row">
            <div class="col col-sm-12 col-md-3">
              <div class="form-group">
                <label for="post">post</label>
                <input type="text" v-model="short_post" class="form-control" placeholder="all things wonderful">
              </div>
            </div>
          </div>
        
          <button v-on:click="post" class="btn btn-primary">post</button>
      </div>
    `,
    components: {
        'alerts': Alerts
    }
})

export default class AdminShortPosts extends Vue {
    short_post: string = "";

    data() {
        return {
            alerts: []
        }
    }

    post():void {
        this.alerts.push({type: 'warning', title: 'Nice', message: this.short_post});
    }
}

This component uses the reusable alerts component...


import Vue from 'vue'
import Component from 'vue-class-component'

@Component({
    template: `
      <div class="alerts">
        <div v-for="alert in alerts">
            <div class="alert" v-bind:class="type_class(alert)" role="alert">
              <strong>{{alert.title}}</strong> {{alert.message}}
            </div>
        </div>
              
      </div>
    `,
    props: {
        alerts: {
            type: Array,
            required: true
        }
    }
})

export default class Alerts extends Vue {
    data() {
        return {
            alert_data: []
        }
    }

    mounted() {
        this.alert_data = this.alerts;
    }

    type_class(alert: Hash): string {
        return `alert-${alert.type}`;
    }
}

Clicking the post button creates an alert which shows the short message that is entered into the edit. Ya! We now have a UI that can allow the user to enter a short post and we can display alerts based upon what happens when we talk to an API. So in my next post we will explore a data/service layer that will allow us to actually create a short post and handle the results.

Posted: September 05 2018