Saturday, December 1, 2012

CarrierWave::InvalidParameter (invalid cache id)

I'm using carrierwave to handle uploads for a project, a glorified lolcat generator. In my carrierwave uploader I had a processor that was calling model.save. My specs were passing but the app was throwing CarrierWave::InvalidParameter (invalid cache id) whenever I called recreate_versions!. I eventually tracked the cause of this down to calling model.save. It turns out that call was unnecessary. Carrierwave must do that for you. My specs were passing because I had processing turned off. config.enable_processing = false. Nobody else on the internets seemed to be having this problem. Hope it helps somebody.

Monday, October 29, 2012

Add Refinery Blog to an Existing Rails App

This is pretty easy, but there is alot of cruddy old documentation out there to confuse you.  Here are the steps I took to add a refinery blog to a simple Rails app.

  1. Add the refinery blog dependencies to my Gemfile
  2. Tweak rails dependencies to mesh with refinery dependencies
  3. Generate refinery and refinery blog stuff
  4. Fix routes
  5. Fix layouts that refinery destroys
Here is a gemfile snippet that shows what I added to make step 1 and 2 happen.  The only trouble I had was that refinery depends on an older version of jquery-rails than rails 3.2.8.  Bundler kept installing an ancient version of refinery because i guess it's dependency rules were more liberal.  Make sure you get a version of refinery that is greater than 2.
Once you have those dependencies you generate the refinery CMS.
rails generate refinery:cms --fresh-installation
That will create lots of stuff, migrate and seed your db, and it will also delete your application layout. Not a big deal if you are using git, we can put things right. Before we do that let's just generate the blog too.
rails generate refinery:blog
rake db:migrate
rake db:seed
Ok, more stuff generated, migrated and seeded. Refinery has installed itself in the root of our application's routes so let's put it in a subdirectory. Open up routes.rb and change the refinery mount to have a different 'at' location. Now notice that refinery has deleted your application layout. You probably want to have separate layouts for your existing application and the refinery application. What I did was to use git to bring back my old layout and then I renamed it to appname.html.erb Then inside application_controller.rb I dynamically set the layout as follows: This basically checks to see if the controller is inside the Refinery module and if it is it sets the appropriate layout. Refinery uses the default layout (which shouldn't exist in your project because it is set inside the refinery engine).
And that is pretty much it. My blog shows up at "/cms/blog". My app is still at "/". And refinery's admin stuff is found at "/cms/refinery".

Friday, September 7, 2012

The mochila pattern

A mochila (pronounced mo-chee-uh is Spanish for pouch) was used for carrying mail by the Pony Express in the nineteenth century. I'm discussing a technique of combining related HTML snippets into one HTML response by wrapping each of the snippets into separate envelopes. This single HTML response that contains multiple envelopes is a mochila. This technique can reduce the number of HTTP requests you need, and offers the ability to re-use existing partials without needing to create a JS template that duplicates a partial.

The example I'll use to illustrate the mochila pattern is an index page that shows a list of video thumbnails. When you hover over a thumbnail, it plays in the foreground while another version of the same video plays fullscreen in the background. The background video has a beautifully subdued alpha and gradient overlay. And the effect adds lots of interest and an artful quality to our page.

In our page the thumbnail video and the background video are separate HTML elements that live on different parts of the page. The background videos are just inside the body tag. The thumbnails are inside of an unordered list. However they are clearly related. If we want to add another video to the page with ajax we need to add snippets of HTML to both the list and the body for the respective new thumbnail and background videos. Here is the skeleton markup to illustrate that:
There are many ways we could add another video dynamically: multiple requests, json requests that populate JS templates, but we're interested in using a mochila. Here is a simple illustration of the technique:

Note how we can use jQuery to manipulate the HTTP response just like we would use it for any other part of the page.  This makes it simple to grab the separate envelopes from the mochila.  I think the other techniques have their place as well.  If you've already got a JS templating system in place, that can be a powerful technique.  But for a simple rails app you might be content to use this technique to get a little more mileage from your already built partials.

Like any technique the mochila can be abused. Filling a mochila with unrelated content or too many envelopes could create confusion and would lead to ugly JS pre-processing on the client. Add this trick to your arsenal, but don't abuse it.  Know your options.  Have a look at underscore.js templates if you haven't already.

Monday, July 23, 2012

Greed scoring solution for the Edgecase Ruby Koans.

Edgecase has some nice koans for learning Ruby.  Going through them is a good refresher for some of the Ruby features you don't use that often, or the parts of Ruby where the principle of least surprise has gotten into the weeds (multiple assignment i'm talking to you). I wrote mine as a class and did TDD so I have my own test suite, but when I plug it into the koans, all is well. My original solution had a bunch of conditional statements, but some refactoring got rid of most of them. Using modulo was the key. Have a look, feedback is welcome.

Tuesday, July 17, 2012

Scale worker processes in Heroku for Sinatra with Delayed Job

I've done this a few times for some of my personal projects and it works pretty well. Every single time I do it I always have the same problems so here is a checklist to keep you from going off the rails (HAHAHA!).
  • Make sure you've got the right gems: delayed_job, delayed_job_active_record, workless, heroku
  • Make sure you've configured delayed job to use your workless process scaler, and your scaler matches the heroku stack you are running
  • Create a Procfile with your worker definition (see gist above)
  • Set all required environment variables: APP_NAME, HEROKU_PASSWORD, HEROKU_USER
  • I usually use the heroku scheduler app add-on to run my rake task that adds stuff to my jobs table.
I've seen the following HTTP errors when running misconfigured apps:  
  • 404.  This is what you'll get if you are missing the APP_NAME because  if you look at the ps_scale method in the heroku gem, it is using that name to build a URL so without it your URL will be broken.
  • 401. This is what you'll get if you forget to set the username and password environment variables because the ps_scale method of the heroku api requires authentication.
  • 422 (Unprocessable Entity). This is what you'll get if you forget the procfile.  It is a shitty error message that is trying to tell you that heroku doesn't know how to create a worker process if you don't define it. Ick.
Allright.  Best of luck future me, and whoever else finds this useful.

Monday, May 28, 2012

Sinatra-san, meet kaminari

Here is a gist with a few snippets that I used to get kaminari pagination working with sinatra. Sinatra is already big in Japan so it's super easy! I ran out of steam trying to override the kaminari templates. My guess is that you'd have to modify kaminari a bit to make that happen. Leave a note in the comments if you figure that out.

Friday, March 30, 2012

HTTP Accept headers for PhoneGap and Rails

Building a PhoneGap mobile application with a Rails backend? You should know about HTTP Accept headers and Rails. The important thing to understand is that best practice in Rails is NOT to use the Accept headers. There is a nice writeup here that explains why in glorious detail. Summary: browser implementation of HTTP Accept headers is broken. Rails best practice is to set the :format parameter in the request. However, if you like the accept headers they are supported but the rules around what is a valid accept header in rails can be tricky. For example: if your accept header matches the following regex:

BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/


Then rails throws it away and defaults to text/html mime type. I know, right? We had a problem with backbone and JQuery. Our application was sending the following accept headers:
application/json, text/javascript, */*; q=0.01
Looking at that you would expect that because we ask for a json response we should get one. Rails returns text/html in this case because our accept headers looks like the kind of thing the browser would send along, thus broken and unreliable. You might be thinking: hey, every other rails app I've built hasn't had this problem. Well, the reason most people don't have this problem is that rails "fixes" the default jquery behavior in the rails jquery-ujs gem. They set a ajaxSetup beforeSend callback in JQuery that puts the */* at the beginning of the header, which is what the magic rails regex wants to see. Here is how I fixed my accept header in JQuery.


$(function() {
$.ajaxSetup({
'beforeSend': function(xhr) {
xhr.setRequestHeader("accept", "appplication/json");
}
});
});

Friday, March 23, 2012

Creating a new Rails app Segmentation Fault on Ruby 1.9.3

Ran across this one today. I was trying to create a new rails app on Ruby 1.9.3.


/Users/oldjosh/.rvm/rubies/ruby-1.9.3-p0/lib/ruby/1.9.1/net/http.rb:799: [BUG] Segmentation fault
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-darwin11.2.0]


It turns out that if you don't compile 1.9.3 against openSSL from macports or some other non-apple source, you end up with a ruby that segfaults when it tries to do ssl. Thus bundler fails to fetch gems when you create a rails app. My fix was to reinstall 1.9.3 and specify where my macports openssl installation was.


$ rvm reinstall 1.9.3 --with-openssl-dir=/opt/local


RVM has another option to get around this if you don't have macports or some other alternative. See their docs for more info. And see the bug that helped me solve my problem.

Wednesday, March 21, 2012

Vimeo's White Screen of Death in IE

Recently I noticed my embedded Vimeo players were all broken in IE. I was getting just a blank white screen. It turns out Vimeo requires you to have Flash version >= 10. That is fine, but unfortunately their player doesn't fail gracefully if you have an older flash version. My VM had Flash 6. It is simple to check for a particular version of flash in JS. That allows us to fail gracefully on behalf of Vimeo. Here is a snippet that can check if the client browser is good enough for vimeo.


<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
<script>
function goodEnufForVimeo(){
var playerVersion = swfobject.getFlashPlayerVersion();
return (playerVersion.major >= 10);
}
</script>