Thursday, October 10, 2013

Ruby variable assignment... how does that really work?

I've recently been working to improve my Ruby skills, so I've started coding many of the exercises in "Cracking the Coding Interview" by Gayle Laakmann McDowell, implementing the problems in TDD/Ruby instead of in Java.

In the process, I ran into a real puzzler -- a bug that I and several friends looked at and couldn't quickly solve. It turned out to be really basic Ruby.

I had developed the following code as part of the answer to CtCI's problem 9.4: Create all the subsets from a set (you can find the complete solution here).
def ss_raw set
  @result_raw << set
  return if set.size == 1
  set.each_index do |i|
    tmp = set
    tmp.delete_at i
    ss_raw(tmp)
  end
end
The intent of this code was to recursively remove one element from the input and generate the subsets. The tmp variable was intended as a proxy for the set variable so that the each_index block could process each subset by deleting one element at a time. It didn't work and gave some really perplexing results, apparently replacing the contents of @result_raw rather than appending to it.

Unfortunately, I forgot the basics:
tmp = set
doesn't create a new variable, it simply creates a new pointer to the same location in storage that set points to. Therefore, modifying tmp also modifies set and the whole process goes south. The solution? Just say
tmp = set.clone
and you get a new and separate variable and the method works as expected.

In many cases, an oversight like this won't cause a problem, but in this cae it wound up modifying the method parameter as well as modifying the basis of the each_index block... a definite no-no and exactly what I was trying to avoid in the first place.

Hopefully this little reminder will help someone else avoid the pain.

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.

Wednesday, July 24, 2013

Setting up Jasmine for JavaScript tests

Testing your JavaScript with Jasmine is A Good Thing, so I figured it would be easy to get started. There's great documentation at the Github/Jasmine site as to how the tests are described and what matchers are available, but there didn't seem to be any clear-cut instructions on how to get the whole thing to run once you've installed it. There's talk of a file 'SpecRunner.html' and there were a number of posts asking "Where's my SpecRunner file?". And even after you install the gem, there's no documentation provided with rake -T to tell you what to do.

Turns out it's really drop-dead simple so - just in case someone else has this problem - here's what I did.
cd /path/to/your/project
gem install jasmine
rake jasmine
http://localhost:8888 in your browser
The tests in your project are run automatically.

Wednesday, June 26, 2013

Silence is NOT golden...

Here's a sneaky little routing gotcha.  Let's say you're TDD'ing a new feature and your test requires a 'new' action. Following best practice, you start by saying
resources :accounts, only: [:new]
instead of
resources :accounts
Before we get to the gotcha, why would I say 'best practice' is to avoid the complete definition? Well... remember one of the core principles of TDD:
Write ONLY enough code to get the test to pass.
This means that adding only a single action is all I need do to get the test to pass, so that's all I add (even though I actually write more code in that case). This idea certainly isn't new to me; for example, check out the Thoughtbot TDD class if you're interested in learning more: great resource!

On a broader scale, assuming you've got this whole feature written, you still want to avoid adding any unused actions. If you use every RESTful action except for :delete, then you don't want to allow the delete action to exist, as it offers one more opportunity for the bad guys to attack your site.

Back to the gotcha. Let's say that you code the above example, but - oops - you make a typo and actually code:
resources :accounts, only: [:newt]
Guess what - this error is silently ignored. No route is generated and you don't get an error message. In fact, the only: and except: options just ignore anything that isn't on the list of RESTful actions (index, create, new, update, edit, show, destroy) and give no warning.

It's easy to overlook this as we're used to having Rails give us helpful error messages if we code something incorrectly. Not so in this case.

Sunday, June 23, 2013

"Can't find generator help."

Here is a tricky little case of  mis-direction. I've gotten used to github, heroku, and a host of other command-line tools that allow you to add the keyword 'help' to the command to get some basic usage info. Not so, Rails.  If you type the following inside a Rails application (I'm on Rails 3.2.13 or 3.2.12):
rails generate help
you get the decidedly unhelpful message:
Could not find generator help.
Rails thinks you're looking to generate a "help" something or other.

However, if you type the same command outside a Rails app, you get what you'd expect:
Usage:
  rails new APP_PATH [options]

Options:
  -r, [--ruby=PATH]              # Path to the Ruby binary of your choice
                                 # Default: /home/jseidel/.rvm/rubies/ruby-1.9.3-p194/bin/ruby
  -b, [--builder=BUILDER]        # Path to a application builder (can be a filesystem path or URL)
  -m, [--template=TEMPLATE]      # Path to an application template (can be a filesystem path or URL)
      [--skip-gemfile]           # Don't create a Gemfile
      [--skip-bundle]            # Don't run bundle install
  -G, [--skip-git]               # Skip Git ignores and keeps
  -O, [--skip-active-record]     # Skip Active Record files
  -S, [--skip-sprockets]         # Skip Sprockets files
  -d, [--database=DATABASE]      # Preconfigure for selected database (options: mysql/oracle/postgresql/sqlite3/frontbase/ibm_db/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
                                 # Default: sqlite3
  -j, [--javascript=JAVASCRIPT]  # Preconfigure for selected JavaScript library
                                 # Default: jquery
  -J, [--skip-javascript]        # Skip JavaScript files
      [--dev]                    # Setup the application with Gemfile pointing to your Rails checkout
      [--edge]                   # Setup the application with Gemfile pointing to Rails repository
  -T, [--skip-test-unit]         # Skip Test::Unit files
      [--old-style-hash]         # Force using old style hash (:foo => 'bar') on Ruby >= 1.9

Runtime options:
  -f, [--force]    # Overwrite files that already exist
  -p, [--pretend]  # Run but do not make any changes
  -q, [--quiet]    # Suppress status output
  -s, [--skip]     # Skip files that already exist

Rails options:
  -h, [--help]     # Show this help message and quit
  -v, [--version]  # Show Rails version number and quit

Description:
    The 'rails new' command creates a new Rails application with a default
    directory structure and configuration at the path you specify.

    You can specify extra command-line arguments to be used every time
    'rails new' runs in the .railsrc configuration file in your home directory.

    Note that the arguments specified in the .railsrc file don't affect the
    defaults values shown above in this help message.

Example:
    rails new ~/Code/Ruby/weblog

    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.
    See the README in the newly created application to get going.

Thursday, June 20, 2013

wkhtmltopdf and all those gems...


Looking back on my wkhtmltopdf / Heroku experience, there are several take-aways for me.

First off, I had contacted Heroku technical support for assistance, and got back a quick reply:

Unfortunately we don't support installing additional libraries or binaries to our stacks. The best workaround is to vendor these into your project. You'll need to use 64-bit Linux versions to make them work on Heroku; compiling statically can also help ensure that any dependencies needed are included. Similarly, for gems that depend on external libraries, we recommend compiling the gem statically and vendoring it into your project (which is what it seems you have already tried to do).

We realize this is not a trivial task and can be very difficult to get working, and we hope to provide an easier way to do this in the future. Unfortunately we do not have an ETA on when this improved functionality will be available.

If you do wish to try to vendor, or if you have no success with vendoring, your binary, library, or gem, you can use Heroku as your build environment. One of our engineers created a build server that allows you to upload source code, run the compilation step, and then download the resulting binary. You can find this project on Github.
Kinda makes sense to me: they have to protect their stack. I'm not surprised, just a wee bit disappointed that they don't make something as widespread and generally useful as wkhtmltopdf available as a standard binary. Oh well; they do seem to be looking into a better solution, and they did provide some good information. The link to that project looks like it might be useful in the future.

Once I got my app with PDF working, I submitted a documentation update to WickedPDF, which was promptly merged (thanks @unixmonkey). Hopefully that'll provide some assistance to other folks.

One of the problems I had with the various gems that include binary versions of wkhtmltopdf was that they hadn't been updated recently... sometimes in over a year.  So I figured that I should be a good citizen and update them with the latest version (0.11.0 rc1 at the time I'm writing this).  To that end, I just submitted a pull request for the wkhtmltopdf-heroku gem. It purports to automagically support WidkedPDF, PDFKit, and wisepdf, depending on which one is loaded (I've not tested it myself).

However, when I started looking at the wkhtmltopdf-binary "family" of gems, it was pretty involved: steerio/wkhtmltopdf-binary (the one I originally investigated), is forked from unixmonkey/wkhtmltopdf_binary_gem which in turn is forked from michaelcollas/wkhtmltopdf_binary_gem, which is itself forked from zakird/wkhtmltopdf_binary_gem and who know how many forks there are on side legs...

That's not something I'm inclined to sign up for! And given the simplicity of adding the single binary in my app (now that I know how to do it), I'm inclined to keep it that way and avoid any of those gems entirely. In fact, I'm beginning to come to the conclusion that it may be better in the long run to install things manually for what I'll call "minor" gem functionality [Note to self: come up with better terminology for this situation] such as this one: I know more of what's going on and have more control over the final outcome.

It also reminds me that, while we work hard to DRY up our code, the proliferation of similar gems on the web is anything but DRY.

Friday, June 14, 2013

WickedPDF, wkhtmltopdf, and Heroku...a tricky combination

At least for me as it took a bit of twiddling to get it running, first in development and then on the Heroku stack. But with a lot of testing and some help from unixmonkey and my friends at Thoughtbot, I finally got it working. Here's how.

First off, I'm running Rails 3.2.13, WickedPDF 0.9.6, and wkhtmltopdf 0.11.0 rc1, running development on a Linux (Kubuntu 10.04) 64-bit machine. NB: The machine you're developing on and deploying to can be different but then you'll have to have two (or more) different copies of wkhtmltopdf and properly configure WickedPDF to handle that difference. I cover that later in this post.

Install wkhtmltopdf

The download site for wkhtmltopdf has pretty much everything you need for whatever machine architecture you are working with. Download the matching flavor for your development and production machines. If you have only a single machine architecture, then just call your one binary 'wkhtmltopdf'.

If you're working with multiple architectures, label each one appropriately, either with the architecture suffix (e.g., -amd64) or simply '-dev' and '-prod'.

Place the one or more binaries in the directory "/bin", right off your root directory (e.g., "#{Rails.root}/bin") and mark them as executable (chmod +x on linux/mac). Note that for Windows development, you'll have a wkhtmltopdf.exe file for development and probably plain 'ol wkhtmltopdf for production.

Install WickedPDF

Installation is straight-forward; just follow the instructions here. However, there are some critical changes you must make for generating PDFs successfully. The section titled "Styles" gives you the key:
You must define absolute paths to CSS files, images, and javascripts
I'm highlighting this because I missed it the first time around and it cost me dearly.  This section goes on to suggest that you use the helpers that are provided. They are:
wicked_pdf_stylesheet_link_tag
wicked_pdf_image_tag 
wicked_pdf_javascript_include_tag 
Every external file that you use must be referenced with an absolute address, so the normal Rails helpers do not work in many cases [Technical Note: the wicked_pdf helpers simply embed the actual CSS or Javascript in the page]. To make life easier for me, I did the following:
  • Create a special pdf.html.haml layout for all PDF pages which uses the wicked_pdf helpers
  • Use the jQuery CDN for including that set of libraries; the Rails-provided helpers do work here because I'm providing an absolute URL; nothing relative to the Rails root of my application 
= javascript_include_tag "http://code.jquery.com/jquery-1.10.0.min.js"
= javascript_include_tag "http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"

Now here's the strange part [I believe this has to do with the Rails asset pipeline; I'll update this post once I nail that down]. I also had to add all my CSS and JS files to my application.rb file for inclusion in the asset pipeline, thusly:
config.assets.precompile += ['blueprint/screen.css', 'jquery.timepicker.css', ...]
Only with this incantation did everything work properly.

Configure WickedPDF for Development & Production

If you're developing on Linux 64-bit, then configuration is easy as you'll use the same binary for both development and production. Update your WickedPDF initializer file ("config/initializers/wicked_pdf.rb") as follows:

WickedPdf.config = { :exe_path => "#{Rails.root}/bin/wkhtmltopdf" }
If you're developing on something other than Linux 64-bit, you'll have to test for the environment and set your exe_path appropriately.. something like this:
WickedPdf.config do |config|  
  if Rails.env == 'production' then
    config.exe_path = Rails.root.to_s + "/bin/wkhtmltopdf"
  else  ### Following allows for development on my MacBook or Linux box
    if /darwin/ =~ RUBY_PLATFORM then
      config.exe_path = '/usr/local/bin/wkhtmltopdf' 
    elsif /linux/ =~ RUBY_PLATFORM then
      config.exe_path = '/usr/bin/wkhtmltopdf' 
    else
      raise "UnableToLocateWkhtmltopdf"
    end
  end
end

For windows, you'll have to check out the RUBY_PLATFORM values you see and modify appropriately; my windows machine reports "i386-mingw32'.

 If you need different versions of the same architecture (say for final testing a new version of wkhtmltopdf before rolling into production), then just label it with the version number and update your WickedPDF configuration file.

Monday, June 10, 2013

Chrome / PDF Problem...

I've recently been working to add PDF generation to a client site and got WickedPDF working. I ran into a problem which I finally resolved (RTFM very carefully)... got some great help from the Wicked folks along the way. In any event, I was finally generating my PDFs fine with Firefox, but Chrome kept failing with the message:
Sorry, we were unable to find the document at the original source. 
Verify that the document still exists.
You can also try to download the original document by clicking here.
All that had to be done was to click on the 'here' link provided, but that's less than an optimal user experience... Not Good, Google! There are quite a few posts out there with the same problem. I finally figured out that this was caused by the Google Docs PDF/PowerPoint Viewer (I was running version 3.10). Easy solution: in Chrome, go to:
Customize | Tools | Extensions
and disable that extension. Now PDFs are properly displayed.

Tuesday, May 28, 2013

Fixing a database problem on a Heroku app

Recently, I was working on an upgrade to a Heroku app and found to my surprise that my schema_migrations table was wrong in production (horror, actually... I hate this kind of problem because of the possibility of data corruption). The database tables were correct, but the schema was behind by 11 migrations. Suffice it to say I have no idea how that happened, but it must have occurred when I was upgrading from a staging instance to production earlier this month [Note to self: figure out a reliable methodology for doing this].

There are a number of posts that recommend directly updating the Heroku database; this one, for example. I started to take this approach and then realized that there was a safer way to make this change. Heroku has a set of database commands that allow you to copy your production database down to your location machine or copy it back to production. This is better, IMO, than mucking with production data live... even with a backup. Working on your local machine, you can run your tests and generally use all available tools to make sure the modifications work before you upload it back to production.

The steps are dead simple:
  1. Find the id of your production database:
    heroku config --app [name]
    the id you want is usually something like "HEROKU_POSTGRESQL_PINK_URL"where "PINK" will probably be some other color.
  2. Make a backup of your production database using the database id:
    heroku pgbackups:capture --app [name] [database id]
  3. "Pull" the production database down to your local machine (Heroku drops it into your development database):
    heroku db:pull --app [name]
  4. Make your changes
  5. Run your tests
  6. "Push" the modified data back to production:
    heroku db:push --app [name]
  7. Open your browser and run a smoke test on your updated database.
Mission accomplished.

Sunday, May 26, 2013

RSpec / Devise / Capybara & feature specs with HTTP Authentication

I'm working on a couple of sites which use HTTP Authentication and - after much googling and failed attempts - developed a way to deal with that with a set of spec helpers. It all started with this gist from Matt Connolly - thanks Matt!

For the record, I'm developing with the following:
ruby 1.9.3p327
rails 3.2.12
devise  2.2.3
capybara 1.1.4
rspec  2.13.0

What I wanted was to be able to say:
def before do
  login_user()
end
and have it Just Work.

In preparation for Capybara 2.0, I'm putting all my integration tests in the spec/features directory and that created some of the confusion. Code in the spec/integration directory has access to the controller, whereas code in the spec/features directory does not. This means that both HTTP Authentication and Devise login must be handled differently.  To resolve this, I started with Matt's approach and modified it so that (so far), it works in any of my tests.

First, I modified Matt's module to add login processing and separate out the HTTP Authentication so that it could be used for controller as well as feature specs. Here's the code:

## spec/support/auth_helper.rb
module HTTPHelper
  def http_config(test_type)
    @test_type = test_type
  end

  def http_login(user,pw)
    puts "@test_type: #{@test_type}"
    if @test_type == :controller then
      request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(user,pw)
    elsif @test_type == :feature then
      if page.driver.respond_to?(:basic_auth)
        puts 'Responds to basic_auth'
        page.driver.basic_auth(user, pw)
      elsif page.driver.respond_to?(:basic_authorize)
        puts 'Responds to basic_authorize'
        page.driver.basic_authorize(user, pw)
      elsif page.driver.respond_to?(:browser) && page.driver.browser.respond_to?(:basic_authorize)
        puts 'Responds to browser_basic_authorize'
        page.driver.browser.basic_authorize(user, pw)
      elsif page.driver.respond_to?(:browser) && page.driver.respond_to?(:header)
        encoded_login = ["#{user}:#{pw}"].pack("m*")
        page.driver.header 'Authorization', "Basic #{encoded_login}"
      else
        puts "page.driver.methods: #{page.driver.methods.sort}"
        if page.driver.respond_to?(:browser) then
          puts "page.driver.browser methods: #{page.driver.browser.methods.sort}"
        end
        raise "I don't know how to log in!"
      end
    else
      raise "I don't know what kind of test this is!"
    end
  end  
end

module AuthHelper
  include HTTPHelper
### For controller specs

  def login_admin
    login_user(:admin)
  end
  def login_user(user_name=nil)
    http_config :controller
    http_login('HTTPname', 'HTTPpassword')
    if user_name.nil? then
      @current_user = FactoryGirl.create :user
      @current_user.confirm!
      sign_in @current_user
    else
      raise NotImplementedError
      @current_user = FactoryGirl.create :user, :name => :user_name
      user = User.where(:name => user_name.to_s).first if user.is_a?(Symbol)
      sign_in user.id
    end
  end
  def current_login
    User.find(session[:user_id])
  end
end

module AuthRequestHelper
  include HTTPHelper
### For request, feature & view specs  
# pass the @env along with your request, eg:
# GET '/labels', {}, @env

  def login_user(user_name=nil)
    http_config :feature
    http_login('HTTPname','HTTPpassword')
    if user_name.nil? then
      @current_user = FactoryGirl.create :user
      @current_user.confirm!
      #Following does not work in feature specs
      #sign_in @current_user
      visit ('/')
      click_on 'Login'
      fill_in 'Email', with: @current_user.email
      fill_in 'Password', with: 'password'
      click_on 'Sign in'
    else
      raise NotImplementedError
    end
  end
end

## Relevant portion of spec/spec_helper.rb
...
  config.include HTTPHelper
  config.include AuthRequestHelper, :type => :request
  config.include AuthRequestHelper, :type => :feature
  config.include AuthRequestHelper, :type => :view
  config.include AuthHelper,        :type => :controller
...

## spec/support/devise.rb
RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
  config.include Devise::TestHelpers, :type => :view
end

Couple things to note: BothHTTP Authentication and Devise sign_in are  different between controller and feature specs primarily, I believe, because of Capybara handling in the feature specs (remember, the controller isn't available in feature specs with Capybara see the "Gotchas" near the bottom of the Capybara Read Me). Also check out this useful post from Thoughtbot.

Before you say anything... yes, I know it's not very DRY: I could have just included the HTTP Authentication code in each of the different authorization modules. But while working on it, I wanted the code isolated for clarity and I'm just happy to have the thing working. Feel free to clean this up if you want.

For now I'm not using the login_admin method, but will be working with that down the line.

Now I can finally get back to the real work of developing my app; hope this helps someone else.

EDIT: Thanks to the folks at thoughbot for this link which describes how to login using Warden. I haven't tried it, but it looks promising.


Sunday, May 19, 2013

Bash aliases and variables don't mix

For a long time, I've used bash aliases such as:
alias hgrep='history | grep $1'
and they've worked just fine. However, when I've tried to do something a bit more complicated, such as:
alias hprju='heroku $1 --app project $2'
it fails with an error message:
!    `--app` is not a heroku command.
Bummer! What I finally realized is that the first example isn't actually replacing $1 with what I specified on the command line. Instead, $1 has NO replacement and my additional text is simply appended to the end of the line. To see how this works, just run the following:
alias test='ls'
test /etc
and you'll get a directory listing of /etc. After some googling -- with a number of questions along the lines of "Why doesn't my first example work and not my second?" -- I found this link, where the 2nd answer had the key. The Bash Reference Manual section on Aliases clearly states:
There is no mechanism [my emphasis] for using arguments in the replacement text, as in csh. If arguments are needed, a shell function should be used (see Shell Functions).
This situation has bugged me off and on for some time and I'm glad to finally understand what's happening. Hope it helps someone else.

Tuesday, April 23, 2013

RVM and vim-rails on Linux

I recently installed Tim Pope's vim-rails plugin (amazing stuff) but pretty quickly ran into a problem running things like the :Rake or :Rscript commands.  I'd get something like the following:

Could not find ZenTest-4.9.1 in any of the sources 

Checking things from the command line showed that ZenTest was, in fact, properly installed.  Finally, the output from a failed :Rake command gave me the clue I needed to resolve this issue:

/home/jseidel/.rvm/gems/ruby-1.9.3-p194@global/gems/bundler-1.1.5/lib/bundler/spec_set.rb
in `block in materialize':
Could not find gherkin-2.12.0 in any of the sources (Bundler::GemNotFound)
The ruby version vim-rails was using was the default
"/ruby-1.9.3-p194@global"
instead of the project-specific ruby I had specified of
"/ruby-1.9.3-p327@Rails3212"

The problem was that I was starting Vim from the system application launcher which is where it picked up the default values for $GEM_HOME since no project was associated.

Simple work-around is to start vim from the project command line and now all the environment settings are correct.

EDIT-1: Just found vim-rvm, again by Tim Pope, which takes care of all of this and then some.

EDIT-2: To get things to work together properly (I'm on RVM 1.19.6 stable and the latest vim-rvm and rim-rails), you have to convert your .rvmrc file to a .ruby-version file using the command:

rvm rvmrc to [.]ruby-version

Saturday, February 23, 2013

Asset pipeline flowing smoothly...

Finished my testing with the changes for an addition to my existing app and decided it was time to get this into production.  Only hitch was that my app was running on bamboo and you need to be on cedar if you want to implement the asset pipeline. The Heroku folks have a good introduction to how to do this here and here. Well laid out and gave me everything I needed to create a new, test app to deploy to.

First problem I ran into was Heroku complaining that it couldn't install sqlite3. Now this is a well-documented problem which requires that you make sure that your sqlite gem is only available in test and development but not in production as Heroku no longer supports that. It's a simple fix:

 gem sqlite3, :group => [:development, :test] 

I dutifully made the change and pushed to my test app but it continued to fail. After an embarrasingly long time, I remembered that I was working on branch 'cedar' (isolating these changes) but the push was going to 'master'. This was a quick fix:

git push test-app HEAD:master

pushes the current HEAD to master on Heroku... problem solved.

Then I ran into a further complication; Bundler worked fine but the Heroku assets:procompile was failing with

could not connect to server: Connection refused
Is the server running on host "127.0.0.1" and accepting
TCP/IP connections on port xxxx?

This was a simple solution, found in the previous reference in the 'Troubleshooting' section; just add this to my application.rb file:
config.assets.initialize_on_precompile = false
Now I could run my migrations, install the sendgrid addon, and my test-app was up and running. Hopefully this can save someone a bit of time.

Monday, February 18, 2013

Turbulence in the asset pipeline

I was running 3.0.20 for a small website and decided it was time to upgrade to the asset pipeline. I didn't require it for this application, but figured it would be good to get some experience.  I also wanted to set the stage for using Twitter Bootstrap. So I figured this past weekend was a good time.

Upgrading to Rails 3.2 was a cake-walk; upgrading to the asset pipeline was another matter. Here's what happened to me in the hopes that it will help other folks.

 To do the upgrade I:

  1. Ran my tests in current app - all green - and made last-minute commits & push to master.
  2. Created a new branch (rails32) so that I could retreat to safety if needed (I was about ready to toss the whole thing at one point).
  3. Went to Ryan Bates' Rails Casts. First episode: Upgrading to Rails 3.2  followed by Upgrading to Rails 3.1. Great stuff! Rails 3.2 without the asset pipeline was up and running in about an hour and worked like a champ: all tests still green.
  4. On to the asset pipeline and another Rails Cast: Understanding the Asset Pipeline. This took a bit more time what with moving things around, but another couple hours or so and ready for testing.
  5. Ran my tests in the new app and still green so it was all looking good until I displayed the app live - that was an awful mess:
    1. Navigation didn't display in the correct location... it was showing up in code sequence rather than being re-positioned to the top of the page
    2. The order of the navigation elements was reversed as was the body display: the left-most columns were displayed on the right, as if someone had done a "reverse" on all the data
    3. The link elements were displaying not only the display text but also the link itself. The link_to helper was working fine and the a elements were perfect... it was just the display that was a mess.
    4. Text elements were overlapping each other in areas.
After many hours of Googling for answers and invoking the help of my friends on the East Bay Ruby Meetup mailing list, and a key post from Billy, I found the answer... actually two of them.

  1. I had to explicitly specify the order of my javascript and css files in the manifest files: application.js and application.css. This meant I stopped using the "//= require_tree ." specification and hard-coded the files I wanted in the order that they had been previously specified. Not only did it get the order right but it also excluded certain elements that were present in the tree that I hadn't been using, such as my jasmine_examples and the myriad of optional blueprint files. That fixed almost everything.
  2. Remaining was the bad display of the a elements. I started removing CSS files one at a time and struck pay dirt on the first one: blueprint/print.css. I've been using this one all along but in the new configuration it was causing the problem. As soon as I removed this file from the mix, I was back to my old display and running the asset pipeline. Whew! I don't know why this code was suddenly causing a problem but I'll deal with that later.
So... what did I learn so that hopefully I don't make the same mistake next time? YAGNI

  • Beware of global options (i.e., //= require_tree .) when upgrading an existing rails app. It may be great for a new app where there's very little to be included, but the cruft that seems to always collect can come back and bite you.
  • As always, take a minimalist approach: include only what you really need and leave the rest for the future
  • Consider adding some tests that would identify this kind of display-centric issue. Not exactly sure how to handle this, but I'll probably at least add a negative test so that if this kind of error shows up again my tests will fail.
There's still the question of installing this in production. I'm running on Heroku and I understand that are some issues to be dealt with there but that'll have to wait for another day.

Thursday, January 31, 2013

ViMemory

There are lots of Vim commands that I use only occasionally and always have to look up. Here they are, all in one place, so that I can find them quickly. Help yourself.

# re-indent an entire file (= is the command)
gg=G 
# show tabs and carriage returns
:set list 
# Change to upper/lower case
gU[movement] or gu[movement]  
# show changes in the current file
:changes 
# jump back to the position of the previous (older) or next (newer) change
 g; or g, 
# Select contents of entire file
ggVG
# Search for word under cursor
*
# Macro recording & playback of single-key macros
qX   # Record macro 'X'
q    # Stop recording
@X   # Play macro 'X'
@@   # Repeat previous macro
# Count occurrences of a pattern (later versions of Vim)
:% s/[pattern]//n
# Did you know that you can use {Ctrl-C} to break out of insert mode? It works just like {Esc} but is easier to type.

#Handling changes to your .vimrc file (Thanks to http://dailyvim.blogspot.com/2008/11/reload-vimrc.html)

# Manually reload your .vimrc file if it has been changed
:source $MYVIMRC  
 # Show your .vimrc filename           
:echo $MYVIMRC               
# automatically update vim when .virmrc changes
:au! BufWritePost $MYVIMRC source $MYVIMRC 

# a collection of neat/quick commands - very useful
ci[c]      # Change the contents of everything 'inside' the [c] delimiters
di[c]      # Delete 'inside' delimiters
[ctrl]i    # Move 'in' to the next jumplist location (:h jumplist)
[ctrl]o    # Move 'out' to the previous jumplist location
[ctrl]=    # Resize all windows to be equal in size
[ctrl]_    # Make active window as large as possible

# There's a really nice, graphical cheat sheet for basic commands at http://www.viemu.com/vi-vim-cheat-sheet.gif

# And finally, there's an awesome, modern book on Vim from the folks at The Pragmatic Programmer: Practical Vim.