DEV Community

Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com

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! 🛀

Top comments (1)

Collapse
 
feetpis profile image
feetpis

Thanks