Friday, September 6, 2013

RVM oddity

Even though I don't use all the features, I love RVM... it generally makes my life easier when dealing with new/multiple versions of Ruby and/or different gemsets. Definitely recommended, although I know there are people who swear by rbenv. In either case, they both make magical things happen by working in the background... all terrific as long as it works. But when it doesn't work as expected, it can really be difficult to diagnose and resolve.

Case in point. The project I'm working on is done in Ruby 1.9.3-p327 and I have a 'Rails3213' gemset that I've been using. I've always used a .rvmrc file (analogous to .vimrc or .bashrc) to specify my desired ruby and gemset versions on a per-project basis. Somewhere along the line, I upgraded RVM and then get a prompt that I should switch from .rvmrc to .ruby-version for my ruby/gemset information, which I followed.

Mistake. Unbeknownst to me, the information in my .ruby-version file was silently ignored and I was using gems from another location inside RVM.  It only came to light when I encountered some strange test results and then debugging changes I made to a gem seemed to disappear. I finally got a clue of what was going on through a tell-tale signal from vim's "tag jump" (Ctrl-]) command : I had been working on the gem in:
~/.rvm/gems/ruby-1.9.3-p327@rails3213/clearance-1.0.1
but when Ctrl-] I jumped to a method definition inside vim, I was routed to a file in:
~/.rvm/gems/ruby-1.9.3-p327/clearance-1.0.1
Going back to the RVM site, I saw that .rvmrc was still (probably always had been?) the preferred way to define things, so good-bye .ruby-version, hello .rvmc, and things were back to normal.

Lesson Learned. For the future, if I run into such strangeness again, I'll look to my environment much earlier to make sure I'm working with the right set of gems or rubies or whatever.  One thing I was reminded of that I had forgetten was that rvm nicely tells you the ruby & gemset that you're using when you enter a project directory with a .rvmrc file:
Using /home/jseidel/.rvm/gems/ruby-1.9.3-p327 with gemset rails3213
And if I need to check up on things, a quick :
rvm list && rvm gemset list
tells me all I need to know that I'm in the right place:
rvm rubies
   ruby-1.9.2-p290 [ x86_64 ]
=* ruby-1.9.3-p327 [ x86_64 ]
   ruby-1.9.3-p448 [ x86_64 ]
   ruby-2.0.0-p0 [ x86_64 ]
   ruby-2.0.0-p247 [ x86_64 ]

# => - current
# =* - current && default
#  * - default
gemsets for ruby-1.9.3-p327 (found in /home/jseidel/.rvm/gems/ruby-1.9.3-p327)
   (default)
   global
   rails3020
   rails3212
=> rails3213
Another thing I'm going to do more carefully is re-create my tags file whenever there are gem changes so that I'm always up-to-date. I found a great bash one-liner (if I can remember where I found this, I'll come back and give credit):
ctags -R . $(bundle show --path)
This puts all your gems into the tags file which means that you can Ctrl-] on methods that are included in Rails or other gems.

Update:
Now when I enter the project directory, I get the RVM warning:
You are using '.rvmrc', it requires trusting, it is slower and it is not compatible with other ruby managers,
you can switch to '.ruby-version' using 'rvm rvmrc to [.]ruby-version'
or ignore this warnings with 'rvm rvmrc warning ignore /home/jseidel/Dev/MyPasswords_Upgrade/.rvmrc',
'.rvmrc' will continue to be the default project file in RVM 1 and RVM 2,
to ignore the warning for all files run 'rvm rvmrc warning ignore all.rvmrcs'.
It may be slower (I sure can't tell the difference), but I'm going to stick with .rvmrc as long as I can.

Friday, August 30, 2013

Another take on WickedPDF, wkhtmltopdf, and heroku...

A while back, I commented on installing WickedPDF/wkhtmltopdf to work on Heroku. But there are still a few more things to be done to get it all to work. Here's a checklist I provided to a friend when they were having problems.

1. Added gem "wickedpdf" in my Gemfile

2. Copied the appropriate wkhtmltopdf binary into the bin/ directory in my Rails app

3. Updated config/initializers/wicked_pdf.rb to include:
WickedPdf.config = { :exe_path => "#{Rails.root}/bin/wkhtmltopdf" }
so that it knows where I've stored the binary

4. Added the following to the show method in my controller; this is what drives the whole PDF creation. There are many more options available; this is just my minimal setup.
format.pdf do
  render :pdf => "AccRpt_#{@accident_report.id}",
    :template => 'accident_reports/show', :formats => [:pdf], :handlers => [:haml],
    :show_as_html => params[:debug].present?,
   # allow debuging based on url param
    :page_size => :letter,
    #:debug_javascript => true,
    :footer => {
      :left => "#{Time.now}",
      :center => "Accident Report ##{@accident_report.id}",
      :right => "Page [page] of [topage]",
      :line => true         },
    :user_style_sheet => "/assets/stylesheets/pdf.css",
    :layout => "pdf.html" #false end

NOTE The "show_as_html" option. By adding this, you can add "&debug=1" to your URL and see what the html would have been. Sometimes helpful in tweaking the output.

5. Created a new stylesheet called pdf.css and a new javascript file called pdf.js. They don't do a lot, but I pretty much extract out as much stuff as I can so that only what's absolutely necessary is included here.

6. Created a new layout called pdf.html.haml. Cuts out all the overhead associated with 'normal' html display. Again, nothing but what's absolutely necessary to produce the PDF.

7. In that layout, used a Content Delivery Network (CDN) for all the jquery stuff I use - that's directly available to wkhtmltopdf since it's a full URL (Remember I said that you can't use relative URL's with wkhtmltopdf).

8. Where necessary, used the WickedPDF-provided helpers to include other stylesheets/javscript files. Make sure you read the "Usage Conditions - Important!" section on the WickedPDF page - I added that after I ran into problems.

9. Created a show.pdf.haml view template with the data/formatting I wanted.
*NOTE**: You can render an existing html partial as part of your PDF output, but to do so you MUST add:
":handlers => [:haml], :formats => [:pdf]"
to the render and then you can actually reuse an html partial, such as _body.html.haml. If you don't do that, you'll get a complaint that it doesn't have the proper pdf template.

10. Added 'PDF' links at various places, such as in the index view and the show view.

11. Made sure that the PDF mime-type was registered:
'Mime::Type.register "application/pdf", :pdf' in config/initializers/mime_types.rb  

I believe that covers it all.