Coming Soon: JavaScript for Rails Developers

This articles was originally published on Rails Designer Late last year I sat down and looked at some of my site's stats. I had loads of articles written that are read by people in the 5-digits every month. Next to that I have a sizeable following on dev.to (+30k) and a solid amount of email subscribers. From all the articles I write, the ones on JavaScript elicit the most questions: “what if I want to this?”, “how would you fix that?” and so on. So, after talking about it with a few developer-friends, I pre-announced a book: “JavaScript for Rails Developers”. It was not a completely new idea, I had it jotted down in my ideas-list for a few years already, but now I had a theme of sorts as well: to make JavaScript your second-favorite language. I had a hunch it was something the market was interested in, but I wasn't 100% sure. So I created a page with a promise of the book and the option to pre-order it with a big discount. Since then a good number of you pre-ordered the book. So much so, that I was confident this book should become reality (I set a goal for myself, and if not matched, I would refund all). So after I decided to go through with the book I spent too much time on finding the right approach. Writing a book is far from the tightly-scoped articles I write here. But at the same, the hands-on articles; building something tangible, always performed better than the more abstract ones. So after many false starts (no really: many!), I finally settled on an idea: building a code editor in Stimulus, based on CodeMirror. This might seem superficial, but I set it up to start with the very basics: using a third-party dependency in Stimulus to extending the functionality with each chapter. Then I explore whenever something new is introduced. Here is an excerpt (the actual markdown/asciidoc I am writing): (…) Now you got a super basic editor working that is not much better than running `data:text/html, ` in your browser. The content on load is static and any change made is lost when you refresh the page. ## 3.3.1 Passing data to a Stimulus controller Stimulus has the values API that allows to pass data to the controller from the HTML. Like a lot of things in Rails, Stimulus also follows certain conventions. You can pass values, like strings, integers and hash and array-objects using the following syntax: `data-[controllerName]-[valueName]-value=""`. Then in the controller you define it using the `static values` object, like this: ``` javascript import { Controller } from "@hotwired/stimulus" import { basicSetup } from "codemirror" import { EditorView } from "@codemirror/view" export default class extends Controller { static values = { content: String } // … } ``` ### Static class field in JavaScript Wait… “static values object”? You can compare the *static class field* to Ruby's class methods (`self.` or `⁠class "It me!" ``` In JavaScript: ``` javascript class Example { static classMethod() { return "It me!" } } Example.classMethod() // "It me!" ``` Both look pretty much alike, right? As an aside: in a later chapter, I will dive deeper into JavaScript classes. Stimulus adds some extras to it too; “hey, these properties should be available across all instances of this controller (not just the current instance). Oh… also I want you to automatically create methods to get/set these values.” So with the above added `static values = {}` line, you automatically get: 1. Getters, like ⁠`this.contenValue`; 2. Setters, like ⁠`this.contenValue = 42`; 3. Has-methods, like ⁠`this.hasContentVale`. (…) ### Fat-arrow functions But before continuing, there is some interesting, and often confusing, JavaScript tomfoolery going on here that trips up many Ruby developers: ``` javascript EditorView.updateListener.of((update) => { // … }) ``` What you see here is called a (fat) arrow function `() => {}`. It was introduced in ES6/ES2015. In Ruby you can compare it to the ⁠`->` (lambda) syntax, but with the added benefit of a lexical `this` binding. Lexical-what? It will automatically keep `this` pointing to where it was defined. Before ES6/ES2015, you had to add `bind(this)`. Let's change the above code to use the post-ES6 syntax to check it out: ``` javascript // … connect() { this.editor = new EditorView({ doc: this.contentValue, parent: this.element, extensions: [ basicSetup, // EditorView.updateListener.of((update) => { // if (update.docChanged) { this.#update() } // }) EditorView.updateListener.of(function(update) { if (update.docChanged) { this.#update() } }.bind(this)) ] }) } // … ``` When making changes in the editor yo

Mar 18, 2025 - 22:33
 0
Coming Soon: JavaScript for Rails Developers

This articles was originally published on Rails Designer

Late last year I sat down and looked at some of my site's stats. I had loads of articles written that are read by people in the 5-digits every month. Next to that I have a sizeable following on dev.to (+30k) and a solid amount of email subscribers. From all the articles I write, the ones on JavaScript elicit the most questions: “what if I want to this?”, “how would you fix that?” and so on.

So, after talking about it with a few developer-friends, I pre-announced a book: “JavaScript for Rails Developers”. It was not a completely new idea, I had it jotted down in my ideas-list for a few years already, but now I had a theme of sorts as well: to make JavaScript your second-favorite language. I had a hunch it was something the market was interested in, but I wasn't 100% sure.

So I created a page with a promise of the book and the option to pre-order it with a big discount. Since then a good number of you pre-ordered the book. So much so, that I was confident this book should become reality (I set a goal for myself, and if not matched, I would refund all).

So after I decided to go through with the book I spent too much time on finding the right approach. Writing a book is far from the tightly-scoped articles I write here. But at the same, the hands-on articles; building something tangible, always performed better than the more abstract ones.

So after many false starts (no really: many!), I finally settled on an idea: building a code editor in Stimulus, based on CodeMirror. This might seem superficial, but I set it up to start with the very basics: using a third-party dependency in Stimulus to extending the functionality with each chapter. Then I explore whenever something new is introduced.

Here is an excerpt (the actual markdown/asciidoc I am writing):

    ()

    Now you got a super basic editor working that is not much better than running `data:text/html, ` in your browser. The content on load is static and any change made is lost when you refresh the page.

    ## 3.3.1 Passing data to a Stimulus controller

    Stimulus has the values API that allows to pass data to the controller from the HTML. Like a lot of things in Rails, Stimulus also follows certain conventions. You can pass values, like strings, integers and hash and array-objects using the following syntax: `data-[controllerName]-[valueName]-value=""`.

    Then in the controller you define it using the `static values` object, like this:

    ```

javascript
    import { Controller } from "@hotwired/stimulus"
    import { basicSetup } from "codemirror"
    import { EditorView } from "@codemirror/view"

    export default class extends Controller {
        static values = { content: String }

    // …
    }


    ```

    ### Static class field in JavaScript

    Wait static values object? You can compare the *static class field* to Ruby's class methods (`self.` or `⁠class << self`). It defines methods that belong to the class itself rather than instances of the class.

    In Ruby:

    ```

javascript
    class Example
    def self.class_method
        "It me!"
    end
    end

    Example.class_method # => "It me!"


    ```

    In JavaScript:

    ```

javascript
    class Example {
    static classMethod() {
        return "It me!"
    }
    }

    Example.classMethod() // "It me!"


    ```


    Both look pretty much alike, right? As an aside: in a later chapter, I will dive deeper into JavaScript classes.


    Stimulus adds some extras to it too; “hey, these properties should be available across all instances of this controller (not just the current instance). Oh… also I want you to automatically create methods to get/set these values.”

    So with the above added `static values = {}` line, you automatically get:

    1. Getters, like ⁠`this.contenValue`;
    2. Setters, like ⁠`this.contenValue = 42`;
    3. Has-methods, like ⁠`this.hasContentVale`.

    (…)

    ### Fat-arrow functions

    But before continuing, there is some interesting, and often confusing, JavaScript tomfoolery going on here that trips up many Ruby developers:

    ```

javascript
    EditorView.updateListener.of((update) => {
    // …
    })


    ```

    What you see here is called a (fat) arrow function `() => {}`. It was introduced in ES6/ES2015. In Ruby you can compare it to the  ⁠`->` (lambda) syntax, but with the added benefit of a lexical `this` binding. Lexical-what? It will automatically keep `this` pointing to where it was defined. Before ES6/ES2015, you had to add `bind(this)`. Let's change the above code to use the post-ES6 syntax to check it out:

    ```

javascript
    // …
    connect() {
        this.editor = new EditorView({
        doc: this.contentValue,
        parent: this.element,
        extensions: [
            basicSetup,
            // EditorView.updateListener.of((update) => {
                        // if (update.docChanged) { this.#update() }
                    // })
            EditorView.updateListener.of(function(update) {
            if (update.docChanged) { this.#update() }
            }.bind(this))
            ]
        })
        }
    // …


    ```

    When making changes in the editor you will still notice the console output with `Update` logs. Let's now remove `bind(this)` and try updating the editor's content again.

    ```

javascript
    // …
        connect() {
        this.editor = new EditorView({
        doc: this.contentValue,
        parent: this.element,
        extensions: [
            basicSetup,
            // EditorView.updateListener.of((update) => {
                        // if (update.docChanged) { this.#update() }
                    // })
            EditorView.updateListener.of(function(update) {
            if (update.docChanged) { this.#update() }
            })
        ]
        })
        }
    // …


    ```

    Errors! If you use a modern editor, you might already see a warning: `#update is declared but its value is never read`.

    Without using `bind(this)` or the (fat) arrow function, `this` would be the CodeMirror editor's context/scope because that is what is calling the function. So `this.#update` fails: CodeMirror doesn't have an `#update` method, only the *editor_controller* does. Compared to Ruby it is akin to losing the `self` reference inside a block.

    ()

It has the hands-on approach of building something real and useful, while learning (new, modern) JavaScript in step by step. I find this works much better than going over JavaScript concepts in the abstract.

I am currently editing the book. Fixing typo's, removing parts and improving bits. While I have never been so unsure about something I have created, I am also really happy with how the book turned out.

Pricing

The tentative pricing looks like this:

  1. Solo Developer ($49) — full Book (PDF/ePub); full code-base access; code snippets
  2. Professional ($69) — everything in Solo Developer; markdown Editor + Preview Variant; railsdesigners.com community access (launching summer 2025; $49 value!)
  3. Team ($149) — everything in Professional; share with 5 developers; 5 community seats

If you have been a Rails developer who has cursed at JavaScript, this book might be for you. If you've been a Rails developer avoiding JavaScript at all costs, this book is what you need. For Rails developers who've wished JavaScript would just disappear, this book might change your mind.

Tentative publishing date for JavaScript for Rails Developers is April 2025 (yep, still leaves some room for interpretation). If you want to get notified when you can get your hands on it, subscribe to the newsletter (I might sent a discount code when launching. Who knows!).

Check out JavaScript for Rails Developers.