Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Applied Rails: Gems I Use

DZone's Guide to

Applied Rails: Gems I Use

We take a look at some Ruby gems made used in a recent project by the author. Find out what they were and if they can help you in your next Rails project. Code included!

· Web Dev Zone
Free Resource

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

In this article, I discuss key gems that I have used in my Rails application. For each gem, I state what it is used for, a brief description of how I used it, and the code snippet(s) pertaining to my use case.

Devise

I use the devise gem for user authentication. It has 10 modules: Database Authenticatable, Omniauthable, Confirmable, Recoverable, Registerable, Rememberable, Trackable, Timeoutable, Validatable, and Lockable. The cool thing is you can use only the modules that you want.

Cancan

I use the cancan gem for user authorization. All I had to do was run a simple command and override the initialize method in the User class.

In the following code snippet, users in role commercial_officer are allowed to execute the claimsForCheckting action in the ExpensesClaim class.

if user.has_role? :commercial_officer
can :claimsForChecking, ExpensesClaim
end


A caveat: cancan is no longer supported, and if you are starting afresh, you have to use cancancan.

role_model

I use the role_model gem to provide role-based access. The cool thing about it is that you can control the roles by just altering a number in the database table. Let's say you have six roles: guest, executive, manager, sales, CXO, admin. Since it works on bit mask, each of the role gets the value of 2n-1 where n ranges from 0 to the total number of roles. In the six roles I mentioned, the guest gets 1 and the admin gets 32. So if a CXO also has a sales role, give her record's roles_mask column a value of 8 + 16 = 24 in the database.

In the following code snippet, a user is given their role at the time of user creation. The set_roles_mask method takes the email used for registration, checks if the email is present in the Employees master table and if yes, sets the Users table roles_mask to the value in the Employees table. If the user is not an employee the user is given a roles_mask of 1 (guest).

include RoleModel
​
roles_attribute :roles_mask
roles :guest, :executive, :manager, :sales, :cxo, :admin
​
before_create :set_roles_mask
​
def set_roles_mask
emp = Employee.find_by(email: self.email)
if emp == nil
self.roles_mask = 1
else
self.roles_mask = emp.roles_mask
end
end


The checking code in the UI layer looks like the following code; here only some users (either in the CXO role or those in the Bulk_email_team) are given access to a particular menu item in the navigation bar.

<% if current_user.has_role? :cxo or
Bulk_email_team.include? current_user.email %>
<li class="dropdown ">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">Bulk Mail</a>
<ul class="dropdown-menu to-right">
<li><a href="/bulk_mails/new">To Customers</a></li>
<li><a href="/bulk_mails/toEmployees">To Employees</a></li>
<li><a href="/bulk_mails">View All</a></li>
</ul>
</li>
<% end %>


With the combination of devise, cancan, and role_model you will have a robust production-ready security layer for your application, all with a few lines of code. Java developers who use Spring frameworks will be surprised at the level of functionality that we achieve with a few lines of code in Rails. This, despite Spring Boot.

Prawn

I use the prawn gem for generating pdf documents. It provides most of the features I require. For bulleted text with proper alignment, I had to write a small function that prints asterisks in the first column. See an earlier blog post of mine[1] post for more details.

prawn-table

I use the prawn-table gem for displaying content in tables inside pdf documents.

In the following code snippet, I check whether there is enough space on the page to render the table. If not, I display the table on a new page.

require 'prawn/table'
​
def instruments_table_data
@instruments_table_data = [["Equipment", "Qty", "Scope"]]
@offers_instruments.each do |instr|
@instruments_table_data << [instr['name'], instr['qty'], instr['scope']]
end
​
return @instruments_table_data
end
​
t = make_table instruments_table_data, header: true
if cursor < 100 + t.height
start_new_page
move_down 50
end
​
move_down 15
text "<u>SCOPE OF INSTRUMENTS</u>", :style => :bold, :inline_format => true
​
move_down 10
text "Instruments scope is as given below:"
move_down 15
indent(40) {t.draw}

Fiscali

I use the fiscali gem for date calculations based on the fiscal year.

In the following code snippet, first the time zone is set to India. If the user did not enter a starting date, the beginning of the Indian financial year (1st April) is taken. If the user did not enter an end date, today's date is taken as the end date. Using the two dates, records created in the table between the start date and end date are fetched.

config/initializers/fiscali.rb

Date.fiscal_zone = :india
Time.fiscal_zone = :india
DateTime.fiscal_zone = :india


# From date is start of financial year if not input
​
if params[:from_date] == ''
from_date = DateTime.now.beginning_of_day.beginning_of_financial_year.to_date
else
from_date = params[:from_date]
end
​
# To date is today if not input
if params[:to_date] == ''
to_date = Date.today.to_date
else
to_date = params[:to_date]
end
​
@te_records = TravelExpense.where(:expense_code => @expense_codes, created_at: from_date..to_date)


date_validator

Data entered by users in the browser screens (HTML forms) is validated in the model classes. the date_validator gem eases the validation of date rules.

In the following code snippet, I validate whether a travel record should be in the past or today. First I check that there is an end date, it is after or on the start date and it is today or before. Nice trick here is, there is no need to validate that the start date is present and is in the past or on today.

class Travel < ActiveRecord::Base
belongs_to :expenses_claim
has_many :travel_expenses
accepts_nested_attributes_for :travel_expenses, allow_destroy: true
​
validates :end_date, presence: true, date: { :after_or_equal_to => :start_date, message: "must be after or equal to start date."}
validates :end_date, presence: true, date: { :before_or_equal_to => Proc.new { Time.now }, message: "must be today #{(Date.today).to_s} or before." }, on: :create
end


The Rails data validation approach is explained as: "Nothing to do with our application comes out of the database or gets stored in the database that doesn't get first go through the model. This makes models an ideal place to put validations: it doesn't matter whether the data comes from a form or from some programmatic manipulation in our application. If a model checks it before writing to the database, then the database will be protected from bad data."[2]

wice_grid

I use the wice_grid gem to filter tabular data. You can also sort the data.

The following code snippet displays Offers in a wice grid and allows user to filter on the customer name. It even pulls the associated records from the customer and employee tables. The simplicity of Rails is evident in the link_to 'view or edit' the offer entity.

# controller code
@offers_grid = initialize_grid(Offer.where(employee_id: myself.id), include: [:customer, :employee])
​
# view code
<h1>Listing Offers</h1>
<%= grid(@offers_grid) do |g|
g.column name: 'Offer Id', attribute: 'offer_id', filter: false
​
if @cmd == true
g.column name: 'Sent By', attribute: 'name', assoc: :employee, custom_filter: @offer_senders
end
g.column name: 'Customer', attribute: 'name', assoc: :customer, custom_filter: :auto
g.column name: 'Date', attribute: 'updated_at', filter: false
g.column name: 'Price (INR)', attribute: 'charges', filter: false
g.column do |c|
link_to 'View / Edit', c
end
end -%>


Paperclip

I use the paperclip gem for attaching uploaded files to a particular entity. The use cases I have tackled using this gem are: 1) Allow the user to select from a pre-loaded set of documents. 2) Allow the user to upload any random file.

Code snippets for these use cases are given below:

# Offer model code
has_and_belongs_to_many :offer_attachments, join_table: "oa_join"
has_many :offer_random_attachments, :dependent => :destroy
​
class OfferAttachment < ActiveRecord::Base
has_and_belongs_to_many :offers, join_table: "oa_join"
end
​
class OfferRandomAttachment < ActiveRecord::Base
belongs_to :offer
has_attached_file :random_attachment, :path => ":rails_root/storage/docs/offers/random_attachments/:id/:filename", :url => "/storage/docs/offes/random_attachments/:id/:filename"
​
do_not_validate_attachment_file_type :random_attachment
end
​
# View code
# first use case
<div class="field">
<%= f.label "Attachment to be sent" %><br>
<%= f.collection_check_boxes :offer_attachment_ids, OfferAttachment.all, :id, :name do |b| %>
<div class="collection-check-box">
<%= b.check_box %>
<%= b.label %>
</div>
<% end %>
</div>
​
​
# second use case
<div class="control-group">
<%= f.label :offer_random_attachments, :class => 'control-label' %>
<div class="controls">
<%= file_field_tag "random_attachments[]", type: :file, multiple: true %>
</div>
</div>


Kaminari

I use the Kaminari gem when I have to display paginated data.

The following code snippet shows employee records in a paginated HTML table.

def index
@paginatable_employees = Kaminari.paginate_array(Employee.all).page(params[:page]).per(10)
end
​
<table>
<thead>
<tr>
<th>Emp No</th>
<th>Name</th>
<th>Qualifications</th>
<th>Joining Date</th>
<th>Division</th>
<th>Department</th>
<th>Designation</th>
<th>email</th>
<th>Phone 1</th>
<th>Phone 2</th>
<th>Manager Emp No</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<%= paginate @paginatable_employees %>
<% @paginatable_employees.each do |emp| %>
<tr>
<td><%= emp.emp_no %></td>
<td><%= emp.name %></td>
<td><%= emp.qualifications %></td>
<td><%= emp.joining_date %></td>
<td><%= emp.division %></td>
<td><%= emp.department %></td>
<td><%= emp.designation %></td>
<td><%= emp.email %></td>
<td><%= emp.phone_1 %></td>
<td><%= emp.phone_2 %></td>
<td><%= emp.manager_emp_no %></td>
<td><%= link_to 'Show', emp %></td>
<td><%= link_to 'Edit', edit_employee_path(emp) %></td>
<td><%= link_to 'Destroy', emp, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>


axlsx_rails

I use the axlsx_rails gem to generate Microsoft Excel files. The following code snippet generates a xlsx file of the customer, their location, and contacts at each location. The header row has cells with blue filling.

def allContacts
@locations_hash = {}
@contacts_name_hash = {}
@contacts_email_hash = {}
​
Location.all.each do |location|
@locations_hash[location.id] = location.name
end
​
Contact.all.each do |contact|
@contacts_name_hash[contact.id] = contact.name
@contacts_email_hash[contact.id] = contact.email_1
end
​
@contacts = []
Customer.all.each do |customer|
@contacts << [customer.name, @locations_hash[customer.location_id], @contacts_name_hash[customer.contact_id], @contacts_email_hash[customer.contact_id]]
end
​
render xlsx: 'allContacts', locals: {xlsx_use_shared_strings: true}, filename: "allContacts.xlsx", disposition: 'inline'
end
​
​
wb = xlsx_package.workbook
wrap = wb.styles.add_style alignment: {wrap_text: true}
wb.styles do |s|
color_cell = s.add_style :bg_color => "0000FF", :fg_color => "FF", :sz => 12, :alignment => { :horizontal=> :center }
date_cell = s.add_style(format_code: "dd-mm-yyyy")
s.add_style alignment: {wrap_text: true}
wb.add_worksheet(name: "All Contacts") do |sheet|
# sheet.add_row ["#{@month_name}"]
sheet.add_row ['Customer', 'Location', 'Contact', 'Email'], style: [color_cell, color_cell, color_cell, color_cell]
@contacts.each do |contact|
sheet.add_row [contact[0], contact[1], contact[2], contact[3]]
end
end
end


custom_error_message

I use the custom_error_message gem for customizing my error message not to have the attribute name prefixed.

This plugin uses the caret (^) to omit the name of the attribute from error messages. Here's an example:

validates :days, numericality: {only_integer: true, greater_than: 0, message: "^QTY / MONTH(S) must be a positive number."}


select2-rails

I use the select2-rails gem for selecting entries in ajax style from a drop-down. The following code shows how users select employee email ids from a select drop down and get a shortened list with each letter they enter.

<script>
$(document).ready(function() {
$("select#ema").select2();
});
</script>
​
<br>
<div class="field" id="recipients_selection">
<%= f.label "Or send to select emails from employee database" %><br>
<%= select_tag :bulk_mail_recipients, options_from_collection_for_select(@employees, :id, :email), id: :ema, :multiple => :multiple, :multiple => true, :style => "width:800px;", data: {placeholder: "Choose an email"} %>
</div>


The extraordinary simplicity of Ruby and the amazing functionality offered by its gems make working with Ruby on Rails a pleasure. To quote David Hansson, the creator of Ruby on Rails[3]:

...two basic tenets of Rails appeal in 2017: 1) We have a unique ideological foundation that’s still controversial today and offers the same benefits against the mainstream choices as it did 13 years ago. 2) We have a pragmatic, full-stack answer that could be formulated based on that ideology that still offers amazing productivity from the second you run the rails new command.
Oh, and on top of all that, I’ve saved the cherry for last. You get to use Ruby, which, even in a world that has rediscovered the benefits of functional programming and immutability, remains the most extraordinarily beautiful and luxurious language I’ve yet to encounter. Just look at some code. I dare you not to fall in love.

References:

[1] http://mh-journal.blogspot.in/2017/03/applied-rails-bulleted-text-with-prawn.html

[2] Agile Web Development with Rails4 by Sam Ruby, Dave Thomas, David Heinemeier Hansson. 2013, The Pragmatic Programmers, LLC.

[3] https://www.quora.com/What-makes-Rails-a-framework-worth-learning-in-2017

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:
gems ,web dev ,ruby on rails ,web application development

Published at DZone with permission of Mahboob Hussain, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}