Using HTTPS Locally: Pow, SSL, Rails, and Apache

Using HTTPS local development or testing environments is a hassle. A common practice is to disable SSL in development, but I’ve had too many cases of minor bugs creeping in when routing works differently between environments. I also don’t like manually having to let my browsers know that a self-signed certificate is valid.

Here’s the configuration that I use to easily add https support on my development machine to any application served—or proxied—through port 80.

Pow

I use Pow as my development rails server. However, because I often work with other languages as well, I run Apache (you could just as easily use nginx) and reverse proxy Rails application requests to Pow.

To do this, you’ll need Pow to bind to a port that is not port 80. Here’s how to configure Pow to use port 88.

Apache

I use nginx in production environments, but I’ve been using Apache on my local development machines for years and just haven’t gotten around to changing my dotfiles to use nginx. You could just as easily use nginx here.

In any case, here’s what I was looking to achieve in my apache config:

Throw error logs in ~/Sites/logs Support vhosts + xip.io domains Access WordPress sites using site-name.wp.dev Access Rails applications using site-name.dev. These requests need to reverse proxy to pow on port 88. Support proxying *.test domains to a customized port. Having a *.test domain allows you to run SSL-enabled integration tests for a multi-domain Rails application against the rspec-run rails server. Checkout my series on rails testing for more details on why this is important.

I was able to get all of this working with a single file thrown in /etc/apache2/other.

Rails: Tunnelss to the Rescue

Tunnelss is a little gem that brings it all together. It looks at your pow config, generates self-signed certificates for those domains, and adds that certificate to your keychain so your browsers accept the self-signed certificate. Brilliant.

The only downside here is you must keep tunnelss running in the background. Right now, the project doesn’t have a launchd plist available. So, for now, you have to start the application manually on each system restart.

Continue Reading

Multi-Engine Rails 3.2 Testing Tips & Tricks, Part 3

This is a continuation of my second post on setting up a CI server for a multi-engine rails 3.2 application.

Use `Pry.rescue {}` For Dynamic `binding.pry`

Getting access to an interactive REPL is essential when debugging a web application. Better Errors does a great job when when interacting with the app directly (in rails4 this functionality comes built in). binding.pry is a great tool when interacting with your code directly in your development or testing environment.

However, there are some cases where adding binding pry to just the right place is either painful or would require you to modify a external gem. An easy way to get around this is to use pry-rescue which will open a pry REPL wherever an exception occurs. This is especially helpful for debugging rake tasks.

Run Rails Server in Test Environment to Debug Hard-to-Replicate Issues

Sometimes I’ve run into issues that I can’t reproduce in development or staging. It’s been helpful to startup a rails server using the test environment to debug issues outside of the content of a specific spec:

bundle exec rails s -e test # if you have a test_app cd spec/dummy bundle exec rails s -e test Use Test Server Static Port Assignment for Absolute URL Dependent Functionality

If you use premailer with a CSS stylesheet, the external stylesheet reference must be absolute (at least, in the version of premailer the app is using).

Additionally, sometimes there is functionality which require the host name of the app to be set via a configuration preference (e.g. Spree Commerce with Spree::Config.set(:site_url, "domain.com")).

Capybara defaults to starting up a testing web server on a random port. This causes issues if you need to set a site wide configuration preference: you don’t know what the port is until the server is running.

I’ve found it helpful to set Capybara to use consistent port:

Capybara.server_port = 8081 Take a Screenshot of Feature Test State on Failure

Use capybara-screenshot to save a screenshot of what the page looked like that triggered the error. In addition to a PNG, a HTML file is also generated. I’ve found this to be very helpful in debugging feature tests.

# spec_helper.rb # disable by default Capybara::Screenshot.autosave_on_failure = false RSpec.configure do |c| c.before(:each, type: :feature) do Capybara::Screenshot.autosave_on_failure = example.metadata[:screenshot] end end

Check out this article for more information.

Increase Capybara Wait Time

In my testing enviornment I run all delayed jobs synchronously in order to test the results of backgrounded operations. This means that requests sometimes have to wait on slow external services or connections. Without increasing the default timeout setting, you’ll get errors from capybara:

Capybara.default_wait_time = 10 Nil Out User Generated Paper Clip File Upload References

Some of the seed data I extracted from the live application had paperclip attachment data. Here’s how to wipe it out quickly:

# seeds.rb Spree::Asset.update_all attachment_file_name: nil, attachment_content_type: nil, attachment_file_size: nil, attachment_width: nil, attachment_height: nil

If you need an image in place, set a default image:

# spec_helper.rb Spree::Image.attachment_definitions[:attachment][:default_url] = "http://placehold.it/460x260" Dotenv

If you have unit tests in your applications’ engines repositories, and you are using the 12 factor app structure, you are going to need to load the .env file from the parent directory.

# sub_engine/spec/spec_helper.rb if ENV['CIRCLECI'].nil? || ENV['CIRCLECI'] != 'true' require 'dotenv' Dotenv.load! '../.env' end

Continue Reading

Automated Tests on Multi-Engine Rails 3.2 App, Part 2

This is a continuation of my first post on automated testing a large rails app.

Setting up the Continuous Integration Server Configuration

In most cases your CI server setup is pretty trivial, some aspects of the apps setup made it a little more challenging:

I use submodules that reference private repositories The engines that make up the app have their own unit tests All of the engines depended on Spree Commerce, which meant they needed to run test_app to execute properly There were a couple custom rake tasks I needed to run before running tests checkout: post: - git submodule sync - git submodule update --init dependencies: post: - cd engine1; bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3 - cd engine2; bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3 database: post: - bundle exec rake db:seed app:custom1 app:custom2 test: pre: - cd engine1 && bundle exec rake test_app - cd engine2 && bundle exec rake test_app override: - cd engine1 && bundle exec rspec - cd engine2 && bundle exec rspec - bundle exec rspec

minimize external system dependencies

Toggle Between Selenium and WebKit

Selenium helps me code & debug feature tests by letting me open up binding.pry in the test and interact with a Firefox instance. WebKit executes tests much faster.

I wanted both, and wanted the ability to switch between the two easily.

Here’s the Gemfile:

group :test do gem 'capybara', '~> 2.2.1' gem 'capybara-screenshot', "~> 0.3.17" gem "selenium-webdriver", '~> 2.44.0' gem "capybara-webkit" end

Here’s the rspec snippet you’ll need to load in spec_helper.rb:

RSpec.configure do |c| c.before(:each, type: :feature) do Capybara::Screenshot.autosave_on_failure = example.metadata[:screenshot] if example.metadata[:selenium].present? || ENV["SELENIUM"] == "true" Capybara.current_driver = :selenium_firefox_driver else Capybara.current_driver = :webkit end end end # Register the selenium firefox driver Capybara.register_driver :selenium_firefox_driver do |app| profile = Selenium::WebDriver::Firefox::Profile.new Capybara::Selenium::Driver.new(app, :browser => :firefox, :profile => profile) end

To run the tests with selenium just set the ENV var:

export SELENIUM=true

Or, better yet, use dotenv and put in .env.

If you used cask to install Firefox you’ll need the following snippet:

firefox_cask_path = '/opt/homebrew-cask/Caskroom/firefox/latest/Firefox.app/Contents/MacOS/firefox-bin' if File.exists?(firefox_cask_path) Selenium::WebDriver::Firefox::Binary.path = firefox_cask_path end Conditionally Raise Exceptions in Tests

By default the test environment does not raise exceptions. When something goes wrong, you don’t get a stack trace. I wanted to toggle this functionality to debug tests; here’s what I did:

# config/environments/test.rb config.action_dispatch.show_exceptions = ENV['RAISE_EXCEPTIONS'] == "true" Output Current File and Line when Running RSpec Tests

Originally pulled from this StackOverflow post:

RSpec.configure do |c| c.before(:each, js: true) do |s| md = s.example.metadata x = md[:example_group] puts "=> #{x[:file_path]}:#{x[:line_number]} #{md[:description_args]}" end end

Continue Reading

Setting up CI for a Multi-Engine Rails 3.2 Application

I recently setup continuous integration (via CircleCI, which I’m really impressed with). It ended up being a bit more tricky for a couple of reasons:

I needed to pull semi-static seed data into the application. For this app, this was product data that isn’t changed often and is pulled from an external system. I wanted to use seed data from the production database because the integrity of the data in the external DB couldn’t be trusted and I wanted to ensure that if the tests passed it was a real representation of if the app would function in the live environment. There were a number of custom rails engines that app was compromised of. Each of these engines had separate unit tests, but not separate integration (feature) tests. The view layer had too many dependencies on the host app to separate out the feature tests. The migrations for each of the engines were inside the engine folder using this trick. I wanted the ability to visually debug feature test via the selenium capybara driver, but I wanted the speed of `capybara-webkit` For whatever reason, the `seed_dump` and `seed_dumper` gem was not working on this 3.2.x app There is a bunch of persistent app-wide configuration settings I needed to set via a rake task Use SQL Dumps for Seed Data

After not being able to get seed_dump extracting data from the development database, I decided on using SQL dumps for seed data. Here are the benefits:

It’s easy to update the data, just run a DB table export The relationships between various models are maintained (this was very important for this specific project, the eCommerce product model was fairly complex) Not dependent on a gem to update the data in the future

The engineer in me doesn’t like the fact that running tests are dependent on non-factory test data, but when dealing with an external data source that has data integrity issues, it’s the most robust way to test that your app will hold up in the wild.

I found a seeds.rb SQL import snippet and expanded upon it to dynamically load in any SQL files in db/seeds/:

unless Rails.env.production? # country and state seed data Spree::Core::Engine.load_seed if defined?(Spree::Core) # https://github.com/spree/spree_auth_devise/blob/1-3-stable/db/default/users.rb ENV['AUTO_ACCEPT'] = 'true' Spree::Auth::Engine.load_seed if defined?(Spree::Auth) # don't export table structures or schema_migrations table; that is handled by load:schema Dir[File.join(Rails.root, "db/seeds/*.sql")].each do |sql_file| sql = File.read(sql_file) puts "Reading seed: #{sql_file}" connection = ActiveRecord::Base.connection # AR can only manually execute one statement at a time statements = sql.split(/;$/) statements.pop ActiveRecord::Base.transaction do statements.each do |statement| connection.execute(statement) end end end # nil out the user generated paper clip attribute Spree::Author.all.each do |a| a.update_attribute :photo, nil end end Rake Task Execution Order for Database Setup

I had a couple custom rake tasks I needed to run to setup my test environment. However, some of those rake tasks required the database schema to be setup for some of rails accessors that are determined by the database schema to be created.

I found that running multiple rake tasks in a single rake command does not trigger a model refresh if the DB schema changes. Run the rake task in a separate bash command to pick up the updated schema:

rake db:drop db:create db:schema:load --trace RAILS_ENV=test rake db:seed custom:configure RAILS_ENV=test --trace Add Engine Migration Paths to ActiveRecord::Migrator

I’ve been adding the db/migrate path in my child engines to my parent engine in order to keep my codebase DRY.

With the following snippet in place running db:schema:load would trigger migration errors. The database schema/creation logic wasn’t picking the migrations inside the engines although db:migrate ran them just fine.

After some digging I found the magical configuration tweak to fix the issue:

initializer :append_migrations do |app| unless app.root.to_s.match root.to_s app.config.paths["db/migrate"] += config.paths["db/migrate"].expanded ActiveRecord::Migrator.migrations_paths += config.paths["db/migrate"].expanded end end

That’s it for now, stay tuned for part 2!

Continue Reading