ROR 101: Highlights of 12 months using Rails
A little over one year ago I jumped ship to a new role at a startup company which required me to get familiar with a new tech-stack. The biggest hurdle by-far was coming to grips with Ruby and Rails, especially given that I had limited experience with anything similar.
The purpose of this post, however, is not to recount each hurdle of the last 12 months but rather to list off a few of my favourite things about Ruby and/or Rails (so far).
Disclaimer: For the purpose of this blog post, I am combining Ruby & Rails as the same thing without differentiating whether a feature belongs to one or the other. (I imagine the enthusiasts will now sharpen their pitchforks đżđ„)
1. Date & Time syntax
I think this feature is very deserving of the top spot in this list. Take the scenario you need to set some kind of expiration timestamp (say 10 minutes) on an object in your application. My Java foundation has got me thinking along the lines of:
get the current time
,convert 10 minutes into milliseconds
,find a method on the Date/Time object that allows me to add some milliseconds
.
The following Rails syntax is a lot nicer:
expiration = Time.now + 10.minutes # Wow!
# But wait, there's more!
expiration_better = 10.minutes.from_now # đ±
The syntax is extremely flexible. Feel free to go absolutely nuts
2.hours.ago
10.years.from_now
3.months.ago
financial_quarter_started = 2.weeks.ago.at_beginning_of_day
team_lunch = 5.days.from_now.at_noon
international_meeting = 3.hours.from.now.in_time_zone("London")
=> Tue, 28 Dec 2021 01:38:45.299432000 GMT +00:00 # Perhaps not then...
2. Syntax abbreviations
Theyâre a major headache when youâre a Ruby n00b
and nothing makes sense, but quite pleasant once youâre comfortable and very common-place in the Ruby community.
Implicit Returns
Who needs that pesky return
keyword anyway?
The value of the last line of code in a block always gets returned automatically. Prefixing return
is optional.
Most of the time I donât use it. But proceed with caution! Itâs still necessary if you wish to return from any line other than the last, E.g.
def lottery_won?
return false unless lottery_ticket_purchased? # <--- explicit return
ticket.has_winning_numbers? # <--- implicit return
end
Parenthesis Who?
If your method call does not specify any arguments, then you donât need to specify any parenthesis.
speakers.set_volume(100) # đ
speakers.increase_volume() # đ
speakers.increase_volume # đ
NB: Even if you are specifying arguments, parenthesis are still optional. Proceed with caution as it can harm readability, especially with multiple argumentsâŠ
speakers.set_volume 100 # Valid (albeit controversial) syntax...
3. Safe Navigation
When one chooses to embrace a less-strictly typed language like Ruby, youâd best get comfortable with nil
. Youâre going to encounter it a lot.
Sometimes the natural reaction to this danger is to write abundently cautious code like:
if currently_logged_in.present? &&
currently_logged_in.user.present? &&
currently_logged_in.user.details.present? &&
currently_logged_in.user.details.address.present?
postcode = currently_logged_in.user.details.address.postcode
end
The above should avoid an exception being raised if one of the prior method calls returns nil
(NoMethodError: undefined method for nil:NilClass
), but the postcode itself may still be nil.
The safe-navigation operator allows us to chain these method calls together safely, without explicitly checking each method call to be non-nil. If it encounters a nil value along the chain, execution of the statement does not proceed and nil
is returned.
postcode = currently_logged_in&.user&.details&.address&.postcode
If the postcode exists, we get the value. If any of the user, details, address or postcode do not exist we get nil
without an error being raised.
As always, with great power comes great responsibility. Only use this when beneficial; Use in situations where a nil
return is not possible is a code smell đ„Ž.
4. Natural Language Syntax (âsyntactic sugarâ đ )
Despite our best efforts, sometimes computers and humans just donât think the same way. Often the fastest path to solving a problem using code is to think like a computer, but this is easier said than done. Rails makes some strides to allow for more human-like language in code. One such example is shown below:
# This, to me, requires the developer to think like a computer
if oven.include?("roast_vegetables") && oven.include?("roast_chicken")
puts "Dinner is nearly ready!"
end
# Rails provides some mechanisms to achieve the same functionality
# in more natural human language
if "roast_vegetables".in?(oven) && "roast_chicken".in?(oven)
puts "Dinner is nearly ready!
end
Sometimes (context-dependent) one way is simply more readable than the other; Rails gives you the freedom of choice đ€
This difference in readability also extends beyond this individual line of code. Within the context of your entire algorithm, should the developer be more focussed on the fact that the oven contains food, or the fact that food is in the oven?
The same freedoms of expression are offered in English (and many other spoken languages), e.g.
Some maniac in a fast car passed me
Some maniac passed me in a fast car
Whatâs more important for the reader to understand the rest of your story / algorithm?
- That the maniac was in a fast car, or
- That the maniac passed you ?
On that philiosophical note, stay tuned for Part 2 đ