Showing posts with label rails. Show all posts
Showing posts with label rails. Show all posts

Wednesday, February 29, 2012

Rails A/B testing with Split on Heroku

I recently decided to start doing some A/B testing on www.checkthesock.com. The last time I tried A/B testing I used Google website optimizer, it worked fairly well but I did not like how difficult it was to setup a test. This time I looked around for A/B testing tools for rails. I ended up finding split and so far I have been very happy with the results. The documentation is fairly good but it did take a little fiddling to get it working on Heroku.

First off add the Redis to Go add-on in Heroku, the Nano plan is free and has been sufficient for my needs so far. Install redis on the dev server. I use a mac so that was as simple as "brew install redis" and then I followed the brew instructions for getting redis to start on login.

To install the split gem add the following to the Gemfile

 gem 'split', '0.3.3', :require => 'split/dashboard'

To set the development environment up in a way that is compatible to how Redis to Go is configured on Heroku add the following to config/environments/development.rb

ENV['REDISTOGO_URL'] = 'redis://localhost:6379'
Then create an initializer for redis in config/initializers/redis.rb and put the following in that file.
uri = URI.parse(ENV['REDISTOGO_URL'])
REDIS = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password, :username => uri.user)
To configure split to use the applications redis configuration create config/initializers/split.rb and add the following.
Split.redis = REDIS

To setup the split dashboard add the following to config/routes.rb

mount Split::Dashboard, :at => 'split'
To add authentication to the dashboard add the following to config/initializers/split.rb
Split::Dashboard.use Rack::Auth::Basic do |username, password|
  username == 'username' && password == 'password'
end

Setting up an A/B test is super easy just follow the instructions in the split README.

Resources:

Note: These instructions are for rails 3.x, the listed resources do have instructions for earlier versions of rails.

Thursday, September 8, 2011

Rails Code QA Update

I just released an updated version of Rails Code QA which now supports rails 3.0 and 3.1 as well as ruby 1.8.x and ruby 1.9.x


Installation
If you are using ruby 1.8.x all you need to do to install rails_code_qa in your rails 3.x app is add the following line to your Gemfile.
gem "rails_code_qa"


If you are using ruby 1.9.x you will also need to add the following to your test/test_helper.rb file
require 'simplecov'
SimpleCov.start 'rails'


Code Coverage
Rails Code QA takes care of picking which code coverage tool to use based on the version of ruby you are using. If you are using ruby 1.8.x code coverage is calculated using rcov and if you are using ruby 1.9.x coverage is calculated using simplecov.

Static Code Analysis
Rails Code QA also runs flog and flay to help you find other issues in your apps code.


Resources

Monday, September 20, 2010

Getting over assert_difference

For quite a while now I have been using assert_difference or its close cousin from shoulda should_change. When I recently updated to a recent version of shoulda I noticed that they had deprecated should_change. The note in the shoulda documentation says the following: "This macro was deprecated because these tests aren’t as valuable as alternative tests that explicitly test the final state."

Ok, now what to do? assert_change is super easy to use, but does it really ensure that the desired action is actually happening? For example:

This example test asserts that the number of User objects in the database has increased by 1. No real guarantee that it was actually the User object we were interested in creating.

Lately I have been trying to be a little more explicit about what is actually happening. It is taking a little while to get used to doing things this way but the results have been satisfying. Here is an example:

This example test asserts that a User object is getting assigned to the @user instance variable and that User object is no longer a new record.

Monday, December 28, 2009

Interesting Rails Methods: update_attribute

Method: update_attribute
Module: ActiveRecord::Base
Documentation: Updates a single attribute and saves the record without going through the normal validation procedure. This is especially useful for boolean flags on existing records.

Notes:
This method actually does far more than just update an attribute. It updates the whole object without validations. This is fine if you just retrieved the object from the database but it can be a disaster if you have modified other attributes on the object.

Given:

Article.find(1)
#<Article id:1 title:"title" body:"first article">

Safe usage of update attribute:

article = Article.find(1)
article.update_attribute(:title, "new title")
Article.find(1)
#<Article id:1 title:"new title" body:"first article">

Unsafe usage of update attribute:

article = Article.find(1)
article.body = ""
article.update_attribute(:title, "new title")
Article.find(1)
#<Article id:1 title:"new title" body:"">

Thursday, October 30, 2008

Upgrading rails apps without downtime

I recently worked on an application that took messages from internal applications and queued them up before sending them to an external vendor. The application was built because the messages were important enough that loosing any messages sent during vendor downtime was not an option. Since all applications involved were using rails it was an obvious choice to develop the queuing app in rails and use a REST api to transfer the data into the queue.

The queue app went together quite nicely and everything was going smoothly until it went live and updates were needed to fix some bugs. Since the queuing app was the method for handling downtime outside of the main application it wasn't safe for the queue to go down while the main application was still up. Out of necessity I quickly came up with a solution.

The final solution consists of running more than one mongrel cluster, preferably on different servers. Proxy to all of those clusters from the apache instance that is serving the main application. This provides redundancy as far as the mongrel clusters are concerned and if the main apps apache server is down the application won't be generating any messages to be queued.

To upgrade the queuing app without downtime upgrade the code behind one of the clusters and restart that cluster, repeating until all clusters have been upgraded. This works very nicely, but it does require careful development to ensure that each update is compatible with the previous version of the application.

Tuesday, August 26, 2008

Easy password hashing in rails 2.1

I was working on a simple authentication system for a new project and got to the point where I needed to hash the password before storing it. I realized that this was a great opportunity to use the new dirty objects functionality that came out in rails 2.1.

First off, a quick explanation of dirty objects. Dirty objects provides the ability to tell what attributes of a model object have changed. For example, given an active record object "foo" with an attribute "bar", dirty objects adds a method "foo.bar_changed?" which returns true if the attribute "foo.bar" has been changed since the object "foo" was pulled from the database.

In the past when changing a password there has never been a really simple/elegant way to detect when the password had been changed and only then, hash the password. Now it is trivially simple. Adding the following few lines of code to the model does the job quite nicely.

after_validation :hash_password

def hash_password
if self.password_changed?
self.password = Digest::MD5.hexdigest(self.password)
end
end
Now, whenever the password in the object is modified, whether it is via a form submission or just updating the object in script/console, save the object and the password will be hashed before it is stored. If there are any validations that don't pass the object will not be saved and the password will be the same as it had been.

Thursday, August 21, 2008

Choosing good gems/plugins for your rails app

Over the past few months I have been working on upgrading some of the rails applications I have been working on. I have been having quite a bit of trouble and a large portion of the issues stem from the gems and plugins that were used. In the past I have not had that much trouble with plugins and gems making upgrades difficult, so I sat down and tried to come up with some guidelines for picking plugins. These are the guidelines I came up with.

My plugin/gem selection guidelines:
  1. Does it have a well defined goal?
  2. Does it do something substantial?
  3. Does it have a good record?
Does the plugin/gem have a well defined goal?
If the plugin you are evaluating does everything, that isn't necessarily a good thing. A plugin that does everything will likely to be harder to debug and has a higher chance of conflicting with something. A plugin that does one thing has a much better chance of doing that one thing very well.

Does the plugin/gem do something substantial?
If the task at hand is pretty simple it may be better to write the code yourself. When you are faced with a rails update, maintaining a few extra lines of code could end up being a lot easier than finding the latest version of the plugin and making sure the new version is compatible with your application.

Does the plugin/gem have a good record?
Does the plugin appear to be well maintained or has it been years since it was updated? Does it only have one contributor or does it have a good community built around it?



Example 1: Chronic (chronic.rubyforge.org)
Does Chronic have a well defined goal?
Yes, Chronic is a natural language date/time parser.
Does Chronic do something substantial?
Yes, it would take a lot of work to write a natural language date/time parser.
Does Chronic have a good record?
It looks pretty good, it has been around for a couple years, quite a few people seem to be using it, and it has survived several rails upgrades without big issues.

Looks like Chronic meets the guidelines fairly well. I have been using Chronic quite successfully for about a year and a half.

Example 2: Facets (facets.rubyforge.org)
Does Facets have a well defined goal?
No, it is an attempt to do just about everything.
Does Facets do something substantial?
Not really, it does a lot, but it is made up of lots of little pieces.
Does Facets have a good record?
Yes and no, it has a substantial community behind it which is good, it has been around for a little while which is good, but it has also had some very large structural changes which made different versions incompatible.

Looks like Facets doesn't meet the guidelines, based on that I would not choose to use Facets in one of my rails apps. Facets is a gem that came built into some apps that I work with, I have had a lot of problems with Facets and how it was used.

Example 3: file-tail (file-tail.rubyforge.org)
Does file-tail have a well defined goal?
Yes, it allows you to tail a file without having process the output of a system tail application.
Does file-tail do something substantial?
Yes, it would be a bit of work to write your own tail library in ruby.
Does file-tail have a good record?
Yes and no, it has been around for quite some time and seems to be very stable, but it doesn't have a big community and I haven't found many people that talk about using it.

File-tail doesn't meet all the guidelines perfectly but it should be reasonably safe. I recently used File-tail in an application and it has performed very well so far.


Saturday, June 14, 2008

Using rails routing for easy search engine friendly URL changes


In this entry I am going to show how to, in a very search engine friendly way, update a URL for a particular page in a rails website. The rails routing system provides named routes, which are a very nice way to change the URL for a particular page and have all of your links update without having to change code in a bunch of different places. That is a great start on moving a page, but it doesn't take care of any links from outside of your site that might be pointing at the old URL. The best way to handle that is to make it so that the old URL redirects to the new URL, your end users won't notice a difference but the search engines bots will take note and update their indexes.


First off if you are not familiar with routing and named routes in rails you might want to read up on it. The rails API docs have some pretty good material on routes located at http://api.rubyonrails.org/classes/ActionController/Routing.htm


Lets pretend we are moving "http://example.com/users/signup" to "http://example.com/signup". Our original named route might look something like this:


map.signup '/users/signup', :controller => 'users', :action => 'signup'


And the code for a link that pointed to it would look something like this:


<%= link_to 'Signup', signup_url %>

To change our URL we would simply change the named route to look like this:

map.signup '/signup', :controller => 'users', :action => 'signup'

All of the links that used the named route would automatically change to link to the new URL but the old URL would stop working. To change that we could add the following to the routes file

map.signup_old '/users/signup', :controller => 'users', :action => 'signup', :old_url => true

This would allow the old URL to work, but it would be best if we made it so that it redirected to the new URL so that search engines would switch over to the new URL faster. Notice that there is an additional parameter that is defined on the end of the second route, this makes it so that we can easily differentiate what URL a visitor arrived on the page with.

Now all we have to do is make a method we can use in a before filter that redirects the user to the same action, the redirect will automatically use the first route we defined (as long as we leave them in that order in the routes file). In the users controller we would add the following code:

before_filter :redirect_to_new_url

def redirect_to_new_url
if params[:old_url] == true
headers["Status"] = "301 Moved Permanently"
redirect_to({:action => action_name})
end
end
The lines in the route file would look like this:

map.signup '/signup', :controller => 'users', :action => 'signup'
map.signup_old '/users/signup', :controller => 'users', :action => 'signup', :old_url => true

Once you have this in place you only have to add a new route to move a URL in a search engine friendly way, and when you decide that all the external links and search engines are updated all you have to do is get rid of the route that points to the old URL.

Sunday, June 1, 2008

What DRY is really about


Lets start with what the acronym DRY stands for, Do not Repeat Yourself. That sounds like a pretty good idea, it makes sense, but what are we really trying to accomplish by keeping our code DRY? Ok, that was a rhetorical question but I know someone out there would probably respond by saying "Not repeating ourselves!", to which the audience would chuckle because everyone knows that isn't what DRY is about. DRY is really about making high quality maintainable code.




Lately I have been finding things in the code base that I am working with that indicates that some programmers have taken DRY way too literally and use it in places that reduce code readability and maintainability. For example I found something similar to the following ruby on rails code a while back.


if something == true
temp_var = {:action => "foo"}
else
temp_var = {:action => "bar"}
end
redirect_to {:controller => "main"}.merge(temp_var)

In this example of code, they are essentially avoiding a tiny bit of duplication, defining the controller. The thing is this code is more difficult to understand than the following.

if something == true
redirect_to :controller => "main", :action => "foo"
else
redirect_to :controller => "main", :action => "bar"
end

In the second example there is a slight bit of duplication, but it is also easier to figure out what the code is doing as you read through your if statement. That increased readability makes the code just a little easier to maintain. Additionally if you were thinking about changing this code there is a good chance that you would be changing the controller argument for only one of the two redirect calls, in which case the second code example is much simpler to edit. Of course there is another option, if the person writing this code originally had been aware of some additional functionality that the rails framework offers they would have used a named route which would get rid of all of the duplication while maintaining great code readability.

if something == true
redirect_to foo_url
else
redirect_to bar_url
end

Now that you know DRY isn't just about not repeating yourself, take a little extra time before removing duplication and think about whether the change gets you closer to the goal of having readable and maintainable code. If the change doesn't make your code easier to maintain consider leaving the duplication or even better do some research and find a solution that gets rid of the duplication without making things harder to read or maintain.

Thursday, January 31, 2008

My first open source rails plugin: SafeDevEmail


I just finished up the initial version of my first open source rails plugin. It is a fairly simple plugin which allows you to configure an email address that will receive all emails sent from your rails app while it is in development mode.


The plugin is available at code.google.com/p/safedevemail/.

To get started all you need to do is drop the plugin in your vendor/plugins directory and edit your mailserver settings in evironment.rb

Config Examples:

SMTP


ActionMailer::Base.smtp_settings = {
:address => "smtp.example.com",
:port => 25,
:domain => "www.mywebsite.com",
:dev_mailto => "developer@mywebsite.com"
}

Sendmail


ActionMailer::Base.sendmail_settings = {
:dev_mailto => "developer@mywebsite.com"
}

Thursday, January 17, 2008

Lazy Migrations


I was working on americanwinery.com and one of my coworkers asked me about a model that they hadn't seen before. Turns out it was from the early days of the site and it was never even used in production. It was a great candidate for a little code cleanup, so I removed the model and tests and started in on the migration to remove the table.



When I write migrations I generally make a point of making them reversible, so as I was looking for the original migration to copy the structure of the table I thought it would be much easier to just call the "up" from the original migration in the "down" of the migration I was working on. It was an interesting thought, turns out it is pretty easy to do.



For example, lets say you have a migration that creates a table named articles and it looks something like this:


class CreateArticles < ActiveRecord::Migration
def self.up
create_table :articles do |t|
t.text :title, :body
t.timestamps
end
end

def self.down
drop_table :articles
end
end


A few days/months/years later you realize that you don't use that table and you decide to write a migration to get rid of it, here is what I would suggest:

class DropArticles < ActiveRecord::Migration
def self.up
CreateArticles.migrate("down")
end

def self.down
CreateArticles.migrate("up")
end
end


That is all there is to it. If you want to do a little more reading on this subject you can check out the API documentation (http://api.rubyonrails.org/classes/ActiveRecord/Migration.html)