You're viewing all posts tagged with rails

Reinstalling All Native Gems on Snow Leopard

After installing Snow Leopard all of my native code gems broke horribly, complaining that they were now on the wrong architecture. To re-install every gem automatically, I used:

sudo gem list | awk '{print $1}' | xargs sudo gem install

Haml 2.2 Compile Error In Ugly Production Mode

If you were previously using the Haml syntax:

%p= 'string ', method, ' string'

you will need to change it to:

%p= ['string ', method, ' string']

to avoid compilation errors in production mode.

Rails 2.2 Templates

TemplateHandlers have been significantly overhauled in Rails 2.2, and these changes are not backwards-compatible with Rails 2.1.

Instead of being responsible for rendering a template, TemplateHandlers should now provide a string of Ruby that will be eval’ed by ActionView further along the rendering chain.

So, where previously a TemplateHandler might have declared a render method:

class DotHandler < ActionView::TemplateHandlers::ERB

  def render(template, local_assigns = {})
    @view.controller.headers["Content-Type"] ||= 'image/png'

    input = super(template)

    output = IO.popen('dot -Tpng', 'r+') do |io|
      io.write(input)
      io.close_write
      io.read
    end

    output
  end
end

ActionView::Template::register_template_handler 'dot', DotHandler
ActionController::Base.exempt_from_layout :dot

Templates should now provide a compile method that will return ruby code for execution later:

class DotHandler < ActionView::TemplateHandler

  def compile(path)
    <<-EOS
      controller.response.content_type ||= Mime::PNG
      #{ActionView::Template.handler_class_for_extension('erb').call(path)}
      @output_buffer = IO.popen("dot -Tpng", 'r+') do |io|
      io.write(@output_buffer)
      io.close_write
      io.read
      end
    EOS
  end

end

ActionView::Template.register_template_handler 'dot', DotHandler
ActionView::Template.exempt_from_layout 'dot'

To chain template handlers, find the appropriate handler with ActionView::Template#handler_class_for_extension and then call it. The code it returns can then be injected into your compiled template.

Custom 404 Pages With Passenger

On failing to match a route, Rails 2.1.2 appears to rescue the ActionController::RoutingError with its stock template (/action_controller/templates/rescues/layout.erb) and then returns an upstream 404 error code — even if you’ve defined a custom rescue_from in ActionController:

rescue_from ActionController::RoutingError, :with => :render_404

With your Mongrel/Thin and Apache/Nginx combo this is fine; you can intercept the error code and redirect your visitor to the appropriate custom error page. With Passenger (mod_rails) however, there is no such intermediary step. 404 error messages that do not match a controller will just generate a blank page.

To address this problem, the best solution I have found is to add a final catch-all route at the bottom of your routes.rb file that invokes your rescue_from method directly:

map.connect '*path', :controller => 'home', :action => 'render_404'

Custom Error Pages With Nginx and Thin

If you are using Nginx to proxy to another web server such as Thin or Mongrel, chances are you have had trouble getting your custom error pages to return the correct status codes.

If your application redirects to a cached error page Nginx will serve it as a normal file and will (correctly) tell the browser that everything was successful. Not quite the intended behaviour.

To fix this, add locations for your error pages and set them to be internal. Now the locations can only be reached when somethig goes wrong (as intended) and Nginx will never mistakenly serve them as valid files.

upstream thins {
  server 127.0.0.1:3000;
  server 127.0.0.1:3001;
}

access_log /var/www/example/log/access.log;
error_log /var/www/example/log/error.log;

root   /var/www/example/public/;

server {
  listen 80;
  server_name www.example.com;

  proxy_set_header  X-Real-IP  $remote_addr;
  proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_redirect off;

  error_page 404 /404.html;
  error_page 502 503 /503.html;

  location ~* ^/(404|502|503).html$ {
    if (!-f $request_filename) {
       proxy_pass http://thins; break;
    }
    internal; break;
  }
  location / {
    if (!-f $request_filename) {
      proxy_pass http://thins;
      break;
    }
  }
}