React on Rails
React on Rails
Ever try writing Angular on Rails? I have and it’s nothing short of belly flopping into a pool of rusty nails and sadness.
Don’t get me wrong. We love Angular here at Cloudspace and it’s our front end framework of choice for most split stack applications. However, as a light front end layer for a Rails app….no. Just no. For all the fun directives, controllers, filters, and animation helpers give you, the battle for ownership over business logic, routing, and other kinds logic becomes a fierce neverending struggle driving you closer and closer to the bar for happy hour.
All I can say is that React on Rails has made full stack development fun for me again.
Problem Space
I want to have a seamless flow of data from my models to my javascript heavy widgets with very little effort on my end.
Tools
React is as close to a web component framework as we’re going to get in modern JavaScript, alongside Polymer. It allows us to create tight JavaScript objects that represent various sub components of our applications. React however, has no support for business logic, routing, or structure.
Ruby on Rails is a full encompassing web application framework. It’s goal is to be the one platform for you application and glue together any extra components you need through the use of gems and engines. Ruby on Rails on it’s own however, is terrible at complex and highly interactive user interfaces.
Enter React-Rails
Like everything in Ruby, react-rails is just a gem. The install instructions can be found on their github page here, but they fundamentally come down to just installing a gem and running a generator. https://github.com/reactjs/react-rails
When generated, the gem adds a components directory to your assets directory and allows you to write in Facebook’s flavor of JSX. You also have access to view helpers that will render those components inline with your HAML or ERB.
A Bit on Web Components
The web component is a front end design pattern that is steadily gaining more popularity over the past few years. We saw it in it’s infancy with jQuery plugins, and saw it truly start to shine in Angular with directives, and then emerge in it’s purest essence in React and Polymer. As we speak, native web components are growing more and more support on a native level with browsers. Put it bluntly, the web component is javascript and markup that extends the normal functionality of HTML. For example, if we want a navbar on our page, a web component may look like this.
This would build a navbar contained to the custom root element that we specify. This is highly reusable, and should ideally carry very few dependencies.
The react-rails gem fully embraces the web component philosophy while at the same time, embraces web component like structures as a part of the Rails framework. They are treated as just another layer on top of models, views, and controllers. This pattern might better be thought of as Model, View, Controller, Web Component. Just promise to not abbreviate that as MVCWC. We really don’t need more acronyms.
Component Generation
You can generate a new component by just running a generator like you would a model, controller, or a migration.
This will add a new base React component in your assets directory and exposes an associated view helper.
View Helpers
What makes the gem worth while though is the view helper that let’s you easily pass data to your javascript layer as easily as including a partial.
This allows your React class to act on a new level below your view, like a directive might in Angular. This, my friends, acts like a component.
Example Project: From Database to Graph
The following files show how we might implement a d3 bar graph detailing the number of blog posts per topic in an application. You can see how we just allow data to move in a linear fashion from the database, to the model, to the controller, to the view, and eventually to the bar graph.
The full project can be viewed here. https://github.com/cloudspace/react-rails-blogpost
Step 1: Setup
Add to your gemfile
Run
Step 2: Scaffold your Model
We don’t need anything really complex for our data layer. Really we just want the supporting elements to make a graph possible. So, we’re going to run the default scaffold for a model.
rails g scaffold Post topic:string content:string title:string
This will build our model
Step 3: Create some Seed Data
In your seeds file, you’re going to want to create a few posts to work with when we migrate the database. So, just add the following.
Step 4: Build a Method to Pull Down Data
Our graph is going to need our data in a certain format to work with. Make the Post model look like this. Since this method makes use of all of the Posts, we put it on the class level.
In our PostsController we’re also going to want to grab hold of this data from the model and pass it to the view like so.
Step 5: Generate a Component
Step 6: Building the Graph
We’re going to make the graph component look like this. Since, this isn’t a D3.JS post, I won’t go too much into how the graphing logic works, but I will point out what is custom, and what React is expecting.
React is expecting two properties in this particular object to exist, ‘propTypes’, and ‘render’. All React components are duck typed to expect a variety of different methods that hook into different steps of compilation and validation. In this case, we only care that the types that we pass in are correct and translated from Rails to JSX, as well as that we actually render the graph.
Everything else is custom to how we want our component to actually work. For example, the xScale and yScale functions just help us abstract out some of the D3 code to be a bit more readable.
Step 7: Including our component
It’s not going to look very pretty, but all we care about right now is that we can see the graph. Head over to app/posts/index.html.erb
and add the following right under the h1 tag.
React-rails will handle the translation of data as it moves between languages for us. Stats is a Ruby hash, yet will be an object literal when we jump to our JSX code.
Step 8: Styling our Graph
We don’t need much style, but we do want to make sure that graph works and looks semi decent, especially since our graphing logic in the component has no styling whatsoever. Create a new sass file named chart.scss and add the following.
Conclusion?
Componentizing your front end can do wonders for your web apps, especially in a world where spaghetti jQuery runs amuck. React is just one solution, but there are several options out there that can help you achieve a similar result. I hope that next time you start a Rails app though, that you will give React, or a similar component like framework a try.