Rails 6 With Full Vue Frontend vs Sprinkled Vue Components
I'm struggling to decide how best to integrate Vue in my Rails 6 app. 🤔
I've read some tutorials that suggest using Rails as API with Vue as frontend. Although I like the idea of doing the entire frontend in Vue leveraging Rails' strong REST API, you also lose a lot of Rails view helpers plus all the other .html.erb
magic.
So I'm leaning more towards just sprinkling Vue components into my Rails app for more dynamic components like loading more cards in a list. However wondering how best to handle things like links and images, since you won't have helpers like link_to
, image_tag
, etc inside your .vue
components.
For example, for a blog with a listing of posts in Rails you'd do something like
<div class="card-columns">
<% @posts.each do |post| %>
<div class="card mb-4">
<div class="card-body">
<h5 class="card-title">
<%= link_to post.title, post %>
</h5>
</div>
</div>
<% end %>
</div>
Where as in Vue you'd do something like
<template>
<div class="card-columns">
<div class="card mb-4" v-for="post in posts" :key="post.id">
<div class="card-body">
<h5 class="card-title">
<a :href="'/posts/'+ post.id">{{post.title}}</a>
</h5>
</div>
</div>
</div>
</template>
<script>
export default {
props: ["posts"]
};
</script>
<style scoped>
</style>
Although now you're hardcoding the href
which is pretty fragile if the routes change in routes.rb
. I much prefer using link_to
or post_path
in .html.erb
, especially when you start using nested resources like post_comment_path(post, comment)
.
So I'm wondering what are best practises for using Vue in Rails app? If you wanted to just use Vue component for dynamic elements, what strategies are recommended? Also how do you decide when to use .vue
vs .vue.erb
?
I'm just curious, is it possible to write vue.erb? Does Rails know how to handle this by default or do you have to do some config magic?
In terms of using Rails/Vue, personally my current practice is to separate them entirely. I build a Vue app that interacts with my Rails API because I use a lot of 3rd party components, and it's simply easier to do that in a separate app altogether.
My Vue app handles it's own routing and static assets, Rails handles it's own API routes and assets, so I do not miss any of the image helpers or link helpers.
That being said,, Vue is a framework that is incrementally adoptable. So you can actually use Vue with a CDN and use it with your html.erb without any issues. If you have existing front end code and a sudden jump to an entirely different Vue app is too much work, it's worth considering this option.
Thanks for the reply Yi Mei Wang! I think what you are suggesting is a good approach.
Here's an article showing how to setup .vue.erb
in your Rails app https://blog.codeship.com/vuejs-components-with-coffeescript-for-rails/ so you can make use of Rails helpers like ActionView::Helpers::FormOptionsHelper
in your Vue components.
Dale,
What did you settle on? I'm planning on taking the approach to start with sprinkling Vue components within rails and let this evolve naturally. I personally do not have the skills to do a full blow SPA with Vue so this was an easy decision for me. What I'm struggling with is how to best sprinkle those components throughout my rails app. The GoRails videos have been super helpful, and I'm using the approaches that Chris has highlighted
- using the content_tag
- using the App mounted to a div
I'm still experimenting on using vuex and using vue components within forms.
Best is to have a wrapper around your your app. Chris talks about this too but just as a refresher
<body>
<div class="wrapper" data-behavior="vue">
<%= yield %>
</div>
</body>
Then throughout your app on your html.erb files you can insert vue components like so
show.html.erb
<div>
<vue-component
:posts="<%= @posts.to_json %>"
></vue-component
</div>
This will then display your vue component on that page. Alternatively you can also do things like this:
Have a vue component say SomeForm.vue where you will not have a template as you'll take advantage of the in-line template feature of Vue. You can import whatever library you want in that vue component have your data, methods etc setup and then do something like this in your html.erb file:
<some-form inline-template :post="<%= @post.to_json %>" >
<div>
<div >
<label class="form-control-label">Post</label>
</div>
<treeselect
:options="posts"
v-model="selectedParent"
:placeholder="placeholderText"
:normalizer="normalizer"
:show-count="true"
value-format="object"
></treeselect>
<%= form.hidden_field :parent_id, {"v-model": "value"} %>
</div>
<div>
<%= form.label :barcode, class: "form-control-label" %>
<%= form.text_field :barcode, class: "form-control", placeholder: "0027081", "v-on:blur": "isUniqueBarcode", "v-model": "item.barcode", ":class": "{'border border-red': validationErrors.uniqueBarcode}" %>
<span class="text-red" v-if="validationErrors.uniqueBarcode">Barcode already exists</span>
</div>
</some-form>