Ruby, Ruby on Rails

Rake:notes FTW!

I just found a really cool feature in Rails, can’t believe I didn’t know about it before.

Apparently you can add comments like this in your Rails app

    def uncompleted_method
      # TODO complete this method
    end

And if you run `rake:notes` in your terminal, it will list down all the TODO comments like so

rake-notes-todo

You can also use `optimize` and `fixme` with rake:notes.

    def need_to_fix
      # FIXME fix this quickly
    end

    def optimize_this
      # OPTIMIZE this is way too slow
    end

Running rake:notes will give you:

rake-notes-todo-2

This is a really useful technique to maintain a running todo list/ reminder system in your Rails app

Ruby, Ruby on Rails

Around callbacks in ActiveRecord

Callbacks are methods that get called at certain moments of an object’s life cycle. If you’re wondering why the above sentence sounds so coherent, its because I stole it verbatim from the Rails Guides.

So most people are pretty familiar with before and after callbacks. before_save and after_update pretty much explains itself. There is another type of callback though, called around.

What in the world does it do?

What it does is it allows you to run code both before and after an operation. So an example will be like this:


class Facility < ActiveRecord::Base
  
  around_save :method_around_save
  
  private 
    def method_around_save
    # you can do stuff here
      yield <---- the save happens here
    # you can continue doing stuff here as well
    end
end

So why is this useful? Whats the difference between this and doing 2 separate before_save and after_save callbacks?

In my opinion, the around callback could be useful if you want all your database transactions in your callbacks to be atomic.

Or if you want whatever you’re doing in after_save depends on what happens before_save

Lets have a concrete example, based on a make-believe real life scenario

Say you have a Building model, which has a number of facilities under it.
Every time a building is created, you want to create a set number of hardcoded facilities.

  class Building < ActiveRecord::Base

  has_many :facilities

  after_create :create_facilities
 
  def create_facilities
    #Do facility creation here
  end
end

So each facility, will have a number of sub-facilities (Just like how badminton courts have Court A, Court B, etc). These sub-facilities are also created when the a facility is created

class Facility < ActiveRecord::Base
  after_create :create_subfacilities

  def create_subfacilities
    # sub-facilities will be created here.
  end
end

So this looks ok, I guess. But what if someone updates the facility? Maybe the user made a mistake and set the number of sub-facilities to 2 when actually there were 3 sub-facilities?

One way is to do a check before the update happens to see if the number of sub-facilities has changed (before_update) and then update the sub-facilities after the facility has been updated (after_update)

Something like this maybe?

class Facility < ActiveRecord::Base
  after_create :create_subfacilities
  before_update :check_for_subfacility_change
  after_update :sync_subfacility

  def check_for_subfacility_change
    @sync? = true if #subfacility has been changed
  end

  def sync_subfacility
    #update number of sub-facilities based on the value of @sync?
  end

  def create_subfacilities
    # sub-facilities will be created here.
  end
end

I’m just guessing here, but perhaps this could be a bit difficult to read after a few months and when the class gets bigger. So it could be easier if we did the whole thing in one around_update callback.

Perhaps something like this

class Facility < ActiveRecord::Base
  after_create :create_subfacilities
  around_update :sync_subfacility

  def sync_subfacility
   sync? = true if #subfacility has been changed
   yield
   #update sub-facilities if sync? is true
  end

  def create_subfacilities
    # sub-facilities will be created here.
  end
end

So there you go, hopefully that made sense. If you can think of a better way please reply in the comments

Ruby, Ruby on Rails

Group_by – The Definitive Guide

I’ve been working on a Rails API that sends JSON goodness to a mobile app. Its the first major app I’ve done that involves me doing the API side.

(I’ve learned that designing APIS is NOT as easy as I thought. Especially when other people have to use them.)

One of the things I had to do was to send a json load of bookings grouped by the
type of facility that was booked.

I admit I don’t religiously read the API docs for any programming language I work on, so I was embarrassingly excited when I found the group_by method

Lets read the official explaination

Collect an enumerable into sets, grouped by the result of a block. Useful, for example, for grouping records by date.

So lets break it down

1) It takes an enumerable, and like all enumerables it iterates through its contents

2) It then groups everything it iterates based on the results of the block

So imagine I had an ActiveRecordRelation with 3 booking objects

@bookings = [
  # 1,
    :facility_name => "BBQ",
    :booking_date => Wed, 30 Nov 2016>,
  # 3,
    :facility_name => "Sauna",
    :booking_date => Wed, 23 Nov 2016>,
  # 2,
    :facility_name => "BBQ",
    :booking_date => Thu, 24 Nov 2016>
]

So what if I want to group these bookings by facility name? I would do something like this.

   grouped_bookings = @bookings.group_by{ |b| b.facilty_name }

grouped_booking will return

@bookings = 
  {
    "BBQ" => [
    # 1,
      :facility_name => "BBQ",
      :booking_date => Wed, 30 Nov 2016>,
    # 2,
      :facility_name => "BBQ",
      :booking_date => Thu, 24 Nov 2016>
  ],
    "Sauna" => [
      # 3,
      :facility_name => "Sauna",
      :booking_date => Wed, 23 Nov 2016>,
    ]
  }

Ruby, Ruby on Rails

Wherefore Art Thou Method?

I’ve been learning me some iOS lately, the most striking feature is the IDE, coming from Ruby and my trusty text editor, IDEs were kind of a shock. It kinda felt like someone always looking over my shoulder. Constantly pointing out what I did wrong, sometimes while in the middle of typing.

After a while I grew quite fond of Xcode, I like how you could option-click a method and see what it was all about, or at least where it was defined.

Ruby doesn’t have anything like that, at least not in the text editor. And what with its plethora of gems, its kinda hard sometimes to find where a method comes from.

I encountered a something like this earlier this week when I was trying to understand some code that was written by another developer.

The app was using  Clearance, which is a pretty nifty authentication gem. So obviously an authentication gem would need a method called “authenticate” right?  I got confused though when I saw it was used like this:

 @user = authenticate(params)

However, when I tried to use it like this:

 User.authenticate(params)

I got a

ArgumentError: wrong number of arguments (given 1, expected 2)

That was weird, looking into the Clearance gem source code, I found this in authentication.rb :

  def authenticate(params)
        Clearance.configuration.user_model.authenticate(
          params[:session][:email], params[:session][:password]
        )
      end

So obviously it accepts one argument right? Maybe another authenticate method was defined somewhere else. After hours of intense research and/or googling around for a bit, I found a method in Ruby called source_location

What this does is it tells you where a method is defined. So running this line in the rails console :

 User.method(:authenticate).source_location

will return this line:

 ["/Users/farisroslan/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0/gems/clearance-1.10.1/lib/clearance/user.rb", 19]

So it turns that there was another authenticate method defined in user.rb!

 def authenticate(email, password)
        if user = find_by_normalized_email(email)
          if password.present? && user.authenticated?(password)
            return user
          end
        end
      end

So now modifying my authenticate method for User so it looks like this:

 User.authenticate(session_params[:email],session_params[:password])

It worked well.

Now in hindsight, perhaps searching “authenticate” in the Clearance repo would have probably be quicker.Still, it should be useful if the other method is in another gem or library.