Passing Props to Vue in a Rails View

Devan Flaherty
5 min readJul 15, 2017

--

I’ve been working on a project utilizing Vue.js in Rails, and it’s been fun but challenging as hell. Not because it’s difficult, but because I’m an intermediate user in both frameworks, so the debugging has been so fun!

Anyways I’m hoping I can help others and release a number of quick tutorials to help those kindred spirits.

So let’s take a look at passing data to your Vue instance from your Rails view.

First let’s ask : Why?

In the app I’m building I’m utilizing a variety of technologies. I’m using Rails for all the api, but as well to build out the mostly static marketing pages, and to make my life easier keeping all the Devise authentication views in Rails. I could spend the time to rebuild it in vue and set up some ajax posts and gets, but why? The benefit isn’t worth what it would cost my client right now.

To make those page loads as quick as possible I’m sticking with Turbolinks, which with a virtual DOM can cause some issues.

And obviously I’m using Vue.js for the more “appy” and UX side of things.

In some parts of the site I’m making http request via Axios, and building lists, show views, and such all via Vue Router and url params within Vue Router (That’s a whole other tutorial in it self). BUT…On another page, It made sense for the data sent from the Controller to the View be passed straight to the respective Vue Instance without making any http get requests.

So the answer to the question why, is that it works for what I need to do in this certain instance. For full-on SPA’s made in a Rails-Api only build I don’t think this would make the most sense, but if you are living in both, because it saves you and your client time. Then that’s all the reason you need.

Getting the Data

Let’s get this out of the way. We are presuming you have found some record in your Controller and you are wanting to send that instance variable to your View.

Like so:

Cool. We are using Rails resourceful routes in conjunction with our Contact model. The resourceful route exposes an ‘edit’ path that looks for this pattern: ‘contacts/:id/edit/’.

From the Controller in our ‘edit’ action we defined, we simply are finding that ‘Contact’ based on the ‘:id’ param sent in the URL. This is all handled by Rails guys, we don’t have to do any http get requests in a Vue instance to grab what we need, Rails is doing the work! So let’s exploit that!

Prepping the Data

Next we need to somehow attach this ‘@contact’ and all the properties associated with it into our Vue instance…from the view.

Let’s make a quick assumption that we are working in, ‘views/contacts/edit.html.erb’, since that makes the most since.

Secondly let’s make sure you have included the ‘javascript pack tag’, in your layout. We could just include it on this view, but I find performance is better when it’s included on every page, but don’t be afraid, just cause we have the ‘pack tag’ included it doesn’t mean we will initialize this Vue Instance on every page.

<%= javascript_pack_tag 'contacts/main.js'%>

Thirdly, let’s apply what the Rails team has already provided us in their documentation (https://github.com/rails/webpacker).

Which looks like this:

Essentially we are taking the data and converting to JSON with that little ‘.to_json’ method. Once we have formatted safely to JSON we pass into a data-attribute on the element the Vue Instance will mount to. Keep in mind, once Vue Renders the element will be replaced, so you won’t have this messy/squirly JSON object in your raw code.

Great, so the data has been passed into our Rails View, which has the element defined that the Vue Instance will mount to, as well as a data-attribute populated with JSON from found record we got from our respective Controller.

Now let’s look at the root Vue Instance.

Digesting the Data

I’m still figuring out app structure. “What’s the best way to structure your application?”, you may ask, and hell-if-I-know. What I do know is I like patterns and things to make sense. Sooo I structure my ‘packs’ directory like my ‘app/views’ directory. Makes sense to me.

So in ‘javascript/packs/contacts/main.js’ is where include this next bit, and is the file you would be including as your ‘javascript pack tag’, mentioned above.

Your file should look like this:

There are a lot of notes in there that make it look pretty crazy, but it really isn’t that bad.

See, much better, but notes are important.

In a nut shell, we :

  1. Wrap our Vue instance with an eventListener for ‘turbolinks:load’.
  2. Make sure the element the instance will mount to is present.
  3. Parse the data from respective mounting element’s data attribute.
  4. Only initialize the instance if both ‘element’ and ‘props’ are present, cause if they weren’t the app would be pointless, and you would get errors, and no good things.
  5. Pass the newly created ‘props’ const into the instance via ‘render’

[Note]: It’s important you not only check for the mounting element, but the PROPS as well. Turbolinks was giving me such crap because the page would load, would find the div from a preview and the vue instance would render, all before props was parsed and sent through. It would work if I hit the link directly, but not if I was scrubbing around via links and navigation.

So, if your app depends on the props, you have to make sure the props are present before rendering it.

Using the data

The moment you’ve been waiting for, you literally couldn’t careless about anything else, you just want to see how to utilize the freaking props, so without further adieu.

At this point we just define the props we want to use in our index.vue template like we would any other prop, and we have access to it.

…and that is it.

Well, guys and gals, there isn’t much more to say here, aside from the point that I spent more time on this article than probably needed. If it saves you an hour or any frustration or heart ache, then it’s worth it though.

If this was helpful at all, if I have typos, or if there is anyway I could have written this better please don’t be afraid to reach out!

--

--

Devan Flaherty

Husband. Dad. Front-End Dev at Moment. There is a salted honey pie from a bakery in Portland, Or … I think of it often.