April 7th, 2009 — archive and restore, environment setup
After a few years of owning my Mac, I started to feel that maybe, just maybe, it might be a little slower than it used to be. If nothing else, too many failed late night experiments had led to me installing weird systemy things that didn’t always entirely want to go away.
To clean up my baby, I tried out the ‘Archive and Restore’ feature found on my Mac DVD. It reinstalls OSX Leopard replacing the old instance and attempts to leave all of your application and profile settings just how they were.
Upon completion, I am certainly running smoother and faster, but sadly some of my web development setup got broken along the way.
So that it’s clear, my environment involves using these primary components:
- MySQL
- Ruby on Rails
- Apache/Passenger
Here’s an account of what I did to restore my environment to working order:
MySQL, Git
First step, I followed Dan Croak’s setup guide for the following steps (Ruby and RubyGems were already working fine btw):
Apache/Passenger
Then I recovered the following files from my Time Machine backup:
- /usr/local/mysql/data (to get my dev databases back)
- /etc/hosts (to get my local ip shortcuts back)
- /etc/apache2/httpd.conf (to get my apache/passenger settings back)
If you didn’t backup your Apache/Passenger config, you’ll want to re-run
sudo passenger-install-apache2-module
and probably follow John Ford’s Apache setup guide to get Passenger working for you again.
TextMate integration
Redo this for TextMate’s mate command in console:
http://blog.macromates.com/2005/textmate-shell-utility-tmmate/
locate
I also consulted Neil Ang’s blog to get locate working again.
There’s also a way to make it use Spotlight’s index if you check the comments, however this prevents searching directories such as /usr and /bin, but it can be fun if you want locate to follow your Spotlight preferences for search restrictions.
That’s it! Now I’m back to work. I hope this helps someone else out there.
December 8th, 2008 — passenger, ruby on rails, tips and tricks
I’ve just recently set up my rails development environment to be managed by Passenger, and I have to say I like being able to type in real URL’s for my domains and not have to manually start my sites.
However, having formerly done my development by first running “script/server” and then going to town, I miss having the log output handy for whenever I blow something up.
If you’ve made the transition to Passenger I imagine you might also feel the same way, so let’s get that back! The easiest way is to use
tail -f log/development.log
Much better! Now we can see the server log output again so it’s easy to view the stack traces for our bugs. However, now that we’re up and running with our super slick hyped-up toy called ‘Passenger’… we’re still having to take just as many steps to get the same results! In fact, typing that command takes longer than script/server used to take.
Well let’s just fix all of our problems in one fell swoop. Add the following to your .bash_login file:
alias go='cd ~/Sites/newcoolsite.com;> log/development.log;mate .;open -a FireFox http://newcoolsite/staff;tail -f log/development.log;'
…where ‘newcoolsite’ is the directory/domain that you’re interested in. Now when we open up our terminal, we just type ‘go’, hit enter, and in about half a second we’ll find the following has happened:
- Our terminal has moved to the proper folder for our site (~Sites/newcoolsite.com)
- The development log is cleared
- TextMate opened our code
- FireFox opened our site (http://newcoolsite/)
- Our terminal started monitoring the server log output
Much better! However there’s still one thing bugging me. We used to just hit Ctrl+C then Up and Enter to restart script/server. It was a very quick and easy way to restart the server and keep our terminal window showing us the activity that we want to see. At this point we still have to type
Ctrl+C
touch tmp/restart.txt
tail -f log/development.log
Unacceptable!! We can easily remedy this situation. Just add a new line to our .bash_login file resulting in the following:
alias go='cd ~/Sites/newcoolsite.com;> log/development.log;mate .;open -a FireFox http://newcoolsite/staff;tail -f log/development.log;'
alias rs='> log/development.log;touch tmp/restart.txt;tail -f log/development.log;'
Now we just hit Ctrl+C, then rs to restart the server and resume our server log monitoring.
Very smooth and painless. Happy coding!
November 11th, 2008 — named_scopes, rails
I recently ran across an article at Caboose.se about building named scopes conditionally to make a slick filter. Unfortunately comments on it are closed now. The code he shared looked like this:
def index
scopes = []
scopes << [ :by_user, params[:user_id] ] if params[:user_id]
scopes << [ :tag_name, params[:tag_name] ] if params[:tag_name]
scopes << [ :rating, params[:rating] ] if params[:rating]
order = { 'name' => 'videos.name ASC' }[params[:order]] || 'videos.id DESC'
@videos = scopes.inject(Video) {|m,v| m.scopes[v[0]].call(m, v[1]) }.paginate(:all, :order => order, :page => params[:page])
end
I found this code soon after writing something similar for myself, and modifying his code to look like mine would give:
def index
scope = Video
scope = scope.by_user params[:user_id] if params[:user_id]
scope = scope.tag_name params[:tag_name] if params[:tag_name]
scope = scope.rating params[:rating] if params[:rating]
order = { 'name' => 'videos.name ASC' }[params[:order]] || 'videos.id DESC'
@videos = scope.paginate(:all, :order => order, :page => params[:page])
end
With this there’s no need for the inject/call, you just call the methods yourself, and skip building an array of symbols/strings. I’m sure this is more efficient, but does this make it more or less readable to you?
I saw Ryan Bates post a response to his article suggesting one could use his scope builder plugin which would turn the code into this:
def index
scope = Video.scope_builder
scope.by_user params[:user_id] if params[:user_id]
scope.tag_name params[:tag_name] if params[:tag_name]
scope.rating params[:rating] if params[:rating]
order = { 'name' => 'videos.name ASC' }[params[:order]] || 'videos.id DESC'
@videos = scope.paginate(:all, :order => order, :page => params[:page])
end
Seems like a very small gain for the introduction of a plugin. Am I missing something? Are there other examples where my solution would not be as attractive? Or is this a case where the original Rails code suits the purpose just fine?
July 1st, 2008 — association proxy, ruby on rails, tips and tricks
I just hit a real mean snag today trying to put an expectation on a model and it didn’t get caught like it should. This is something I do all the time so I knew I wasn’t just making a basic typo. Here’s what my setup looked like:
The model
def purchase
send_shipping_notice
end
def send_shipping_notice
puts "hi"
end
In my spec/test
def given_bought_on(date)
wp = @order.product
puts wp.inspect
wp.should_receive(:send_shipping_notice)
wp.purchase
end
The output
#<Product id: 270, owner_id: 270, name: 'thing'>
hi
1)
Spec::Mocks::MockExpectationError in 'Product should purchase'
Mock 'Product' expected :send_shipping_notice with (any args) once, but received it 0 times
./spec/models/product_spec.rb:21:in `given_bought_on'
script/spec:4:
So as you can see, I put an expectation on the wp variable, and verify it gets called by seeing ‘Hi’ get printed. However the expectation totally gets overlooked and my test framework complains that it never happened.
The catch is that the wp in my test and the web_page self inside the model are two different models. So the expectation is on a different model. Calling .object_id or .inspect on either one will affirm (or rather lie) to you that they’re the same, but they are not.
This is (as I’m told) well documented in ActiveRecord and is intentional by design. The wp variable is in fact an Association Proxy, not the WebPage I think it is. It just lies to you outright so you think it’s a WebPage.
My solution, while rather a hack, is the only thing I know to get my spec to pass:
def given_bought_on(date)
wp = Product.find(@order.product_id)
puts wp.inspect
wp.should_receive(:send_shipping_notice)
wp.purchase
@order.reload
end
Now it grabs the model directly and there’s no confusion.
June 24th, 2008 — pagination, ruby on rails, tips and tricks
I want my list of data to be paginated by letters. The will_paginate plugin certainly gives excellent pagination if all you want is “prev 1 2 3 .. 6 next” kind of pagination.
However what if you’re looking for entries that start with the letter H and you have no idea if that’s page 4 or page 42? You’re probably wanting something more like “# A B C D…” pagination.
I did some googling and found people speaking of solutions for “A B C D…” but in my case, not all of my entries start with letters! If you have something like media titles in your data set, having an entry start with a number is perfectly normal. Some might even start with special characters! Some people suggest having an ‘All’ option, but if you need pagination, it’s probably because you have enough data that showing all options at once is a very bad idea.
Here’s my solution:
First I make a helper function for my options that’ll be cached permanently.
def letter_options
$letter_options_list ||= ['#'].concat(("A".."Z").to_a)
end
Here’s my index action in my controller:
@letter = params[:letter].blank? ? 'a' : params[:letter]
if params[:letter] == '#'
@data = Model.find(:all, :conditions => ["title REGEXP ?",
"^[^a-z]"], :order => 'title', :select => "id, title")
else
@data = Model.find(:all, :conditions => ["title LIKE ?",
"#{params[:letter]}%"], :order => 'title', :select => "id, title")
end
Here’s my html
<div class ="pagination">
<% letter_options.each do |letter| %>
<% if params[:letter] == letter %>
<span class="current"><%= letter %></span>
<% else %>
<%= link_to letter, staff_games_path(:letter => letter)%>
<% end %>
<% end %>
</div>
There we go! Now the # will pull up all entries where the first character is not a letter.
June 19th, 2008 — attachment fu, mime types, rubyzip, zip
Today I’m going to share how you can let your app accept zip files which will then be extracted into multiple attachments. If you already use Attachment Fu to manage files, this should be super easy to add.
Before my controller had something like this:
Attachment.create(:uploaded_data => params[:Filedata])
First break that up into something more like this:
attachment = Attachment.new
attachment.uploaded_data = params[:Filedata]
attachment.save
Then put in some split logic for if it’s a zip file:
attachment = Attachment.new
attachment.uploaded_data = params[:Filedata]
if attachment.content_type == "application/zip"
# Unzip this and process all the inner files
Attachment.build_from_zip(attachment)
else
attachment.save
end
Now we’ll need the RubyZip gem and MIME Types gem, so do:
sudo gem install rubyzip
sudo gem install mime-types
Now in the Attachment class we’ll add the build_from_zip method:
def self.build_from_zip(ss)
zipfile = Zip::ZipFile.open(ss.temp_path)
zipfile.each do |entry|
if entry.directory?
next
elsif entry.name.include?("/")
next
else
screen = Attachment.new
screen.filename = entry.name
screen.temp_data = zipfile.read(entry.name)
mime = MIME::Types.type_for(entry.name)[0]
screen.content_type = mime.content_type unless mime.blank?
screen.save
end
end
end
The only two non-obvious things to note here are:
- I skip the files with / in them because when I archive files on my machine, hidden files with / characters in them make it into the archive. I only want the real files.
- I use the MIME Types gem to decide the content type from the filename.
I hope you find this helpful, enjoy!
May 23rd, 2008 — ajax, javascript, tips and tricks
Today I have another IE6 quirk in dealing with Prototype. I have a bunch of elements that I want to sort with a Sortable object, which works as expected for the most part, except in IE6!
I set background-color: #E6F2FF; to the rows of my ‘table’ which of course isn’t a real table, just some nicely styled div’s! The problem with this is that there’s a bug in this situation with IE6. All the contents of my rows are hidden! That means text, links, images. It looks as if all of the rows are just empty… except I can mouse-over and my mouse can interact with the elements.
It turns out, the opacity css attribute is 0. Or at least IE6 behaves as if it is. The thing is, FireBug doesn’t agree, and if you set opacity: 1; in your stylesheet it won’t cut it. The problem begins just after the Sortable.Create call. Removing this call fixes the problem, obviously, but that’s not what we want!
Here’s my solution. After the Sortable.Create call, do this:
if (Prototype.Browser.IE) {
$$('.relevant_class_name').invoke.setStyle({opacity: 1});
}
where relevant_class_name is the css class assigned to the row’s of data on my page. This sets the opacity to all of the affected elements after the the Sortable object screws things up.
Hooray! I hope this helps someone else.
April 4th, 2008 — ajax, javascript, tips and tricks
In the current project I’m working on I have all sorts of cool AJAX madness happening to add things to my pages. For one particular example, I have AJAX calls that add pieces to the page with more AJAX functions inside of those pieces. Fun, huh?
The kicker is that some of the elements on the page there are being shown with the style attribute of position: static;. It just so happens that Prototype and position: static do not always play nicely in this case.
Let me show you what I mean. Here you see an image with two links placed with position: static;.

Clicking on “+ Add Foo” twice and “+ Change Bar” gives:

This works as expected. However if I add a duplication of this segment of the page using an AJAX call, the new portion does not work as expected while in Internet Explorer (every other browser works just fine of course).
To illustrate the problem while trying to do the same thing with the new segment, first I add the new segment via the “+ Add Many Things” link.

Then I click “- Change Bar” which hides the following two lines. You now see the two links I’ve been referring do not follow the movement of the page. They should have scrolled up and they did not.

To handle this, I need some extra JavaScript. First I add the following to the parameters of my AJAX call:
onSuccess: function(request){ reposition(); }
Next I want to take the elements that I know I have this problem with (selected by class name) and then first turn off the “relative” position by setting it to “static” and then back to “relative” again. By the way I figured this out thanks to way too much time fiddling with things in FireBug and the IE Dom Inspector. I can’t come up with any real sense to it. To make this happen, I add the following JavaScript for IE only:
function reposition() {
if (Prototype.Browser.IE) {
$('publication_list').select('.remove').each(swapStaticToRelative);
$('publication_list').select('.add_company_role').each(swapStaticToRelative);
$('publication_list').select('.add_cover').each(swapStaticToRelative);
}
}
function swapStaticToRelative(item) {
item.setStyle({ position: 'static' });
item.setStyle({ position: 'relative' });
}
Note that the following also works for detecting that the browser is any version of IE:
function reposition() {
/*@cc_on
/*@if (@_win32)
$('publication_list').select('.remove').each(swapStaticToRelative);
$('publication_list').select('.add_company_role').each(swapStaticToRelative);
$('publication_list').select('.add_cover').each(swapStaticToRelative);
@else @*/
/*@end
@*/
}
I wish I could remember where I found that, but it’s crazy cool. Sure the Prototype way is better… but this is a fun one to stare at for a while until you figure out how it’s working.
So with that change in place, this time it works as expected.

The only thing better I think (aside from IE not sucking) would be to have a way to select fields by style attributes. If I could figure that out, I’d be able to make a single call to swap these CSS attributes for all instances on the page that are relevant to this problem. If I could do that, then it might be a candidate for a patch to Prototype.
If you have a suggestion for a better way to handle this or if my post helped you out, please let me know by leaving a comment!
March 31st, 2008 — plaintext, ruby on rails, stories, tips and tricks, webrat
Building off of my last post on Stories, I’d like to show you some improvements I was able to make with the help of WebRat.
You can install WebRat using:
script/plugin install http://svn.eastmedia.net/public/plugins/webrat/
I got the inspiration from Ben Mabey at ‘ben.send :blog’ which illustrates an approach to stories that is unbelievably easy to pick up. He also provides source code to the example that he’s built so that you can play with it. Very cool!
I snagged that source myself and started playing with it, and added a lot of functionality of my own that I found useful. The real cool thing is that the ONLY application specific code I have is this:
# user_steps.rb
steps_for(:user) do
Given("that $actor is not logged in") do |actor|
get "/sessions/destroy"
response.should be_redirect
flash[:notice].should == "You have been logged out."
#fails here even though in the next request it will pass
#controller.should_not be_logged_in
end
Then("$actor $should be logged in") do |actor, should|
controller.send(shouldify(should), be_logged_in)
end
end
# navigation_steps.rb
def path_from_descriptive_name(page_name)
case page_name
when "home"
""
when "signup"
"users/new"
when "login"
"sessions/new"
else
"#{page_name}"
end
end
With that, and the generic application-independent helper methods that also live in my steps directory, I can write the following story:
Story: Making posts
As a visitor
I want to be a member
So that I can make posts
Scenario: Glenn creates a new account
Given that Glenn is not logged in
And there are some number of users
And no user with login 'Glenn' exists
When he goes to the signup page
And fills in Login with 'Glenn'
And fills in Email with 'glenn@glennfu.com'
And fills in Password with 'blah'
And fills in Confirm Password with 'blah'
And clicks the 'Sign up' button
Then there should be 1 more user
And a user with login 'Glenn' should exist
Scenario: Glenn logs in
GivenScenario Glenn creates a new account
When Glenn goes to the login page
And fills in Login with 'Glenn'
And fills in Password with 'blah'
Then he should be logged in
Scenario: A member makes a post while logged in
GivenScenario Glenn logs in
And there are some number of posts
When he goes to the posts page
And clicks on 'New post'
And fills in Title with 'Woo'
And fills in body with 'Stuff here'
And clicks the 'Create' button
Then there should be 1 more post
And a post with title 'Woo' should exist
Scenario: A nice lady makes a post while not logged in
Given that she is not logged in
Then she should not be logged in
Given there are some number of posts
When she goes to the posts page
And clicks on 'New post'
Then she should see the login page
Scenario: An angry visitor should be able to see posts
Given that he is not logged in
When he goes to the posts page
Then he better not f'ing see the login page
Scenario: A visitor should not be able to edit posts
GivenScenario A member makes a post while logged in
And that she is not logged in
When she goes to the posts page
And clicks on 'Edit'
Then she should see the login page
Pretty cool, huh? I was even able to add some personality with the angry visitor Scenario. Notice that I don’t have any steps written about Posts or my PostsController. I don’t need it because I have generic model steps that parse the model from the text in my PlainText instructions. It has all the basics that you need. You interact with forms and links on the top level by name, and then check the results either by text on the page or by finding models.
If you’d like to play with it yourself, I’ve zipped up my stories folder for you to play with.
Download it here!
It also has the old user_story.rb from the previous example. If you have any suggestions for improvements to this or ideas for something else I should do with it, please leave a comment!
My only quirk with this is that if you check the first step in the steps_for(:user) above you’ll see I have a line commented out. It checks for controller.should_not be_logged_in and if I uncomment it, the check fails even though the two above it pass. As you can see in the PlainText, on the very next line I call the very same check and it passes. If you could help me figure out my mistake here I’d really appreciate you leaving a comment with your thoughts!
I hope you find this useful, and if so, be sure to go toss a thank you over to Ben for the inspiration.
March 27th, 2008 — rspec, stories, tips and tricks
Update: I’ve made some improvements upon this using WebRat that you can read all about here.
I’m having a great time with RSpec’s new StoryRunner, and wanted to share a bit of what you can do with it. I learn very well from examples and I know many others do as well so I hope that this provides as a useful resource for getting your ideas flowing on how to use StoryRunner for your own projects.
To start, I set up a simple project using the following
# Create the project
rails blog
cd blog
# Install Restful Authentication
script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/
script/generate authenticated user sessions
# Create a Post model
script/generate scaffold post title:string body:text published:boolean
Now I have the essentials for a simple app to play with. Of course you’ll also want to install RSpec.
Now to try out StoryRunner! I’ll write a story to cover the login system. No need to write Spec’s for it, it’s already well tested. However in writing this story we get a reusable Scenario that will be nice to have later, as well as give us a nice starting point for stories.
require File.join(File.dirname(__FILE__), "helper")
Story "User Stuff", %{
As a writer
I want to be a member
So that I can make posts
}, :type => RailsStory do
Scenario "I log in as a new user" do
Given("that I am not logged in") do
delete "/sessions/destroy"
controller.should_not be_logged_in
@user_count = User.count
end
When("I create a new user", "Glenn") do |name|
@user = User.create(:login => name,
:email => "#{name}@glennfu.com", :password => name,
:password_confirmation => name)
end
Then("there should be 1 more user stored") do
User.count.should == @user_count + 1
end
When("I login as", "Glenn") do |name|
post "/sessions/create", :login => name, :password => name
end
Then("I should be logged in") do
controller.should be_logged_in
response.should be_redirect
end
end
end
This should be pretty easy to follow. I start by logging out, then creating a user and logging in with it. This is runnable with ruby stories/user_story.rb
Now that this is already written, we can easily add similar stories. Notice that we don’t have to re-define our steps here:
Scenario "I log in with the wrong user/password" do
Given "that I am not logged in"
When "I create a new user", "Glenn"
Then "there should be 1 more user stored"
When "I login as", "JoeBob"
Then "I should not be logged in" do
controller.should_not be_logged_in
response.should_not be_redirect
end
end
Now I’ll write a story for our Posts. Notice the usage of “GivenScenario”, very cool!
Scenario "Create a new post while logged in" do
GivenScenario "I log in as a new user"
Then "I should be able to make a post" do
post "/posts/create", :post => {:title => "the title",
:body => "The body!"}
@post = Post.find_by_title("the title")
flash[:notice].should == "Post was successfully created."
@post.should_not be_nil
response.should be_redirect
end
end
What if I want to also test posts failing? I’ll modify the previous step to be a bit more robust (and also more useful).
Then "I $should be able to make a post", "should" do |should|
post "/posts/create", :post => {:title => "my title",
:body => "The body!"}
@post = Post.find_by_title("my title")
if should == "should"
flash[:notice].should == "Post was successfully created."
@post.should_not be_nil
else
flash[:notice].should be_nil
@post.should be_nil
end
response.should be_redirect
end
With this change, I can easily add a new Scenario to test when making posts should fail:
Scenario "Create a new post while not logged in" do
Given "that I am not logged in"
Then "I $should be able to make a post", "should not"
end
I hope you found this useful!