Relying on the user's input is a crucial part of building a robust application. That's why I try to apply strong validations on the incoming data on forms or otherwise. One of the important input which needs to be captured very precisely is –– Amount. Thou Rails ecosystem has an amazing gem called Money to work with the amount. However, I wanted an equally elegant experience while dealing with amount related inputs for my users on the front-end.

After playing around with a couple of Javascript libraries –– I ended up picking Cleave.js. I configured it to work in conjunction with Money gem. Here is the end result

Input masking with Cleave.js & Money gem

Here's how to achieve this experience

First, let's get our dependencies added in our project

gem 'money-rails'
yarn add cleave.js

rails g money_rails:initializer

Then once we configure config/initializers/money.rb based on our requirements, we will move to set up the Javascript part.

In our app/views/layouts/application.html.slim we will define a global object in respect to Cleave.js configuration in the head tag. It should look something like this

/ Global config for input masking in Cleave library
javascript:
    window.__AMOUNT_INPUT_MASK__ = {
    prefix: "#{raw Money.default_currency.symbol} ",
    numeral: true,
    numeralThousandsGroupStyle: 'lakh',
    rawValueTrimPrefix: true
};

tweak numeralThousandsGroupStyle config based on your requirement

In our app/assets/javascripts/application.js we will write a small piece of JS snippet which will attach input masking as per our defined Money config to any input which has a class currency-input-mask

document.addEventListener("DOMContentLoaded", function(event) {
    // Input Mask
    document.querySelectorAll("input.currency-input-mask").forEach(function(el) {
        new Cleave(el, window.__AMOUNT_INPUT_MASK__);
    });
});

Now, any input field with above mentioned class will allow our users to enter values in a much more controlled fashion –– reducing the chance of human errors with more refined data.

There is just one last step which needs to be taken care before we move on. Because our input value now holds other data like currency & commas, which is what we are going to receive in parameters in our controller when the user submits the form.

To address this part, we will need to clean up the value before we can pass it on to our Model. Let's create a helper file in app/helpers called input_helper.rb and define a method to shave off wanted characters from the value

module InputHelper 
    def strip_inputmask(amount)
      amount.is_a?(String) ? amount.gsub(/#{Money.default_currency.symbol}|,/, '').strip.to_i : amount
    end
end

Lastly, In our controller, we will include this helper and use the method we just defined

class ApplicationController 
 include InputHelper


 ...
 model.amount = strip_amount(params[:model][:amount])
 ...
end

I believe this little care to our application has a drastic impact overall to the entire project and brings peace amongst all the stakeholders.

? Do let me know your thoughts or feedback if this was valuable in any way