nginx/passenger/rails needs extra path to make some gems work
Having tested markdown code block highlighting, I was surprised to find Pygments not being able to highlight anything when run via nginx/passenger in FreeBSD production. Blam -- sever error:
Processing by ArticlesController#show as HTML
Parameters: {"id"=>"9"}
rendering ruby block
Rendered articles/_full_body.html.haml (113.2ms)
Rendered articles/show.html.haml within layouts/application (114.4ms)
Completed 500 Internal Server Error in 121ms
ActionView::Template::Error (Failed to get header.):
7: = article.summary
8: - if article.body?
9: .article
10: =raw article.render_body( internal_images_by_name )
11: - else
12: %p no article body??
13: %p
lib/markdown_utils.rb:11:in `block in block_code'
lib/markdown_utils.rb:10:in `block_code'
app/models/article.rb:110:in `render'
app/models/article.rb:110:in `render_body'
app/views/articles/_full_body.html.haml:10:in `_app_views_articles__full_body_html_haml__4458801067574565172_17264035260'
app/views/articles/show.html.haml:3:in `_app_views_articles_show_html_haml__3162500010226637938_17263456920'
app/controllers/articles_controller.rb:73:in `show'
where the line in question looks like this:
class HTMLwithPygments < Redcarpet::Render::HTML
def block_code(code, language)
sha = Digest::SHA1.hexdigest(code)
Rails.cache.fetch ["code", language, sha].join('-') do
Pygments.highlight(code, lexer: language) # line 10 - exception here
end
end
end
More interesting: it works fine from rails/console, even in production:
% rails c
Connecting to database specified by database.yml
Loading production environment (Rails 3.2.13)
irb(main):001:0> Pygments.highlight("puts 'hi'", :lexer => :ruby)
=> "<div class=\"highlight\"><pre><span class=\"nb\">puts</span> <span class=\"s1\">'hi'</span>\n</pre></div>"
irb(main):002:0>
Some tedious debugging explains why Pygments.rb cannot popen4 the Python interpreter under Nginx: Pyhton lives in /usr/local/bin which is not on the path for the Rails process created by Nginx/Passenger. Many ways to fix that. In my case, I added something to the Rails initialization to make sure /usr/local/bin is always on the path for the Rails process.
Now is works like a charm - you're looking at the results in the above code blocks for this tech note.