DEV Community

Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com

1

Sanitize your strings in JavaScript like a Rails developer

This article, originally published on Rails Designer, is extracted from the book JavaScript for Rails Developers. Get your copy today. ✌️


Ruby (and Rails) are known for great Developer Experience. Not in the least because of the many little helpers available. JavaScript doesn't have most of these unfortunately, but luckily, as a developer, many are easily replicated. Let's look at the API I am looking for:

class Editor {
  async #update(content) {
    const sanitizedContent = sanitize(content, { trimTrailingWhitespace: true })

    const response = await fetch(
      this.updateUrlValue,
      {
        // …

        body: JSON.stringify({
          content: sanitizedContent
        })
      }
    )

    // …
  }
}
Enter fullscreen mode Exit fullscreen mode

sanitize(content, { trimTrailingWhitespace: true }) is what I want to implement. You could extend the options with whatever you need:

sanitize(content, {
  trimTrailingWhitespace: true,
  trimLeadingWhitespace: true,
  maxConsecutiveNewlines: 2,
  maxConsecutiveSpaces: 1
  // … etc.
})
Enter fullscreen mode Exit fullscreen mode

The code for it is quite simple really! Let's create it at: app/javascript/helpers/textSanitizers.js.

// app/javascript/helpers/textSanitizers.js
class TextSanitizers {
}

export const sanitize = (content, options = {}) => {
  return new TextSanitizers(content).process(options)
}
Enter fullscreen mode Exit fullscreen mode

Above shows that the content is passed as an argument and then very likely set as an instance variable. It also needs a process method.

class TextSanitizers {
+  constructor(content) {
+    this.content = content
+  }

+  process(options = {})
+    return this.content.replace(/[ \t]+$/gm, "")
+  }
}
Enter fullscreen mode Exit fullscreen mode

Above is all that is needed to sanitize trailing white-spaces from the content. But I want this class to be responsible for many more sanitizations! Let's set it up to be ready for that.

class TextSanitizers {
+  availableCleaners = [
+    "trimTrailingWhitespace"
+  ]

  constructor(content) {
    this.content = content
  }

  process(options = {}) {
-   return this.content.replace(/[ \t]+$/gm, "")
+   return Object.entries(options).reduce((result, [option, value]) => {
+     return this.availableCleaners.includes(option) ? this[option](result, value) : result
+   }, this.content)
  }

  // private

+  trimTrailingWhitespace(text) {
+    return text.replace(/[ \t]+$/gm, "")
+  }
}
Enter fullscreen mode Exit fullscreen mode

The process method determines which cleaning operations need to run. When no options are passed, it defaults to an empty object ({}). Then inside the method Object.entries converts the options into an array of key-value pairs: {trimTrailingWhitespace: true} would become: [["trimTrailingWhitespace", true]]. If this seems like a lot, the book JavaScript for Rails Developers has you covered (more sanitization options included)! 😊

Okay, with that done, it is now easy to extend TextSanitizers class with more options:

class TextSanitizers {
  availableCleaners = [
    "trimTrailingWhitespace",
+   "trimLeadingWhitespace",
+   "maxConsecutiveNewlines",
+   "maxConsecutiveSpaces"
  ]

  constructor(content) {
    this.content = content
  }

  process(options = {}) {
    return Object.entries(options).reduce((result, [option, value]) => {
      return this.availableCleaners.includes(option) ? this[option](result, value) : result
    }, this.content)
  }

  // private

  trimTrailingWhitespace(text) {
    return text.replace(/[ \t]+$/gm, "")
  }

+ trimLeadingWhitespace(text) {
+   return text.replace(/^[ \t]+/gm, "")
+ }

+ maxConsecutiveNewlines(text, maxNewlines) {
+   return text.replace(/\n{3,}/g, "\n".repeat(maxNewlines))
+ }

+ maxConsecutiveSpaces(text, maxSpaces) {
+   return text.replace(/ {2,}/g, " ".repeat(maxSpaces))
+ }
}
Enter fullscreen mode Exit fullscreen mode

For every new sanitization option, you add it to availableCleaners and then add the method with a matching name.

And that is how you added a little bit of Rails into JavaScript. Super clean! 🛀

Postmark Image

"Please fix this..."

Focus on creating stellar experiences without email headaches. Postmark's reliable API and detailed analytics make your transactional emails as polished as your product.

Start free

Top comments (1)

Collapse
 
feetpis profile image
feetpis

Thanks

Sentry image

How we debugged a broken checkout flow in Flask + React

Dropped carts = lost revenue. See how Sentry tracing can catch a full-stack bug in a Flask + React checkout flow—before it can become a support fire drill.

Read more →

Join the Runner H "AI Agent Prompting" Challenge: $10,000 in Prizes for 20 Winners!

Runner H is the AI agent you can delegate all your boring and repetitive tasks to - an autonomous agent that can use any tools you give it and complete full tasks from a single prompt.

Check out the challenge

DEV is bringing live events to the community. Dismiss if you're not interested. ❤️