TIL

#ruby, #rails, #OOP, #javascript, #ember

1/26/17

closed

please visit my new blog @ https://johnromani90.github.io/

1/25/17

Setting up Polymorphism in Ruby on Rails

Polymorphism can take a little longer to understand conceptually than other topics in OO. It is an abstraction which takes a little more effort for the developer to implement, but makes extending easier later on.
In this example I have three models that I want to add an attachment too: Patient, Prescriber, Order. Each attachment requires the same attributes and instead of adding a new attachment column on each model I am electing to create a new model called "AttachmentObject" and make it polymorphic. I am using the paperclip gem with S3 for attachment upload.
class AddAttachmentPolyObject < ActiveRecord::Migration
  def change
    create_table :attachment_objects do |t|
      t.string :title, null: false
      t.references :attachable, polymorphic: true, index: true, null: false
      t.attachment :attachment, null: false

      t.timestamps
    end
  end
end
class AttachmentObject < ActiveRecord::Base
 belongs_to :attachable, polymorphic: true
 validates :title, :attachable_id, :attachable_type, presence: true
end

then for my relationships to my "attachable" models (Patient, Prescriber, Order).
class Patient < ActiveRecord::Base
 has_many :attachment_objects, as: :attachable
end

class Prescriber < ActiveRecord::Base has_many :attachment_objects, as: :attachable end
class Order < ActiveRecord::Base has_many :attachment_objects, as: :attachable end

It is not necessary to name your "has_many" relationship with a name that uses "able" as a suffix, but you will see that it is a popular amongst rails devs and you should use it as a convention when possible. Now comes the fun parts. With my AttachmentObject I can now use rails helpers to find its related attachable parent. Active Record does this by looking up the 'attachable_type' (which points to either Patient, Prescriber, or Order table) and 'attachable_id' which points to a row on the table. for example:
#explicitly
order = Order.create( valid_attributes )
order_attachment = AttachmentObject.create(title: "phish", attachable_type: "order", attachable_id: order.id) 

#or implicitly
order_attachment = AttachmentObject.create(title: "phish", attachable: order) 
I can then do
phish = AttachmentObject.find_by_title("phish") 
phish.attachable #returns the related order_attachment

12/20/16

Cacheing Ruby With APICache gem

If you're running a rails app then chances are you're playing with multiple apis. This week I found myself working with the robust JIRA api so that I could return worklogs and do something meaningful (and more user friendly) for a client.

You could easily write your own cacheing class using timestamps and urls as keys for the queries, but I really like this gem (APICache by Martyn Loughran) because it has a couple nice features out of the box like :period, :valid, and :cache timeout options. The gem is also simple; it consists of two main classes, Api and Cache, which are both under 100 lines of code. The other few classes are wrappers that help you configure your 'mem-cache' store which we'll get into later.

First download the api_cache gem Then add 'config/initializers/api_cache.rb' And add this code
if Rails.env.production?
  APICache.store = APICache::DalliStore.new
end
This will set up a dalli store (which is a pure Ruby client for accessing memcached servers) when you are in production and will use memory to cache data when running locally. This allows you to boot up your app and play around without having to run a second server every time. When you get ready to deploy to production read the Dalli docs to learn more about how the process works.

In my example we are retrieving large data sets. Returning the JSON and refreshing the page took around 15 seconds, no bueno. In order to cache all our request to the Jira server we used our own wrapper class that defined a 'get' method. This class inherited from our jira::client so that way all gets would go through our logic. If we want to implement a new http request (like put, patch, post) we can follow the same pattern. We then wrapped our get method with APIcache logic
  def get( url )
    APICache.get(url, :cache => cache_timeout, :timeout => 15) do
      super(url)
    end
  end

  def cache_timeout
    skip_cache ? 1 : 3000
  end
The skip_cache is an attr_accessor which we pass in when we instantiate this class on specific situations. Besides that we use our default cacheing timeout setting which is 50 mins.
The Api Cache gem also allows these configurations 
{
  :cache => 600,    # 10 minutes  After this time fetch new data
  :valid => 86400,  # 1 day       Maximum time to use old data
                    #             :forever is a valid option
  :period => 60,    # 1 minute    Maximum frequency to call API
  :timeout => 5     # 5 seconds   API response timeout
  :fail =>          # Value returned instead of exception on failure
}
Check out api_cache gem for the official docs.