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.

Använda Spotify MetaData API i Ruby

Spotify har släppt ett API för att kunna hämta information om låtar via deras Spotify-url:er. Nedan är ett exempel i Ruby på hur du kan hämta artist och låt. Anropas med ex. spotify:track:4KPU7XGqxo4UlMp3is7NBI

def getTitleFromSpotifyTrack(trackID)
    require 'net/http'
    require 'rexml/document'
    require 'rexml/xpath'

    res = Net::HTTP.get_response(URI.parse("http://ws.spotify.com/lookup/1/?uri=#{trackID}"))
    contents = res.body

    doc = REXML::Document.new contents

    track = REXML::XPath.first(doc,'/track/name/text()')
    artist = REXML::XPath.first(doc,'/track/artist/name/text()')

    return "#{artist} - #{track}"
  end