Posts tagged ruby
Multiple Ruby Version Support on Heroku
Starting today Heroku will allow you to specify a version of Ruby in your production app. As one of the most requested features we have been asked for time and time again, we’re happy to announce that it’s now live. To get started you’ll want to update your version of Bundler locally to version 1.2.0, or above.
This is a re-post of an Article I wrote for the Heroku Blog
$ gem install bundler --pre
Then you’ll want to specify the version of Ruby you want to use in your application inside of your Gemfile. For example if we wanted to use Ruby 1.9.3 in our production application you would want to include ruby '1.9.3' inside of your Gemfile. In a rails Gemfile it might look something like this:
source 'http://rubygems.org'
ruby '1.9.3'
gem 'rails', '3.2.3'
Once you’ve added ruby to your Gemfile, commit it to git
$ git add Gemfile
$ git commit -m 'use Ruby 1.9.3 on Heroku'
Then you’ll want to deploy your app
$ git push heroku master
Once your application is done deploying you will be able see the version of Ruby you are using is 1.9.3.
$ heroku run bash
$ ruby -v
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-linux]
It’s that simple!
With this new feature you can also use this process to call a specific version of Ruby other than 1.9.3, however, if it is not installed on the Heroku system you’ll receive an error.
Production and Development Parity
At Heroku, we strongly believe that there should always be a strong parity between development and production environments in order to minimize any surprises. When the tooling of your development environment most closely matches your production environment, there is far less room for error. Another good example of keeping parity between dev and production environments would be running PostgreSQL locally in the development environment instead of SQLite since you’re production system is running Postgres on Heroku.
While there are other reasons you may want to use different versions of Ruby in certain scenarios including performance issues or to access version-specific Ruby features, developers should overall strive to use the same tools and versions of software for development as are used for production.
Patch Versions
While you can now specify the version of Ruby you would like your web application to use, at this time we do not support that ability to request a specific patch version to be called, such as Ruby 1.9.2-p290. Ruby patches often include important bug and security fixes and are extremely compatible. While you can specify the version of Ruby you wish to use, Heroku will provide the most secure patch level of that version.
Debugging
If you’ve followed all the steps above and you’re still seeing a different version of Ruby than you need, please recheck your path.
$ heroku config
PATH => vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:/bin:bin
RACK_ENV => production
# ...
You need to ensure that bin is in front of your path so you could change the above to
$ heroku config:add PATH=bin:vendor/bundle/ruby/1.9.1/bin:/usr/local/bin:/usr/bin:/bin
As a tip, It is a good idea to use the free releases feature whenever you are modifying your ‘config’ in case you need to roll back to a previous version of Ruby.
Thanks
Thanks to Terence Lee Heroku Ruby team member and bundler maintainer for the additional support of ruby versions to the Heroku Ruby Buildpack and orchestrated the release of Bundler 1.2.0. Also thanks to Yehuda Katz and the entire Bundler team for helping get this release out the door.
Give this feature a try and let me know what you think @schneems!
Wicked Gem Featured on Railscasts
Wicked was featured by Ryan Bates on Railscasts this past week. I’ve learned quite a bit over the years from Railscasts, so it’s a great honor to have my work featured there.
Legacy Concerns in Rails
The cats out of the bag, Ruby isn’t immune to legacy code problems. Just because your app is written in a hip, fun, and dynamic language doesn’t mean that your codebase can’t stagnate, bloat, and quickly turn into an unmaintainable ball of mud. Before Gowalla was purchased by Facebook, the Rails code base stood at close to seven thousand files, with the largest model clocking in at around 3,500 lines of code. While we were somewhat unique, being originally written in Merb and then ported to Rails, applications of this size aren’t all that uncommon. If you’ve got a large app there are a number of things you can do make your situation better, one of the simplest with the greatest impact is splitting up models into concerns.
If you’re not familiar with concerns, you can read up about them at Concerned about Code Reuse?. Go ahead, we’ll wait.
Rails has long advocated a thin controller, fat model approach to development, which works great early but can lead to a model obesity epidemic. If we split out our models into different concerns we can group related code, and even make re-using code between projects easier. Best of all, if you start early on it’s a pretty painless process.
The User Model
There’s only two businesses that refer to their customers as ‘users’ and software is one of them. It’s also bound to be one of the largest models in your app since so much will likely need to be connected to a user. It’s a good place to start splitting up a model into a concern. Lets say that we want to add some methods on our user object so they can access Facebook information we can start by creating a new file app/models/user/facebook_methods.rb (you’ll need to create the user folder).
This file is where we’ll group all of our methods related to Facebook. For this example i’ll be using the Koala Facebook gem, and we assume our user model has a facebook_token attribute persisted to the database.
module User::FacebookMethods
extend ActiveSupport::Concern
def facebook_graph
@facebook_graph ||= Koala::Facebook::API.new(facebook_token)
end
end
Not a bad start, now we want to add this ability to our user model, open up app/models/user.rb and add our concern.
class User < ActiveRecord::Base
include User::FacebookMethods
end
Great! Now we can construct our Facebook graph object straight from our user.
user = User.where("facebook_token is not null").first
user.facebook_graph
# => <# Koala #...
user.facebook_graph.get_connections("me", "friends")
# => {52930 => 'Terence Lee', 12345 => "Ruby Ku" #...
That Was Easy, but…
What did that buy us? First we’ve got an obvious place to store our code. Want to write a method that pulls out all of a user’s Facebook friends? Put it in the facebook_methods.rb file. If you forget the name of that method, check out your Facebook methods. If you need the facebook_graph method, bet you money it’s in that concern. If all related code is in one place its a lot easier to scan visually and to search for keywords.
Won’t This add More Code to the Codebase?
In the example above, we added 4 extra lines of code to save us 3 measly lines in our user.rb file. While this isn’t ideal for such a small concern, as it grows in size its much easier to keep track of the components, which in turn helps keep your code small and manageable. It also nudges developers to create unit tests for those specific concerns. This sounds minor, but when you get to a file with 3500 lines of code, you start duplicating functionality that you didn’t know existed. Either it was added by another developer, or you forgot you added it months ago. Keeping everything in its place helps keep your code sane.
How Should I Break up My Code
Often times I like breaking out my concerns based on knowledge of third party services. For example I broke out a concern for all the Facebook methods above. I use websolr and I like having a separate concern for all the search related methods. Recently I played around with the Ice Cube gem which is a library for creating an iCal formatted recurring date syntax. I split that code out into a concern, not because it was touching another service, but because I might want to re-use that code in another model some day, and it’s easier to break out the code now. There are no hard and fast rules, just don’t go overboard and have 100 concerns for every model with 3 lines of code in each of them, and on the flip side don’t have one concern with everything.
Just think of the different areas of ‘concern’, that your code covers. Get it?
Legacy Code
While building out the final version of the Gowalla service we managed to promote Redis and Cassandra to first class data storage citizens, completely re-write all web controllers, and split out a brand new api into a separate set of controllers (more on this in a later date). It was a ton of work, we were completely changing the way our service worked and creating new paradigms such as a “Stories” where multiple users could check each other in and at the same time, we still had to support a ton of 3rd party client applications using the old API.
So, how did concerns help? We used concerns to isolate new code and new services. It also helped us to add more & better unit testing by focusing different spec files on different areas so models/users/following_methods.rb would be tested by spec/models/users/following_methods_spec.rb. Most of the developers used some form of automatic test runner such as Guard Rspec, and it is nice being able to run only the unit tests associated with the concern you’re writing without having to run all the unit tests for that model.
Bonus! Ever find a method that you were pretty sure wasn’t being called by anything. Maybe it’s in a model that wasn’t exactly 100% tested. You could try making a concern for methods of questionable value. In a month if it’s still there, delete the sucker, deploy to staging, validate and commit to master.
Shared Concerns
If you have code that needs to be shared by multiple models in your project, you can keep this in your lib folder. I actually like to have a concerns folder like lib/concerns/models/duplicate_code.rb. When we added Cassandra to the Gowalla project we needed a way to get our Postgres models to play nice. Thats when Adam Keys and Bill Doughty pulled out common logic and put it into a concern using another library called Chronologic. lib/concerns/models/chronologify.rb
Then any time you wanted this shared code into your model, you just had to include it.
# models/checkin.rb
class Checkin < ActiveRecord::Base
include Concerns::Models::Chronologify
end
Don’t forget to add the concern folder in your lib to your search path.
Wrap it Up
There have been tomes written about dealing with legacy code in software, I’ve been recently recommended Working Effectively with Legacy Code . Using concerns won’t be a magic bullet, but it will help keep your code nicely organized. Even if you’re dealing with a pristine new app, concerns are one way to help it stay that way. Give concerns a try and let me know if you have a good or bad experience @schneems.
Concerned about Code Reuse?
Right out of the gate, Ruby gives us some powerful ways to re-use instance and class methods without relying on inheritance. Modules in Ruby can be used to mixin methods to classes fairly easily. For example, we can add new instance methods using include.
module DogFort
def call_dog
puts "this is dog!"
end
end
class Dog
include DogFort
end
Now we’re able to call any methods defined in our DogFort Module as if they were simply slipped into (included) into our Dog class.
dog_instance = Dog.new
dog_instance.call_dog
# => "this is dog!"
Using Modules a fairly easy way to re-use methods, if you want you can extend a Module to add methods to a class directly.
module DogFort
def board_the_doors
puts "no catz allowed"
end
end
class Dog
extend DogFort
end
Now if we were to call Dog.new.board_the_doors we would get an error, since we’ve added it as a class method instead.
Dog.board_the_doors
# => "no catz allowed"
Dog.class
# => Class
Sweet! Though what if you wanted to add an instance method and a class method to a class. We could have two Modules, one to be included and one to be extended, wouldn’t be to hard but it would be nice if we only had to use one include statement, especially if the two Modules are related. So is it possible to add instance and class methods with only one include statement? Of course…
Enter Concerns
A concern is a Module that adds instance methods (like Dog.new.call_dog) and class methods (like Dog.board_the_doars) to a class. If you’ve poked around the Rails source code you’ll see this everywhere. It’s so common that Active Support added a helper Module to create concerns. To use it require ActiveSupport and then extend ActiveSupport::Concern
require 'active_support/concern'
module DogFort
extend ActiveSupport::Concern
# ...
end
Now any methods you put into this Module will be instance methods (methods on a new instance of a class Dog.new) and any methods that you put into a Module named ClassMethods will be added on to the class directly (such as Dog).
require 'active_support/concern'
module YoDawgFort
extend ActiveSupport::Concern
def call_dawg
puts "yo dawg, this is dawg!"
end
# Anything in ClassMethods becomes a class method
module ClassMethods
def board_the_doors
puts "yo dawg, no catz allowed"
end
end
end
So now when we add this new Module to a class, we’ll get instance and class methods
class YoDawg
include YoDawgFort
end
YoDawg.board_the_doars
# => "yo dawg, no catz allowed"
yodawg_instance = YoDawg.new
yodawg_instance.call_dawg
# => "yo dawg, this is dawg!"
Pretty cool huh?
Included
That’s not all, Active Support also gives us a special method called included that we can use to call methods during include time. If you add included to your ActiveSupport::Concern any code in there will be called when it is included
module DogCatcher
extend ActiveSupport::Concern
included do
if self.is_a? Dog
puts "gotcha!!"
else
puts "you may go"
end
end
end
So when we include DogCatcher in a class it’s included block will be called immediately.
class Dog
include DogCatcher
end
# => "gotcha!!"
class Cat
include DogCatcher
end
# => "you may go"
While this is a contrived example, you can imagine wanting to maybe make a concern for Rails controllers and wanting to add before_filter’s to our code. We can do this easily adding the included block.
Is this magic?
Nope, under the hood we’re just using good old fashioned Ruby. If you want to learn more about all the fun things you can do with Modules I recommend checking out one of my favorite Ruby books Metaprogramming Ruby and Dave Thomas also has a fantastic screencast series.
Gotcha
When you’re writing Modules I guarantee that you’ll slip up and accidentally try to create a class method using self or class << self but it won’t work because it’s now a method on the Module.
module DogFort
def self.call_dog
puts "this is dog!"
end
ene
In the example above the context of self is actually the Module object DogFort so when we include it into another class we won’t see the method.
class Wolf
include DogFort
end
Wolf.call_dog
# NameError: undefined local variable or method `call_dog'
wolf_instance = Wolf.new
wolf_instance.call_dog
# NameError: undefined local variable or method `call_dog'
If you want to use that method in this context you will need to call the Module directly
DogFort.call_dog
# => "this is dog!"
puts DogFort.class
# => Module
Fin
That’s all for today, in my next post I’m going to show you how to clean up your legacy code base with concerns. Let me know if you have any questions @schneems!
You may also be interested in Concerning Yourself with ActiveSupport::Concern, Concerns in ActiveRecord and Better Ruby Idioms.
Performance Testing Rails with BlitzIO
Haven’t you always wanted to make some changes to your server and then absolutely slam it with traffic to see the result? Thats pretty much what I did last week while writing how to Super Charge your Rails App with Rack Cache, using the BlitzIO tool.
If you’re interested in trying out Blitz watch a demo in the screencast below.
For a walkthrough on how to add Rack::Cache and Memcache to your server read my performance article on the Heroku Dev Center.
Learn Ruby with Hourschool
I’m teaching a beginner ruby class. If you’ve ever been interested in learning Ruby this is a hands on class with no experience and no software required. Class is this Wednesday the 15th at 7pm in downtown Austin.
If you’ve never taken a class at Hourschool before, it’s a peer-to-peer learning platform that lets anyone teach and take classes. It’s been a fun way to meet people in the community and pick up some skills too. Even if you’re not into programming they’ve got lots to offer, from cooking to color design. Forget going to a boring movie next week, learn how to make bagels with real live people instead !!
P.S. Hourschool runs on Heroku and I helped build it (in Ruby of Course)!
Speed up Capybara Tests with Devise
All good developers should write tests, and anyone with a high stake in a web app should write acceptance tests. Acceptance tests use a web driver like Capybara to test the full functionality of your web app by interacting directly with view elements the same way a user would (clicking links, filling out forms, etc.)
My only problem with acceptance tests is that they can be a bit slow, so i’m always looking for ways to speed mine up. One of my pain points is since everything is done via manual interaction with a headless website, any test requiring a logged in user (most of them) also requires that before it is run, Capybara must log the user in by visiting the sign in path and entering valid credentials. While I still think manual sign in should be tested, it doesn’t need to be tested every single time we run another test.
If you’re doing authentication with Devise to speed things up a bit we can stub out a logged in user with Warden’s built in test helpers.
It works like this when you’re running a non-acceptance test we want to use Devise’s sign_in helper since we have direct access to the request object (not available during capybara/acceptance tests). All other times we want to use Warden’s login_as method.
Here is an example of as_userand as_visitor helpers that do just that:
I then needed to call Warden.test_reset! after each test to ensure correct functionality
RSpec.configure do |config|
config.after(:each) { Warden.test_reset! }
end
Then in my tests (shown here with capybara/rspec, I can simply log in a user like this:
It’s that simple. With a few lines of code I was able to speed up my tests and keep all expected behavior. For more details on how this works, you can go to the wiki page I created: https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara . Good luck and happy testing!
Keep your Rails Project Sane
We’ve all been there, we start a new project with grand hopes and aspirations. But soon enough our project turns into one big ball of mud. In this presentation I talk about some common mistakes in Rails and how to keep your project Sane.
I gave this presentation at Austin On Rails and it was filmed by Austin Tech Videos.
Help Me, Help Rails
Rails needs controller level filter logging and Im submitting a patch to Rails core, but first I want some feedback. Let me know if you like it, hate it, or don’t understand it. All comments welcome, especially alternative implementation & style.
Please let me know what you think, please leave comments on the original gist: https://gist.github.com/1443757
Likeable: Love your Objects with Redis
This is a re-post of an article I wrote for Gowalla’s Engineering Blog. You can view the original article here.
Likeable is a new open-source Ruby library that we built here at Gowalla to power all of the “loves” on stories, comments, highlights and photos that you see. It’s built on top of Redis to be extremely simple, isolated and fast. Likeable plays well with ActiveRecord objects, but can be used with any Ruby object that implements an #id method.
To see it in action, head over to my Gowalla profile and love the first thing you see. Immediately you’ll see the heart change colors and the love count increase by one. If you click on that number you’ll see everyone who has loved that object.
This might seem trivial at first glance. But consider that dozens of elements on the page must pull this information: how many people have loved it, whether the viewer has loved it, and (on some pages) which of your friends have loved it. Using Redis allows us to stay simple, flexible and fast.
The Code
Let’s say we’ve got a comment made on a recent Gowalla story.
@comment = Comment.last
@comment.like_count #=> 0
If our user wants to like this comment, he can do so with ease:
@user = User.find_by_username('schneems')
@user.like! @comment
And that’s it. The comment now reports the details of the like.
@comment.like_count #=> 1
@comment.likes #=> [#<Likeable::Like ... >]
@comment.likes.last.user #=> #<User username: "schneems" ...>
The Install
For Rails apps, Likeable is extremely simple to set up.
First, add Likeable to your Gemfile:
gem 'likeable'
Set up your Redis connection in (e.g.) config/initializers/likeable.rb:
Likeable.setup do |likeable|
likeable.redis = Redis.new
end
Next, add the Likeable::UserMethods module to your User model:
class User < ActiveRecord::Base
include Likeable::UserMethods
end
Finally, add the Likeable module to any model you want to be likeable:
class Comment < ActiveRecord::Base
include Likeable
end
To learn more, check out the Likeable source, look at the example Rails app or watch the Likeable screencast.
Contributing
We’d love to get contributions to Likeable. If you want it to do something it doesn’t already, open an issue on GitHub. Or, if you feel so inclined, create a patch and submit a pull request.