Currency Input Masking with Cleave.js and Money gem in Ruby On Rails
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
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