React on Rails

When I was first learning React I went through about 17 tutorials before I finally grokked what it was all about. Which is weird because React is quite simple really.

I’m gonna build the tutorial that I wished I’d had when I started learning it.

I’ll assume my reader knows Rails very well but knows just enough Javascript to add sprinkles. I won’t try to teach you React, but I’ll point you in the right direction to learn what you need to know.

Let’s do this.

But “Do what?” you may ask?

We are going to build a blogging platform. It’s going to be Rails on the back end and React on the front end. We’re going to test with Minitest, Jest and Enzyme as we go along. We’ll deploy it on Heroku. We’ll use CircleCI for continuous integration.

We are not going to use Redux. I have an idea for a more object-oriented state management system that leverages the rich metadata that Rails already has and, hopefully, avoids all the acres of boilerplate code that every other React tutorial seems to generate. I don’t have a design for this in mind. I’m hoping one will emerge as we go along.

Let’s start with a quick planning session. What do we want our blogging platform to do?

  • An author can publish a blog post.
  • A reader can read a blog post.
  • The home page shows a list of posts, most recent first.
  • An author can edit a blog post.
  • Readers can comment on a post.
  • Comments are held for moderation.
  • The author can approve comments.
  • Notify the author when there are comments.

At some point we’ll want to upload images and have multiple authors and fancy formatting and RSS feeds and other blogphernalia but that list is enough to get us started.

I’ll tackle the second story first because I like to get something working from end to end as quickly as possible and reading a post has fewer moving parts than creating one.

Join me here to get started.

Episodes

I’ll add links to all the episodes here for folks who want to skip ahead.

  1. Install Rails, Yarn, React & create a project on GitHub.
  2. Create a Post model in Rails and show the JSON.
  3. Introducing React components.
  4. Testing React with Jest & Enzyme. Setup CircleCI.
  5. Introduce class components and load a post from the server.
  6. Mock the API call to the server.
  7. Add a test helper to make testing React components easier.
  8. Create a new post in our PostsController.
  9. Use a controlled form to create a new post.
  10. Connect our new form to the back end to create a post.
  11. Fetch a list of posts from the server.
  12. Testing asynchronous components.
  13. Managing state in a React application.
  14. CHECKPOINT: Review the plan.
  15. Add a user model for registration and sign in.
  16. Deploy to Heroku.
  17. Extract our ReactToRails library to eliminate some boilerplate.
  18. Use the ReactToRails library to build the CRUD for users.

Back in the day…

In the navy, we would have called this a dit.

I did an electronic engineering apprenticeship in the Royal Navy and, in one of our classes, we had to build little circuits with actual transistors and resistors, wires and crocodile clips. We built AND gates and OR gates and XOR gates and NAND gates and all the rest.

File:TTL NAND OC.svg
NAND gate – Michael Frey

In the next class, they gave us little silicon chips that had AND, OR, XOR, etc gates built-in and we had to connect them all together to make adders and accumulators and hooked them up to 7-segment LED displays and switches to make a simple calculator. You can guess what comes next.

half adder circuit using NAND gates only
Half adder using NAND gates only – Nitianabhigyan

First, there was the Limrose Machine that you programmed by the toggling switches on the input port to make binary numbers.

Image
Limrose Machine

Next up was the Zilog Z80 that we programmed in assembly language until finally, they taught us BASIC on a proper (circa 1984) computer.

When I finally made it on to HMS Southampton to do my sea training, I took turns to do watch-keeping in the computer room where there was an enormous (bigger than my living room) Ferranti FM1600-B computer that the ship used for target tracking and fire control.

It was like going back to the Limrose Machine after programming in BASIC.

This computer had 1k of RAM in about a cubic foot of magnetic core and was connected to all the ships systems via synchros. They were mechanical synchros mind you so, every time the gun turned or the radar tracked a target, you’d hear the Zzzzz of the synchros lining up.

The computer had no ROM. Its operating system was stored on 9-hole punched tape on these massive paper spools which the tape reader would dump into a big basket for the computer operator to re-spool by hand ready for next time.

Unfortunately the computer did not know how to read 9-hole tape but there was another spool of 5-hole tape with the instructions. If only the computer knew how to read 5-hole tape…

Fortunately, the computer operator (me!) had memorized the long series of 24 bit instructions to be entered on the bit switches on the panel of the Ferranti that would start the spool spooling.

This is not the computer. This is just the input panel.

When the computer crashed in the middle of the night (which it did, frequently) and the angry captain was calling (SHOUTING!) down from the Ops Room, the poor operator (me!) had to frantically remember the series of instructions to start that 5-hole tape spooling.

1101 0001 1000 1000 1000 1100
1001 0101 1100 0000 1011 1100
0101 1001 1010 1100 1100 1111
1111 0101 1100 1100 1000 1100
0101 0101 1000 1000 1000 1110

Then I had to enter a different series of instructions for the 9-hole tape. Then quickly, re-spool the paper tape in case it crashed again.

Good times.

Ferranti FM1600 B - Computer - Computing History
The computer is that big thing (in several cabinets) in the background. The thing in the foreground is the input panel.
Note the paper tape reader next to the input panel.
Note also the big blue bin where the paper got dumped as it was spooling.

After programming in Ruby and Rails for several years, Javascript and React feels like going back to the Limrose Machine.

React is so much better than Javascript sprinkles in so many ways but I still feel like I am connecting NAND gates with crocodile clips. It feels like there should be another layer of abstraction on top of React/Redux to hide some of the messiness.

Maybe all that stuff is out there and I just have not found it yet?

It started with a rant

I’ve been using React for a while and now that I have got over my disgust for coding with angle brackets, I think it is wonderful.

I’ve built two big sites on Rails over the last few years and the ”sprinkles of Javascript” pattern that Rails wants me to use has grown, both times, into a big ball of javascript mud where it’s hard to figure out where anything is or belongs.

For my last two or three sites I have used React and I don’t want to go back to sprinkles of Javascript. I like the logical flow of react and I love the idea that all of the UI flows out of the current state.

It’s not all roses in React Land though.

The people who set the trends in Javascript have a great tolerance for ugliness and it bothers me that all of the tutorials have you copy-pasting reams of boilerplate code and you have to write a thousand lines of code before you have anything to show for it.

Here’s an example from https://www.robinwieruch.de/react-fetching-data (nothing against this particular example. This is a typical React tutorial.)

import React, { Component } from 'react';
 
export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      data: null,
    };
  }
 
  componentDidMount() {
    fetch('https://api.mydomain.com')
      .then(response => response.json())
      .then(data => this.setState({ data }));
  }

render() {
    const { hits } = this.state;
    return (
      <ul>
        {hits.map(hit =>
          <li key={hit.objectID}>
            <a href={hit.url}>{hit.title}</a>
          </li>
        )}
      </ul>
    );
  }
}

It’s easy to understand why the folks at Basecamp prefer their sprinkles of Javascript.

Here’s the (kind of) equivalent code in Rails/haml.

class HitsController < ApplicationController
  def index
    @hits = Hit.all
  end
end

# index.html.haml
%ul
  - @hits.each do |hit|
    %li= link_to hit.title, hit.url

Why does Javascript need so many lines of code? Is it intrinsic to the language or is it that the folks who write it aren’t interested in readability? And who thought it was a good idea to write code in angle brackets?

And that was just the view.

I haven’t figured out state management in React yet and that’s my mission in this series of posts — to find a better to way to hook the view up to a Rails back end. I have no idea whether I will arrive at my destination but I intend to travel well.

In my first React app, I tried to build an object model like I might in an iOS app and I passed a controller down through the view components to handle events. Disaster.

Then I discovered Redux and I used it for the next couple of apps. I felt like I had joined a south sea cargo cult. If React revels in a surfeit of syntax, Redux positively wallows in it. The tutorials never seem to end and I found I had to constantly go back three pages to remind myself of the difference between an action and an action creator.

On page 7 of the tutorial, if your actions and your action creators and your reducers and your selectors and your dumb components and your connected components are all aligned correctly you’ll get a bit of data to appear in a view but I can’t stop thinking the whole time how much easier it would be to just write 5 lines of haml.

When I am learning, I like to have something working with a few lines of code and then to build from there.

The people who invented Redux have mounded Byzantine complexity on top of the ugliness of Javascript. I often wonder what Redux would look like if @dhh had invented it. Could Javascript and React be beautiful like Ruby and Rails?

And finally, a bonus, and no doubt unwarranted, rant about functional programming.

After 30 years of OOP, I struggle a lot with functional programming. It bugs me no end that, in Redux, the things that look a lot like methods are on the other side of the island from where the data lives. It’s as though the cargo cult people discovered that you could throw a message in a bottle into the outgoing tide and it would be received in the next cove on the following Tuesday.

Why not put the methods next to the data that they manipulate? I’m imagining an object-oriented Redux that feels a bit like Active Record. 

So that’s what I’m going to do. Like the final round of Whose Line Is It Anyway?, I’m going to try to sing Redux in the style of @dhh. 

Wish me luck.

Back to Blogging

I was quite active in the XP community in the first few years of the millennium but I’ve have been so focussed on work for so long that I have not had time to think, never mind write.

I picked up Javascript again a couple of years ago after not touching it for 20 years. I have some thoughts that I want to share.

Javascript has changed so much that it was like entering a foreign land. It reminded me a little of that episode of Red Dwarf where Lister and The Cat arrive back in Nodnol after several centuries away and they don’t even recognize the language.

Javascript was like that for me.

I read the other day that no one likes object-oriented programming any more. Perhaps no one ever did, really, and the whole of the last 30 years was just a con trick played on Blub programmers like me by the titans of the software industry.

It is fair to say that, generations later, the idea of organizing your code into larger meaningful objects that model the parts of your problem continues to puzzle programmers. If they are used to top-down programming or functional programming, which treats elements of code as precise mathematical functions, it takes some getting used to. After an initial hype period had promised improvements for modularising and organising large codebases, the idea was over applied. 

I like OOP and, suddenly, I want to write about it.

Here goes…