Hi, I'm Ben Oakes and this is my geek blog.
Currently, I'm a Software Developer at Hedgeye.
Previously, I was a Research Assistant in the Early Social Cognition Lab at Yale University and a student at the University of Iowa.
I also organize NewHaven.rb.
I do development with Ruby, JavaScript, SQL, HTML, and CSS. I have an amazing fiancée named Danielle Smith.
I recently wrote a comment for “GitHub for Mac: Easier Updates”. Since it sums up my feelings on several subjects (including my feelings about the future of OS X), I thought I should repost it here.
Maybe more people use this than I realize, but I have to say I still don’t get this.
As a web developer myself, I tend to support web-based apps; perhaps the Mac app is popular with Mac/iOS developers? More can be done from the web interface, which works on Windows, Mac, and Linux. (Plus, the web UI always stays up to date.) The only additional feature this really seems to add is a “sync” button locally. Perhaps I’m missing something, but this is all that I take away from the feature list and what I’ve used of it.
To be honest, the direction in which OS X Mountain Lion is headed doesn’t thrill me. Since I’m contemplating a move from OS X back to Linux, it’s disappointing to see an interface for this closed system even being worked on. Such a huge amount of open-source projets are hosted on GitHub (including the Linux kernel itself). If I were to expect Linux support from anyone, it would be you guys. I can understand that OS X is likely a large market for GitHub users, but I would wonder about the portability of this app…
This would be much more compelling if it were an open-source interface for git repos, but I could understand how that might not be in GitHub’s best interest. (But imagine a GitHub tool built by the users, for the users…) Maybe I’m more of a git power user than I realize, but without at least support for a remote other than origin, multiple operating systems, etc., I can’t say this is something I’ll ever use. Making it open-source would be a bonus, although it seems unlikely at this point.
Maybe I’m just missing something, but other commenters here would seem to agree.
Update: By the end of the day, they deleted not only this comment, but many others that cast an unfavorable light on GitHub for Mac. (There was at least one other that had a function named shallWeUseThisSoft.)
In the interest of preservation, here are some other recently added comments that seem likely to be deleted:
Please do not distribute through the mac app store and if possible do not use an apple developer id to authenticate your apps so that we don’t end up with an ecosystem fully controlled by apple (see the gatekeeper non sense they are going to introduce in mountain lion).
Like many web apps, we typically have a need for a staging environment to test before we deploy to production. Combined with continuous deployment, it becomes much quicker and easier to find issues that would affect production by testing in this production-like environment.
This staging environment needs to be as close as possible to production; ideally the only things that are different are the data and some integration points. Having different behavior based on environment makes realistic testing difficult. Different configuration based on environment can also be problematic. In many ways, staging can be thought of as being based on production… but how does that work in pratice?
Rails doesn’t provide a built in idiom for a staging environment (the default environments are just “development”, “test”, and “production”), so many people have come up with their own way of managing the staging configuration problem. Many times the reality is that config/environments/staging.rb is a copied and pasted version of config/environments/production.rb along with some minor adjustments.
That’s ugly.
Here’s a more elegant strategy that we’re trying out:
# File: config/environments/common.rb
OurApp::Application.configure do
# Common configuration goes here
# Example:
config.foo_bar = false
end
# File: config/environments/staging.rb
require_relative './common'
OurApp::Application.configure do
# Any staging-specific configuration goes here.
end
# File: config/environments/production.rb
require_relative './common'
OurApp::Application.configure do
# Any production-specific configuration goes here.
end
This allows us to set a baseline “production” configuration, but still override settings as necessary. It seems to reduce the amount of manual maintenance (“syncing”) of enviroments in the way we were hoping too, so we don’t accidentally let a configuration change go untested until a production deployment.
(Technical info: this was written against Ruby 1.9.2p180 and Rails 3.2.3.)
We’ve been using jsTestDriver (JSTD) along with the Jasmine BDD library via jasmine-jstd-adapter. We’re also using some glue code I wrote called jasmine-jstd-conf which writes a jsTestDriver config file based on jasmine.yml.
Right now, we have some older, mostly-unused machines running a bunch of browsers attached to JSTD. While doing some maintenance today, I had an interesting idea: we need to support the browsers that are popular according to our analytics. That typically means the current and previous version, except for IE, which we support 7.0+ (9.0 is current).
However, we also need to support the next version of any popular browser. Since Chrome and Firefox both have a beta channel of what is likey to be released as the next version, we can easily test whether any of our JavaScript will break in the new version of those browsers before they’re released and before a user runs into a problem we could have detected earlier.
So, we now have Chrome 16, 17 (current), and 18, along with Firefox 9, 10 (current), and 11.
Here’s some sample JSTD output from a Jasmine test suite we have:
Chrome 16.0.912.77 Windows: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (267.00 ms)
Chrome 17.0.963.56 Mac OS: Run 100 tests (Passed: 100; Fails: 0; Errors 0) (318.00 ms)
Chrome 17.0.963.56 Windows: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (196.00 ms)
Chrome 18.0.1025.39 Mac OS: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (209.00 ms)
Firefox 9.0.1 Mac OS: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (681.00 ms)
Firefox 9.0.1 Windows: Run 50 tests (Passed: 49; Fails: 1; Errors 0) (1598.00 ms)
Firefox 10.0 Windows: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (293.00 ms)
Firefox 10.0.2 Mac OS: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (260.00 ms)
Firefox 11.0 Mac OS: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (368.00 ms)
Microsoft Internet Explorer 7.0 Windows: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (2749.00 ms)
Microsoft Internet Explorer 8.0 Windows: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (2078.00 ms)
Microsoft Internet Explorer 9.0 Windows: Run 100 tests (Passed: 100; Fails: 0; Errors 0) (698.00 ms)
Safari 534.52.7 Mac OS: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (1553.00 ms)
Safari 6533.18.5 iPhone OS: Run 50 tests (Passed: 50; Fails: 0; Errors 0) (184.00 ms)
With that many JavaScript implementations to support, writing automated tests only makes sense.
We recently noticed that Airbrake doesn’t always filter our parameters.
I looked into the cases, and eventually narrowed it down to this: an unhandled exception is filtered properly, but a notification made via notify_airbrake does not.
def airbrake_filter_if_filtering(hash)
return hash if ! hash.is_a?(Hash)
if respond_to?(:filter_parameters)
filter_parameters(hash) rescue hash
else
hash
end
end
After doing some research, I found that filter_parameters is a Rails 2 method that has since been replaced by ActionDispatch::Http::ParameterFilter. There are other methods used in Airbrake are deprecated by Rails. For example filter_parameter_logging (found in test/catcher_test.rb) disappeared after Rails 2.3.8.
I attempted to add a test for my changes, but couldn’t reproduce the problem using the available helpers in test/catcher_test.rb, although the problem clearly exists in our production use. As near as I can tell process_action_with_manual_notification may not actually be testing in a realistic way; there seem to be at least two ways that Airbrake filters parameters. If I’m missing something, please point me in the right direction.
At any rate, the changes in this pull request fixes the problem when I tested on a staging environment. Our app is using Ruby 1.9.2p180 and Rails 3.1.2 at the time of this writing.
Ruby’s autoload works fine if you’re using it in a gem that’s loaded once (and need to use it on Ruby 1.8, vs. require_relative in Ruby 1.9+), but if autoload is used in a collection of Ruby classes or modules in a folder that’s in the Rails load path, then it’s probably not a good idea. You’ll get unexpected reloading behavior, at a minimum. That applies to submodules too, of course.
In general, you don’t want to mess with $LOAD_PATH, which was a fairly common practice in 1.8. That’s largely gone away in 1.9 with the advent of require_relative, but many gems need to be backwards compatible. In Ruby 1.8, you can always futz around with __FILE__, but that gets messy as well.
We have a project that accesses a shared database. To prevent problems (and confusion) we wanted to block the creation of migrations in the “secondary” applications so that there was one authoritative place for migrations to live.
It’s easy to accomplish in a simple way.
If you’ve never made any migrations in the secondary application, just do this:
$ echo "NOTE Please do not make migrations in this project. They should all live in _primary app_." > db/migrate
That way, when you run rails g migration foo, you’ll get this:
We recently had a need to use Heroku with an external MySQL database. Thankfully, there was already a gem that solved the problem. However, it didn’t have that much by the way of documentation, so I wrote this up and contributed it to the author. Also, I added X.509 support, which we required.
NOTE: After my pull requests are merged, you should look to the main repository’s README which has a copy of the below.
Example: MySQL with a CA Certificate
In this example, we are setting up a connection to an external MySQL server using the default initializer.
What we have:
A CA certificate called ca-cert.pem
A database is available at mysql://username:password@server/dbname (where username, password, server, and dbname are the appropriate values for our server)
Other security, e.g. firewalls. Please make sure to open the appropriate ports and grant the necessary access for your database to be available externally. Further discussion is outside the scope of this document, but for accessing EC2, you might start at devcenter.heroku.com/articles/external-services.
First, we configure Heroku with the appropriate environment variables:
# You may have to specify the app name or remote name here via --app or --remote, respectively
heroku config:add EXTERNAL_DATABASE_CA='ca-cert.pem'
heroku config:add EXTERNAL_DATABASE_URL='mysql://username:password@server/dbname'
By default, heroku_external_db looks for the CA cert in config/ca, so we need to commit it:
mkdir -p config/ca
cp path/to/ca-cert.pem config/ca
git add config/ca
git commit -v # Using -v since we want to make sure the contents are what we expect (e.g. not a private key)
Additionally, we need the mysql gem in our Gemfile since we are setting up a MySQL server:
echo "gem 'mysql', '~> 2.8.1'" >> Gemfile
bundle install # Need Gemfile.lock too
Keep in mind that Heroku installs its own database.yml for Rails apps and we have to install pg as well. Unfortunately, shared databases are mandatory (but are free).
$ heroku addons:remove shared-database:5mb
-----> Removing shared-database:5mb from our-app... failed
! Shared databases cannot be removed
PostgreSQL may still be useful to you if, for example, you want to have feature toggles in a local database, but the main data kept externally. However in our case, it also means all developers will need MySQL and PostgreSQL running locally, which is unfortunate.
One workaround is only installing pg in production:
# File: Gemfile
# *Only* needed on production.
group :production do
gem 'pg', '~> 0.11.0' # Regardless of whether you plan to use the database or not, Heroku requires you have 'pg' installed.
end
With our dependencies out of the way, we can move on to testing the connection.
If you are making a new application, you may wish to have a simple MVC for testing that the connection works. E.g., for a blog style application with posts do:
rails generate scaffold post
# NOTE you probably want to change the default "Post.all" to "Post.limit(5)" or something similar
git add .
git commit # ...
# Don't forget to set a default route, etc.
With all these changes committed, we can deploy to our Heroku app:
git push heroku master # Your remote may be different
Now, since we are connecting to an existing database, we don’t need to run any migrations. (Keep in mind that when sharing a database, it is best to have one authoritative source for migrations to live.) If in your situation you’re creating a new database, you may need to do that, run migrations, seed the database, etc at this point.
Open our-app.heroku.com and we should see our data. If you happen to run into a problem, please check the logs first:
heroku logs --tail # Again, you may need to specify an app
If you are having a problem, a good starting point is double checking your passwords, usernames, security settings, etc.
Example: MySQL with X.509
The process is very much the same as the above example, except two extra environment variables and files are required. Below are the extra steps.
What we have:
A CA certificate called ca-cert.pem
A client certificate called client-cert.pem
A client key called client-key.pem
First, we configure Heroku with the appropriate environment variables:
RubyConf 2011 was a blast. It was great to meet other Rubyists, get a ton of T-shirts (no really, I got 8 or so), and talk Aaron Patterson into giving Jonathan Magen a special message.
If you weren’t able to go, I pushed my notes up to a public GitHub wiki. A couple others from Hedgeye are adding their notes as well, so with those (plus the Confreaks videos when those guys finally have access to a reliable Internet connection), it’s almost like you were there.
We have a simple application that doesn’t have an ActiveRecord dependency. It’s deployed to Heroku, and it’s been working fine on Rails 3.0.x since April 2011. We knew we weren’t using ActiveRecord for database connectivity, but we let it be, since it wasn’t causing any issues.
When upgrading to Rails 3.1, we found that every single page would give ActiveRecord::ConnectionNotEstablished on our staging environment on Heroku. The same error didn’t happen in development. Although we might have been able to get gem 'pg' set up and working, we really didn’t need an ActiveRecord dependency at all.
That’s what Rails 3.1.0 generates when running rails new myproject --skip-active-record. (Note that require "active_record/railtie" is commented out.) This solved our ActiveRecord::ConnectionNotEstablished problem, but gave us a few others, namely:
Fixtures
ActiveRecord::RecordNotFound (used for 404s)
Fixtures
There’s some normal stuff to get rid of in terms of spec_helper.rb and/or test_helper.rb. Here’s an example:
# File spec/spec_helper.rb
# # If you're not using ActiveRecord, or you'd prefer not to run each of your
# # examples within a transaction, remove the following line or assign false
# # instead of true.
# config.use_transactional_fixtures = true
You may have others. Tarantula had to be adjusted for us, for example.
ActiveRecord::RecordNotFound
ActiveRecord::RecordNotFound, however, was an interesting problem. Everything worked fine without ActiveRecord except the places where we were using ActiveRecord::RecordNotFound to give a HTTP 404 to the user agent. That seems strange in a lot of ways, because a 404 shouldn’t have anything to do with your chosen ORM. My first intuition was to do require 'active_record/errors' (see also the Rails docs), but that caused problems with assumptions in 'rspec/rails'.
Right now, the below is what we ended up with:
# File: config/application.rb
# Pick the frameworks you want:
# require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "sprockets/railtie"
require "rails/test_unit/railtie"
# For errors like ActiveRecord::RecordNotFound
require "active_record"
Our automated tests (Rspec, integration tests, Tarantula, Selenium, etc) all pass with it and we no longer get ActiveRecord::ConnectionNotEstablished, but we still have an ActiveRecord dependency I don’t like. (There must be another error we can raise — I don’t entirely like the render '/404.html', status: 404 solution for several reasons.)
According to the Application Helpers guides, you probably want distance_of_time_in_words or time_ago_in_words.
Example:
%p
= time_ago_in_words(my_date)
ago
For reasons I don’t quite understand, this documentation is also incorrect:
time_ago_in_words(2.days.ago) => "2 days ago"
The actual behavior is:
time_ago_in_words(2.days.ago) => "2 days"
I’m planning to move some of this into the padrino-framework project directly. Incorrect documentation is worse than no documentation; maybe it will be more accurate if kept in the code. :)