Proper Counter Cache Migrations in Rails

A lot of people are doing a lot of heavy lifting in their database migrations when deploying. That might work well for people when their data set is ~1 000 records, but when you are working with 500 000+ records, that’s just not feasible.

There’s a lot of bad advice in terms of counter_cache and Rails so I wanted to make sure this one got some extra visibility.

http://ryan.mcgeary.org/2016/02/05/proper-counter-cache-migrations-in-rails/

Migrate to Ruby on Rails 5.x using RocketPants

At Sparta, we’ve been using a Gem called RocketPants since day 1 (roughly three years now) to easier maintain, version and develop our internal API. The Gem has since then lost a decent chunk of its community and it looks like less people are using it.

I would guess that since the Rails API Gem was merged into Ruby on Rails with the 5.0 release, the need for a Gem such as RocketPants shrunk.

Anyway, I’ve been doing some work on making the Gem support Ruby on Rails 5.0 and 5.1, and it seems like some other people were stuck on the 4.x branch of Rails because they were unable to upgrade.

RocketPants with support for Ruby on Rails 5.0 (and 5.1) : https://github.com/Sutto/rocket_pants/pull/143/files

I’ve been using it myself on Ruby on Rails 5.0 for the last year without any issues, so the whole Gem feels fairly stable.

This is not a permanent solution as the Gem has lost a big part of its community and we want to avoid getting stuck on a Gem that will not be developed any further, I will follow up in another post on how we at Sparta will migrate to another solution. Most likely we will be using the built in Rails API.

In addition, my colleague Yi got the rocketpants-rpm (provides support for making RocketPants::Base work with RPM) gem up and running for Rails 5 as well. It’s available under our Github organisation here.

 

Inspect SQL queries generated by Ruby on Rails

I’m currently working on a rewrite of XCStorm, my website dedicated to crawling the web for news about cross country skiing.

Preview of the new filter system at XCStorm

I’m using Heroku for hosting and for development I’m running SQLite and for staging/production its Postgres (I know its bad practice to mix…). Anyway, I found myself in a situation where I needed to compare SQL queries generated by the ORM.

Create a file named .irbrc and put this into it:

ActiveRecord::Base.logger = Logger.new(STDOUT)

Afterwards, start your Rails console and enter your query.

The reason I’m mixing database adapters is because at this point it doesn’t matter since the data won’t be complex and its easier for my partner to setup and interact with the database.

Riding the Rails: Amazon S3 & Flowplayer

Vi har börjat använda Amazon S3 för att lagra filmer som vi sedan ska spela upp (med hjälp av Flowplayer) i en inloggningsskyddad applikation.

För att sätta upp kopplingen mot S3 så använder vi oss av Paperclip och AWS::S3. Att få igång uppladdningen mot S3 tillsammans med Paperclip var absolut inga problem, det fungerade i princip så fort vi hade lagt in något liknande detta i vår modell:

has_attached_file :media_file,
    :storage => :s3,
    :s3_credentials => Rails.root.join('config', 's3.yml'),
    :path => ":attachment/:id/:style/:basename.:extension",
    :bucket => 'our_bucket',
    :s3_permissions => 'authenticated-read',
    :url => ":s3_protected_url"
    
  # Video Validations
  validates_attachment_presence :media_file
  validates_attachment_content_type :media_file, :content_type => ['application/x-shockwave-flash', 'application/x-shockwave-flash', 'application/flv', 'video/x-flv', 'video/H264']

(Det är authenticated-read som sätter rättigheterna på anslutningen och gör att vi kan använda oss av Paperclips expiring_url-metod.)

Problemet uppstod när vi skulle använda Flowplayer för att streama direkt ifrån S3, vi vill bara ha verifierade användare som ser våra filmer. Det blev strul med tecknen i de meckiga länkarna som S3 genererar och Flowplayer kunde inte läsa de rakt av.

Vi använde oss då av en “Alternate embedding method” aka. flashembed.js. Så här beskrivs “Flashembed and Flowplayer”:

Flowplayer is a regular Flash component just like any other Flash component. It can be placed on your page with this tool or by using HTML-based object tags or you can use our “competitor”, SWFObject.

Sedan när vi skickade den “säkra” länken från controllern till viewn så fick vi manuellt ersätta lite tecken:

@media[:flash_url] = @media.media_file.expiring_url.gsub("&", "%26").gsub("?", "%3F").gsub("=", "%3D")

För att embedda den i viewn så får du även se till att säga åt Rails att det är en säker länk (med hjälp av html_safe):



Riding the Rails: Aktiva menyobjekt

Fredrik W visade mig en riktigt stilig sak häromdagen på ett Rails-projekt vi håller på med. Att göra layouter och framför allt visa vilket menyobjekt som är “aktivt”, dvs vilken sida du är på just nu.

Lägg in denna helpern, i exempelvis application_helper.rb:

  
def menu_item(text, link, options = {:use_span => false, :only_controller => false})
   active = Rails.application.routes.recognize_path link
   text = content_tag("span", text) if options[:use_span]
     
   link_is_currently_active = options[:only_controller] ? params[:controller] == active[:controller] : params[:controller] == active[:controller] && params[:action] == active[:action]
    
   klass = link_is_currently_active ? "active" : ""
   return content_tag("li", link_to(text, link), :class => klass)
end
  
def menu(options = {}, &block)
  return content_tag("ul", options, &block)
end

Vi läser alltså av existerande routen och jämför den med menyobjektets. Så nu istället för att länk runt dig i applikationen med link_to så kan du nu använda blocket menu:

<% menu do %>
  <%= menu_item "Link 1", project_path(@project) %>
  <%= menu_item "Link 2", project_medias_path(@project) %>
<% end %>

Vips, så har vi nu fått en lista med det aktiva objektets klass som “active“.

Nu är det klart att detta är en väldigt begränsad lösning och kanske inte lämpar sig i större projekt med stora menystrukturer, men för enklare projekt fungerar detta alldeles utmärkt.