In which I show how to install your own version of RubyGems on DreamHost, or any shared host with ssh access for that matter.
I get a lot of ideas, so many in fact that I would never want to purchase a Slicehost, Railsmachine or Engine Yard slice for each one. I would run out of money in a few weeks. Instead, I put most of my ideas through a trial run on a shared host (DreamHost). If I find myself using the application a lot and needing performance to improve, I’ll bump it up to a slice on one of the aforementioned hosts, but until then the app will sit in shared-ville.
As such, I have spent a lot of time battling Rails on DreamHost. Back in the old days (fcgi), I had cron jobs running Ruby scripts and all kinds of tweaks trying to keep my DreamHost rails apps going. I finally gave up on DH and bought a slice at slicehost (whose site we at Ordered List designed).
I’m happy to say that the battle is now over. It is really easy to host your own git repositories, install your own version of Rubygems and deploy your Rails apps on DreamHost with passenger (mod_rails). Don’t expect DH to amaze you with performance, but for tiny apps with a few users (or heck just for yourself), Dreamhost is a cheap and really viable option.
Your Own Version of RubyGemsRest assured I’ll cover setting up and deploying an app in a future article, but for now I am going to show a quick and easy way to install your own gems on Dreamhost (or virtually any shared host you have ssh access to) and how to tweak Rails to obey (if necessary). Installing RubyGems in your home directory, as I am about to show you, allows for installing gems without sudo, which most shared hosts deny.
To get going, ssh into the server you would like to install RubyGems on and then run the commands below. For now copy and paste, but I have a gem in the works that will automate this someday. If you are going to follow along, I would practice on something that doesn’t matter first to see if you run into anything.
# group 1 cd ~ mkdir .gems bin lib src # group 2 echo 'export GEM_HOME="$HOME/.gems"' >> .bash_profile echo 'export GEM_PATH="$GEM_HOME:/usr/lib/ruby/gems/1.8"' >> .bash_profile echo 'export PATH="$HOME/.gems/bin:$PATH"' >> .bash_profile source ~/.bash_profile # group 3 cd ~/src wget http://rubyforge.org/frs/download.php/43985/rubygems-1.3.0.tgz tar xzvf rubygems-1.3.0.tgz cd rubygems-1.3.0 ruby setup.rb --prefix=$HOME cd ~/bin ln -s gem1.8 gem cd ~ # group 4 which gem # should return /home/USERNAME/bin/gem gem -v # should return 1.3.0 # group 5 gem update --systemThe first group of lines creates the needed directories. The second group of lines ads 3 lines to your .bash_profile file. Basically, it sets your GEM_HOME to ~/.gems and your GEM_PATH to look first in your GEM_HOME and then look at DreamHost’s typical gem path. The final line of that group sets the PATH to check ~/.gems/bin first and then look in the normal path for binaries.
The third group downloads version 1.3.0 of RubyGems into your ~/src directory, untars it, and runs the setup file to install RubyGems. It then cds into your ~/bin directory and creates a symlink from gem to gem1.8 so you don’t have to type gem1.8 install somegem.
Group 4 verifies that everything went ok and is just a sanity check and the last line, group 5, updates RubyGems to the latest version. I don’t really want to update this article for every RubyGems update so be sure you run this command to get the latest version.
Now that you have RubyGems installed, you can install any gem by issuing the normal gem install command. The nice thing is that sudo is not needed as the gems are installed in your home directory, which you have permissions for.
Tweaking RailsFor whatever reason, DreamHost was ignoring the GEM_PATH and first looking in their gems, only looking in my gems if they did not have it installed. The easy fix for this is to put the following line at the top of config/environment.rb (if someone knows a better way, let me know).
ENV['GEM_PATH'] = File.expand_path('~/.gems') + ':/usr/lib/ruby/gems/1.8'The line above tells Rails to look first in your custom gems and then at DreamHost’s installed gems. You only need to do this if DreamHost has an older version of a gem you are installing and you specifically need the newer version. I ran into this with RedCloth 4, which is not installed on my DreamHost server, as of the writing of this post.
ConclusionIf you followed the few lines above, you can now install your own version of RubyGems on a shared host, install your own gems (with gem install foo) and use those gems in your Rails apps. One thing I did not mention is you can use the vendor everything method for any gems that don’t need to build extensions. Thought I would put that out there too.
Hope this is helpful. If you decide to give DreamHost a shot (who I recommend among shared hosts), use RAILSTIPS as the promo code. It will give you $30/off and I get a kickback as well.
In which I show how easy it is to setup your own remote git repositories with a cheap server and ssh access.
GitHub is awesome, really awesome for open source projects and for projects with multiple people. In fact, if you use your own git setup for an open source project, you are most likely hindering your project’s progress and wasting your time.
On the other side of the coin, if you are a lone shark and you don’t need GitHub’s awesome social features, I have news for you: you can host your own git repositories really easily and on the cheap side.
Remote SetupIf you are like me, you probably have a DreamHost, TextDrive or some other cheap shared hosting account with ssh access. What you might not know is that is all you need to host your own private git repositories.
ssh username@yourcheaphost.com mkdir -p ~/git/yourproject.git cd ~/git/yourproject.git git --bare initThat is it. Your git repository is now setup. Not too hard eh? You could put that anywhere but a folder named git makes sense to me.
Local SetupSo your remote server is now setup, but how do you use it? Glad you asked. Open up a new tab (or window) or quit your ssh connection and cd to wherever you want to setup your project locally.
mkdir yourproject cd yourproject git init git remote add origin ssh://username@yourcheaphost.com/~/git/yourproject.git touch .gitignore git add . git commit -m "Initial Commit" git push origin masterAt this point you have now pushed to your remote repository and are almost good to go. The last thing is you need to add the following on your local machine to .git/config in your project.
[branch "master"] remote = origin merge = refs/heads/master The EndThat is it. You can now push and pull at will. If you want to give anyone else commit access, just add their ssh key to ~/.ssh/authorized_keys and you can work on the project with a friend. Setting up your own git repositories is really easy, as you can see, so don’t be afraid.
Further ReadingSo what I showed above is really the most basic setup you can have. It involves pushing and pulling using ssh and is easy peasy. If you want more than that, such as finer grained access control, enjoy the following links.
Casper Fabricius wrote a handy shell script that allows doing all that I mentioned above on DreamHost in one easy terminal command.
Rick Olson has an article on moving to git where he shows a rake task he used and also links to gitosis.
Speaking of gitosis, Garry Dolly has an article on setting up gitosis and how to add users and manage their repository permissions.
Tim Lucas has a good post on setting up a new remote git repository.
GitHub has a ridiculous number of guides that are geared towards using GitHub but have morsels handy for non-GitHub usage.
Happy, cheap git hosting!
In which I explain why I use jQuery at times and how you can as well. Oh, and I provide a wealth of links. Links are fun!
A few people have suggested that I post about how to use jQuery with Rails. I thought about it and felt that others have already covered it quite well but why not collect their posts here for you to enjoy, right? Plus, I do all my JavaScript from scatch so I do not really ever use the helpers Rails provides and as such could not post intelligently on them.
So John, When Did You Quit Prototype?I haven’t! I do not intend to ever quit using Prototype. Honestly, I have used jQuery quite a bit less than Prototype. I have found that jQuery and Prototype are both great and in different situations I will use a different library. The one thing I will say is even if you don’t actually switch to jQuery, I think it is important to learn new things and stretch yourself. It is good to feel frustrated and like a beginner. Also, jQuery takes a very different approach which has actually helped me write better Prototype code. Hope this is helpful and not overwhelming. :)
Creating A Plugin
Today, I wrote an article on How to Create a jQuery Plugin From Scratch over on my Addicted To New site. I picked out the most basic thing a plugin could do and explained each step in a lot of detail. Give it a read if you are into Prototype but are curious about jQuery.
After creating my live search with quicksilver for prototype example, I decided to port it to jQuery (view demo). Then, humbly, I was corrected by the jQuery man himself, John Resig, who re-ported my port in a more jQuery-ish functional style. For those that are curious, I also massaged the AJAX-RDoc project to use quicksilver searching. This is really helpful when you can’t quite remember a method name.
Likewise, when I created fancy zoom for prototype, my partner in crime, Steve Smith, created a port of fancy zoom for jQuery (view demo). Fancy Zoom is great for showing text and images with an Apple-esque, in page zoom transition or even Flash if you have a video you would like to feature.
jQuery Railscast
Ryan Bates did an awesome job showing how to use the jQuery on Rails plugin with Rails in a recent screencast. He also gave a really quick example on how to create a plugin. I would recommend watching this and subscribing to his Railscasts, which are great.
jRails is a drop-in jQuery replacement for Prototype/script.aculo.us on Rails. Using jRails, you can get all of the same default Rails helpers for javascript functionality using the lighter jQuery library. Ryan shows how to use it in the screencast mentioned above, but I thought I would also mention it separately. If you are a fan of the Rails javascript/ajax helpers, this plugin is for you. It makes each of them work with jQuery and has some nice demos on the site.
While dispelling the myth that Rails is tied to Prototype, DHH gave some jQuery examples.
Brandon showed how he includes the authenticity token using prototype and the pug automatic shows how to do the same using jQuery.
Ben Curtis has a tutorial on how to do drag and drop sorting with jQuery and Rails.
Yehuda Katz has a year old presentation on jQuery and Rails that is still worth a look.
Nutrun has a more full post on how to do unobtrusive ajax with jQuery and Rails
ErrTheBlog (errtheblog is dead. long live errtheblog!) gave jQuery some serious love a while back in their jSkinny article. Chris also created a plugin named Facebox that is used extensively on GitHub and has a short post that shows how to get jQuery working with respond_to.
If you are a fan of Low Pro, Dan Webb has created a port of Low Pro for jQuery. (article #1, article #2)
In some Rails Rumble observations, it was noted that jQuery was more widely used than Prototype.
Don’t forget that “jQuery UI provides abstractions for low-level interaction and high-level, themeable widgets, built on top of the jQuery JavaScript Library, that you can use to build highly interactive web applications.” Be sure to check out the demos.
If you are a fan of Twitter, you can follow jQuery for links to articles and such.
Nathan Smith gave a crash course on jQuery that includes a sweet airline seat demo.
jQuery does not come with all of Prototype’s functionality out of the box, but you can usually find a plugin that does what you need if you are too lazy to make something yourself.
Lastly, one of my favorite jQuery resources is Visual jQuery. I found this site a blessing when I was trying to learn jQuery.
Feel free to post your favorite jQuery/Rails resources as a comment below.
In which Daniel Morrison covers how to install and use delayed job, a rails plugin that encapsulates the common pattern of executing longer tasks in the background.
I realized when I started taking suggestions that I would not be able to do them all justice, so I asked a few of my friends to be guest authors. Daniel Morrison, of Collective Idea, is the first and will be showing a few ways he has used delayed job to offload tasks to the background. Without any further ado, here is Dan.
At Collective Idea, we started using delayed_job a few months ago, and have fallen in love with its simplicity. In fact, my first implementation of it was done and tested on a quick train ride to Chicago, with time to spare.
So it’s easy?Yep, you can add delayed_job in 10 minutes or less.
Getting StartedInstall the plugin, which is available on GitHub.
Then build & run a migration to add the delayed_jobs table:
create_table :delayed_jobs, :force => true do |table| table.integer :priority, :default => 0 table.integer :attempts, :default => 0 table.text :handler table.string :last_error table.datetime :run_at table.datetime :locked_at table.datetime :failed_at table.string :locked_by table.timestamps end(In the future there will be a generator for this step. Tobi, please merge some of the forks!)
Run your jobsThe rest of the article will focus on creating jobs, but when you want to run them, you can simply run rake jobs:work
The job runner will grab a few jobs and run them one at a time. It locks them so that multiple runners won’t conflict, and it will retry jobs a number of times if it fails for some reason. If it does fail, it stores the most recent error message. Play around in script/console with the Delayed::Job model to see how it works.
There are some other ways to run jobs in production in some of the forks on github. Collective Idea’s for example, adds script/delayed_job. The rake task will work for now though.
Example 1: Delay SomethingNow the fun part: pick something to delay. A great place for delay is email. I’ve seen places where apps have broken due to email not being able to send. Maybe the client changed their email server and didn’t tell the programmer, or maybe the mail server was temporarily down for maintenance. Either way, it generally shouldn’t stop our app.
Here’s a common controller pattern for a contact form:
def create @contact_form = ContactForm.new(params[:contact_form]) if @contact_form.save flash[:notice] = 'Your feedback has been sent. Thanks for contacting us!' ContactMailer.deliver_contact_request(@contact_form) redirect_to @contact_form else render :action => "new" end endThe problem is that if the mailer fails due to outside circumstances, we’re throwing an error. We could rescue from that, but since there’s nothing the user can do, we shouldn’t involve them.
Instead, let’s send email as a delayed_job, which will retry on failure and also keep track of the last error it sees.
Here’s the refactored action:
def create @contact_form = ContactForm.new(params[:contact_form]) if @contact_form.save flash[:notice] = 'Your feedback has been sent. Thanks for contacting us!' ContactMailer.send_later(:deliver_contact_request, @contact_form) redirect_to @contact_form else render :action => "new" end endThat’s it! send_later works just like send, but magically turns it into a delayed_job. Now our user can keep clicking through the app, and the email will send in a few seconds.
Example 2: A more complex example.My first use of delayed_job was a large import process that could take 5 minutes or more. What’s going on here is the user uploads a large CSV file that we then processed the crap out of, adding hundreds or thousands of rows to different tables.
In my controller, I had something along these lines:
def update @item = Item.find(params[:id]) if @item.update_attributes(params[:item]) @item.import_file.import! redirect_to @item else render :action => 'edit' end endThe problem here is the browser has to sit and wait until the import! method finishes. Not good. There’s no need for the user to wait for the import. We can give them a message in the interface that the import is still in-progress.
So change the controller method above to this:
def update @item = Item.find(params[:id]) if @item.update_attributes(params[:item]) Delayed::Job.enqueue ImportJob.new(@item.import_file) redirect_to @item else render :action => 'edit' end end ImportJob is a simple class I’ve defined and tossed in the lib/ directory. class ImportJob attr_accessor :import_file_id def initialize(import_file) self.import_file_id = import_file.id end def perform import_file = ImportFile.find(import_file_id) import_file.import! import_file.complete! end endAgain, that’s it! Our ImportJob, holding our ImportFile (which is an ActiveRecord object, using attachment_fu) is added to the queue. When we pop it off the queue later, the perform method is called, which does our import. My complete! method sets a completed_at flag so I can tell the user that we’re done.
My real code is a bit more complex, but hopefully you can see how this style can by used for doing multi-step jobs.
Example 3: Tiny but useful.The import job above adds a lot (hundreds) of locations to this app that will show up on a map eventually. I’m using acts_as_geocodable (because it’s awesome) to geocode the addresses via Google & Yahoo, but I don’t need that info right away, and I don’t need it holding up the imports.
acts_as_geocodable does its work by adding an after_filter :attach_geocode automatically to the model you specify.
So for my app, I changed it from an after_filter to a delayed_job.
Here’s all the code it took:
class Location < ActiveRecord::Base acts_as_geocodable # some code removed for clarity def attach_geocode_with_delay self.send_later(:attach_geocode_without_delay) end alias_method_chain :attach_geocode, :delay endVery fun.
Your turnThere’s really not much more to delayed_job than that. Its simplicity is what makes it great. So go and delay something already!
In which I show that XML does not have to suck—instead you can just HappyMap it!
As much as I write about XML, you would swear it is all I do, but I promise it is not. In fact, I do not really use XML that often, but I will admit that I am intrigued by it. A while back, you may remember, I posted about ROXML, a ruby object to xml mapping library. I liked the idea but not the implementation. Soon after, I started playing around with what I have named HappyMapper, a ruby object to xml mapping library.
I wrote nearly 95% of it in a weekend and then let it sit. I let it sit so long that it started to rot. Today it hit me that I do not have to finish something in order to release it. The thing that wasn’t working was xml with a default namespace. For good reasons I am sure, libxml-ruby does not like having default namespaces. I thought to myself, you know, this library is cool even without namespace junk. I mean who even uses namespaces other than Amazon. I started to package it for release and then I noticed a few nitpicky things. I tweaked them and five hours later I had also fixed the namespace issue and changed the API a bit. So much for releasing unfinished code in hopes that someone smarter than I would finish it up…
ExamplesBut I digress, you do not care about all that, right? How about some examples? Twitter’s xml seems to be popular on this here blawg, so I will start with that. Given this xml sample from twitter:
<statuses type="array"> <status> <created_at>Sat Aug 09 05:38:12 +0000 2008</created_at> <id>882281424</id> <text>I so just thought the guy lighting the Olympic torch was falling when he began to run on the wall. Wow that would have been catastrophic.</text> <source>web</source> <truncated>false</truncated> <in_reply_to_status_id>1234</in_reply_to_status_id> <in_reply_to_user_id>12345</in_reply_to_user_id> <favorited></favorited> <user> <id>4243</id> <name>John Nunemaker</name> <screen_name>jnunemaker</screen_name> <location>Mishawaka, IN, US</location> <description>Loves his wife, ruby, notre dame football and iu basketball</description> <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url> <url>http://addictedtonew.com</url> <protected>false</protected> <followers_count>486</followers_count> </user> </status> </statuses>You could setup the following ruby objects:
class User include HappyMapper element :id, Integer element :name, String element :screen_name, String element :location, String element :description, String element :profile_image_url, String element :url, String element :protected, Boolean element :followers_count, Integer end class Status include HappyMapper element :id, Integer element :text, String element :created_at, Time element :source, String element :truncated, Boolean element :in_reply_to_status_id, Integer element :in_reply_to_user_id, Integer element :favorited, Boolean has_one :user, User end statuses = Status.parse(xml_string) statuses.each do |status| puts status.user.name, status.user.screen_name, status.text, status.source, '' endYou can note a few things about HappyMapper from that example.
That was an easy one, how about something more complex and ugly, like some Amazon xml. Given some Amazon xml such as this:
<?xml version="1.0" encoding="UTF-8"?> <ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05"> <OperationRequest> <HTTPHeaders> <Header Name="UserAgent"> </Header> </HTTPHeaders> <RequestId>16WRJBVEM155Q026KCV1</RequestId> <Arguments> <Argument Name="SearchIndex" Value="Books"></Argument> <Argument Name="Service" Value="AWSECommerceService"></Argument> <Argument Name="Title" Value="Ruby on Rails"></Argument> <Argument Name="Operation" Value="ItemSearch"></Argument> <Argument Name="AWSAccessKeyId" Value="dontbeaswoosh"></Argument> </Arguments> <RequestProcessingTime>0.064924955368042</RequestProcessingTime> </OperationRequest> <Items> <Request> <IsValid>True</IsValid> <ItemSearchRequest> <SearchIndex>Books</SearchIndex> <Title>Ruby on Rails</Title> </ItemSearchRequest> </Request> <TotalResults>22</TotalResults> <TotalPages>3</TotalPages> <Item> <ASIN>0321480791</ASIN> <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh</DetailPageURL> <ItemAttributes> <Author>Michael Hartl</Author> <Author>Aurelius Prochazka</Author> <Manufacturer>Addison-Wesley Professional</Manufacturer> <ProductGroup>Book</ProductGroup> <Title>RailsSpace: Building a Social Networking Website with Ruby on Rails (Addison-Wesley Professional Ruby Series)</Title> </ItemAttributes> </Item> </Items> </ItemSearchResponse>You could create the following objects to obtain Item information:
module PITA class Item include HappyMapper tag 'Item' # if you put class in module you need tag element :asin, String, :tag => 'ASIN' element :detail_page_url, String, :tag => 'DetailPageURL' element :manufacturer, String, :tag => 'Manufacturer', :deep => true end class Items include HappyMapper tag 'Items' # if you put class in module you need tag element :total_results, Integer, :tag => 'TotalResults' element :total_pages, Integer, :tag => 'TotalPages' has_many :items, Item end end item = PITA::Items.parse(xml_string, :single => true, :use_default_namespace => true) item.items.each do |i| puts i.asin, i.detail_page_url, i.manufacturer, '' endThe previous example showed a few more things.
Installation is typical as the gem is on rubyforge and github.
#rubyforge $ sudo gem install happymapper # github $ sudo gem install jnunemaker-happymapperIf you run into problems, feel free to fork and add some specs for the xml it is not working with. From there you can dive in and fix them or let me know and I will take a look. Think this will be handy? Got an idea? Let me know in the comments below. Oh, and yes, in the future, HappyMapper will have killer HTTParty integration.
In which I show that XML does not have to suck—instead you can just HappyMap it!
As much as I write about XML, you would swear it is all I do, but I promise it is not. In fact, I do not really use XML that often, but I will admit that I am intrigued by it. A while back, you may remember, I posted about ROXML, a ruby object to xml mapping library. I liked the idea but not the implementation. Soon after, I started playing around with what I have named HappyMapper, a ruby object to xml mapping library.
Logo created by Peter CooperI wrote nearly 95% of it in a weekend and then let it sit. I let it sit so long that it started to rot. Today it hit me that I do not have to finish something in order to release it. The thing that wasn’t working was xml with a default namespace. For good reasons I am sure, libxml-ruby does not like having default namespaces. I thought to myself, you know, this library is cool even without namespace junk. I mean who even uses namespaces other than Amazon. I started to package it for release and then I noticed a few nitpicky things. I tweaked them and five hours later I had also fixed the namespace issue and changed the API a bit. So much for releasing unfinished code in hopes that someone smarter than I would finish it up…
But I digress, you do not care about all that, right? How about some examples? Twitter’s xml seems to be popular on this here blawg, so I will start with that. Given this xml sample from twitter:
<statuses type="array"> <status> <created_at>Sat Aug 09 05:38:12 +0000 2008</created_at> <id>882281424</id> <text>I so just thought the guy lighting the Olympic torch was falling when he began to run on the wall. Wow that would have been catastrophic.</text> <source>web</source> <truncated>false</truncated> <in_reply_to_status_id>1234</in_reply_to_status_id> <in_reply_to_user_id>12345</in_reply_to_user_id> <favorited></favorited> <user> <id>4243</id> <name>John Nunemaker</name> <screen_name>jnunemaker</screen_name> <location>Mishawaka, IN, US</location> <description>Loves his wife, ruby, notre dame football and iu basketball</description> <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url> <url>http://addictedtonew.com</url> <protected>false</protected> <followers_count>486</followers_count> </user> </status> </statuses>You could setup the following ruby objects:
class User include HappyMapper element :id, Integer element :name, String element :screen_name, String element :location, String element :description, String element :profile_image_url, String element :url, String element :protected, Boolean element :followers_count, Integer end class Status include HappyMapper element :id, Integer element :text, String element :created_at, Time element :source, String element :truncated, Boolean element :in_reply_to_status_id, Integer element :in_reply_to_user_id, Integer element :favorited, Boolean has_one :user, User end statuses = Status.parse(xml_string) statuses.each do |status| puts status.user.name, status.user.screen_name, status.text, status.source, '' endYou can note a few things about HappyMapper from that example.
That was an easy one, how about something more complex and ugly, like some Amazon xml. Given some Amazon xml such as this:
<?xml version="1.0" encoding="UTF-8"?> <ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05"> <OperationRequest> <HTTPHeaders> <Header Name="UserAgent"> </Header> </HTTPHeaders> <RequestId>16WRJBVEM155Q026KCV1</RequestId> <Arguments> <Argument Name="SearchIndex" Value="Books"></Argument> <Argument Name="Service" Value="AWSECommerceService"></Argument> <Argument Name="Title" Value="Ruby on Rails"></Argument> <Argument Name="Operation" Value="ItemSearch"></Argument> <Argument Name="AWSAccessKeyId" Value="dontbeaswoosh"></Argument> </Arguments> <RequestProcessingTime>0.064924955368042</RequestProcessingTime> </OperationRequest> <Items> <Request> <IsValid>True</IsValid> <ItemSearchRequest> <SearchIndex>Books</SearchIndex> <Title>Ruby on Rails</Title> </ItemSearchRequest> </Request> <TotalResults>22</TotalResults> <TotalPages>3</TotalPages> <Item> <ASIN>0321480791</ASIN> <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh</DetailPageURL> <ItemAttributes> <Author>Michael Hartl</Author> <Author>Aurelius Prochazka</Author> <Manufacturer>Addison-Wesley Professional</Manufacturer> <ProductGroup>Book</ProductGroup> <Title>RailsSpace: Building a Social Networking Website with Ruby on Rails (Addison-Wesley Professional Ruby Series)</Title> </ItemAttributes> </Item> </Items> </ItemSearchResponse>You could create the following objects to obtain Item information:
module PITA class Item include HappyMapper tag 'Item' # if you put class in module you need tag element :asin, String, :tag => 'ASIN' element :detail_page_url, String, :tag => 'DetailPageURL' element :manufacturer, String, :tag => 'Manufacturer', :deep => true end class Items include HappyMapper tag 'Items' # if you put class in module you need tag element :total_results, Integer, :tag => 'TotalResults' element :total_pages, Integer, :tag => 'TotalPages' has_many :items, Item end end item = PITA::Items.parse(xml_string, :single => true, :use_default_namespace => true) item.items.each do |i| puts i.asin, i.detail_page_url, i.manufacturer, '' endThe previous example showed a few more things.
Installation is typical as the gem is on rubyforge and github.
#rubyforge $ sudo gem install happymapper # github $ sudo gem install jnunemaker-happymapperIf you run into problems, feel free to fork and add some specs for the xml it is not working with. From there you can dive in and fix them or let me know and I will take a look. Think this will be handy? Got an idea? Let me know in the comments below. Oh, and yes, in the future, HappyMapper will have killer HTTParty integration.
In which I discuss method visibility and the subtle difference between protected and private in hopes of clearing things up for those new to ruby.
One thing that I remember as confusing when I was starting out in ruby was “protected.” I understood the difference between private and public, but I remember protected seeming mysterious for quite a while. In the same vein as my class and instance variables article, I’ve decided to throw some examples together in hopes that those new to ruby will find it helpful. If I miss anything or am flat out wrong on something, let me know in the comments.
PublicIf you don’t explicitly state private or protected, your methods are public. This is pretty easy to understand and the code samples below show that public methods can be called for an instance of a class, in an instance of an unrelated class and in an instance of an inherited class. In other words, you can call a public methods wherever you want.
class A def foo puts 'foo in A' end end a = A.new a.foo class B def foo puts 'foo in B' a = A.new a.foo end end b = B.new b.foo class C < A def bar puts 'foo in C' foo end end c = C.new c.bar # Outputs: # foo in A # foo in B # foo in A # foo in C # foo in A PrivatePrivate methods are named that for a reason. It means that they are private to the class they belong to and cannot be used outside of that class, without using send.
class A private def foo puts 'foo in A' end end a = A.new a.foo # NoMethodError: private method ???foo??? called for ...Likewise, as one would expect, subclassing and attempting to use a private method outside of the class definition will result in much of the same.
class A private def foo puts 'foo in A' end end class B < A end b = B.new b.foo # NoMethodError: private method ???foo??? called for ... Valid Private UsesYou can however use private methods inside of a class definition and inside of a subclass definition.
class A def bar puts 'bar in A' foo end private def foo puts 'foo in A' end end class B < A def baz puts 'baz in B' foo end end a = A.new a.bar b = B.new b.baz # Outputs: # bar in A # foo in A # baz in B # foo in A ProtectedProtected is similar to private but has one quite subtle difference. Like private, protected cannot be used outside of the class definition.
class A protected def foo puts 'foo in A' end end a = A.new a.foo # NoMethodError: protected method ???foo??? called for ... class B < A end b = B.new b.foo # NoMethodError: protected method ???foo??? called for ...Also, like private, you can use protected inside of a class definition as long as it is wrapped with a public method.
class A def bar puts 'bar in A' foo end protected def foo puts 'foo in A' end end a = A.new a.bar class B < A def baz puts 'baz in B' foo end end b = B.new b.baz # Outputs: # bar in A # foo in A # baz in B # foo in A The Subtle DifferenceThis is where the weird part of protected comes in. You can instantiate a class and call a protected instance method on that class inside of a subclass and things will work just fine.
class A protected def foo puts 'foo in A' end end class B < A def baz puts 'baz in B' a = A.new a.foo end end b = B.new b.baz # Outputs: # baz in B # foo in AThe same is not true of private, however, and you will end up with a NoMethodError.
class A private def foo puts 'foo in A' end end class B < A def baz puts 'baz in B' a = A.new a.foo end end b = B.new b.baz # Outputs: # baz in B # NoMethodError: private method ???foo??? called for ... More on Method VisibilityJamis Buck posted a great article on this a while ago. I am hoping the fact that I did not use metaprogramming in my examples will help those who are just starting out and might not understand the syntax in Jamis’ post. That said, his article is definitely worth a read as well.
In which I discuss method visibility and the subtle difference between protected and private in hopes of clearing things up for those new to ruby.
One thing that I remember as confusing when I was starting out in ruby was “protected.” I understood the difference between private and public, but I remember protected seeming mysterious for quite a while. In the same vein as my class and instance variables article, I’ve decided to throw some examples together in hopes that those new to ruby will find it helpful. If I miss anything or am flat out wrong on something, let me know in the comments.
PublicIf you don’t explicitly state private or protected, your methods are public. This is pretty easy to understand and the code samples below show that public methods can be called for an instance of a class, in an instance of an unrelated class and in an instance of an inherited class. In other words, you can call a public methods wherever you want.
class A def foo puts 'foo in A' end end a = A.new a.foo class B def foo puts 'foo in B' a = A.new a.foo end end b = B.new b.foo class C < A def bar puts 'foo in C' foo end end c = C.new c.bar # Outputs: # foo in A # foo in B # foo in A # foo in C # foo in A PrivatePrivate methods are named that for a reason. It means that they are private to the class they belong to and cannot be used outside of that class, without using send.
class A private def foo puts 'foo in A' end end a = A.new a.foo # NoMethodError: private method ‘foo’ called for ...Likewise, as one would expect, subclassing and attempting to use a private method outside of the class definition will result in much of the same.
class A private def foo puts 'foo in A' end end class B < A end b = B.new b.foo # NoMethodError: private method ‘foo’ called for ... Valid Private UsesYou can however use private methods inside of a class definition and inside of a subclass definition.
class A def bar puts 'bar in A' foo end private def foo puts 'foo in A' end end class B < A def baz puts 'baz in B' foo end end a = A.new a.bar b = B.new b.baz # Outputs: # bar in A # foo in A # baz in B # foo in A ProtectedProtected is similar to private but has one quite subtle difference. Like private, protected cannot be used outside of the class definition.
class A protected def foo puts 'foo in A' end end a = A.new a.foo # NoMethodError: protected method ‘foo’ called for ... class B < A end b = B.new b.foo # NoMethodError: protected method ‘foo’ called for ...Also, like private, you can use protected inside of a class definition as long as it is wrapped with a public method.
class A def bar puts 'bar in A' foo end protected def foo puts 'foo in A' end end a = A.new a.bar class B < A def baz puts 'baz in B' foo end end b = B.new b.baz # Outputs: # bar in A # foo in A # baz in B # foo in A The Subtle DifferenceThis is where the weird part of protected comes in. You can instantiate a class and call a protected instance method on that class inside of a subclass and things will work just fine.
class A protected def foo puts 'foo in A' end end class B < A def baz puts 'baz in B' a = A.new a.foo end end b = B.new b.baz # Outputs: # baz in B # foo in AThe same is not true of private, however, and you will end up with a NoMethodError.
class A private def foo puts 'foo in A' end end class B < A def baz puts 'baz in B' a = A.new a.foo end end b = B.new b.baz # Outputs: # baz in B # NoMethodError: private method ‘foo’ called for ... More on Method VisibilityJamis Buck posted a great article on this a while ago. I am hoping the fact that I did not use metaprogramming in my examples will help those who are just starting out and might not understand the syntax in Jamis’ post. That said, his article is definitely worth a read as well.
In which I show that XML does not have to suck—instead you can just HappyMap it!
As much as I write about XML, you would swear it is all I do, but I promise it is not. In fact, I do not really use XML that often, but I will admit that I am intrigued by it. A while back, you may remember, I posted about ROXML, a ruby object to xml mapping library. I liked the idea but not the implementation. Soon after, I started playing around with what I have named HappyMapper, a ruby object to xml mapping library.
Logo created by Peter CooperI wrote nearly 95% of it in a weekend and then let it sit. I let it sit so long that it started to rot. Today it hit me that I do not have to finish something in order to release it. The thing that wasn’t working was xml with a default namespace. For good reasons I am sure, libxml-ruby does not like having default namespaces. I thought to myself, you know, this library is cool even without namespace junk. I mean who even uses namespaces other than Amazon. I started to package it for release and then I noticed a few nitpicky things. I tweaked them and five hours later I had also fixed the namespace issue and changed the API a bit. So much for releasing unfinished code in hopes that someone smarter than I would finish it up…
But I digress, you do not care about all that, right? How about some examples? Twitter’s xml seems to be popular on this here blawg, so I will start with that. Given this xml sample from twitter:
<statuses type="array"> <status> <created_at>Sat Aug 09 05:38:12 +0000 2008</created_at> <id>882281424</id> <text>I so just thought the guy lighting the Olympic torch was falling when he began to run on the wall. Wow that would have been catastrophic.</text> <source>web</source> <truncated>false</truncated> <in_reply_to_status_id>1234</in_reply_to_status_id> <in_reply_to_user_id>12345</in_reply_to_user_id> <favorited></favorited> <user> <id>4243</id> <name>John Nunemaker</name> <screen_name>jnunemaker</screen_name> <location>Mishawaka, IN, US</location> <description>Loves his wife, ruby, notre dame football and iu basketball</description> <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url> <url>http://addictedtonew.com</url> <protected>false</protected> <followers_count>486</followers_count> </user> </status> </statuses>You could setup the following ruby objects:
class User include HappyMapper element :id, Integer element :name, String element :screen_name, String element :location, String element :description, String element :profile_image_url, String element :url, String element :protected, Boolean element :followers_count, Integer end class Status include HappyMapper element :id, Integer element :text, String element :created_at, Time element :source, String element :truncated, Boolean element :in_reply_to_status_id, Integer element :in_reply_to_user_id, Integer element :favorited, Boolean has_one :user, User end statuses = Status.parse(xml_string) statuses.each do |status| puts status.user.name, status.user.screen_name, status.text, status.source, '' endYou can note a few things about HappyMapper from that example.
That was an easy one, how about something more complex and ugly, like some Amazon xml. Given some Amazon xml such as this:
<?xml version="1.0" encoding="UTF-8"?> <ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05"> <OperationRequest> <HTTPHeaders> <Header Name="UserAgent"> </Header> </HTTPHeaders> <RequestId>16WRJBVEM155Q026KCV1</RequestId> <Arguments> <Argument Name="SearchIndex" Value="Books"></Argument> <Argument Name="Service" Value="AWSECommerceService"></Argument> <Argument Name="Title" Value="Ruby on Rails"></Argument> <Argument Name="Operation" Value="ItemSearch"></Argument> <Argument Name="AWSAccessKeyId" Value="dontbeaswoosh"></Argument> </Arguments> <RequestProcessingTime>0.064924955368042</RequestProcessingTime> </OperationRequest> <Items> <Request> <IsValid>True</IsValid> <ItemSearchRequest> <SearchIndex>Books</SearchIndex> <Title>Ruby on Rails</Title> </ItemSearchRequest> </Request> <TotalResults>22</TotalResults> <TotalPages>3</TotalPages> <Item> <ASIN>0321480791</ASIN> <DetailPageURL>http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh</DetailPageURL> <ItemAttributes> <Author>Michael Hartl</Author> <Author>Aurelius Prochazka</Author> <Manufacturer>Addison-Wesley Professional</Manufacturer> <ProductGroup>Book</ProductGroup> <Title>RailsSpace: Building a Social Networking Website with Ruby on Rails (Addison-Wesley Professional Ruby Series)</Title> </ItemAttributes> </Item> </Items> </ItemSearchResponse>You could create the following objects to obtain Item information:
module PITA class Item include HappyMapper tag 'Item' # if you put class in module you need tag element :asin, String, :tag => 'ASIN' element :detail_page_url, String, :tag => 'DetailPageURL' element :manufacturer, String, :tag => 'Manufacturer', :deep => true end class Items include HappyMapper tag 'Items' # if you put class in module you need tag element :total_results, Integer, :tag => 'TotalResults' element :total_pages, Integer, :tag => 'TotalPages' has_many :items, Item end end item = PITA::Items.parse(xml_string, :single => true, :use_default_namespace => true) item.items.each do |i| puts i.asin, i.detail_page_url, i.manufacturer, '' endThe previous example showed a few more things.
Installation is typical as the gem is on rubyforge and github.
#rubyforge $ sudo gem install happymapper # github $ sudo gem install jnunemaker-happymapperIf you run into problems, feel free to fork and add some specs for the xml it is not working with. From there you can dive in and fix them or let me know and I will take a look. Think this will be handy? Got an idea? Let me know in the comments below. Oh, and yes, in the future, HappyMapper will have killer HTTParty integration.
In which I discuss how to automatically stamp your models with who done it.
Something I do in every app I create is add creator_id and updater_id to nearly every model. As created_at and updated_at are known as timestamping, I refer to my creator and updater attributes as “user stamping.” The annoying part is in every controller I had to assign those attributes to the currently logged in user. This isn’t a big deal but I’m lazy so I started to look for solutions.
Thread.currentThe first thing that popped into my head was Thread.current. Thread.current is basically a hash that allows you to assign thread-safe key value pairs for the current thread. My thought, based on some research, was to wrap Thread.current[:myapp_user_id] with User.current so I could just use User.current in any active record model. Only problem is that smelled a little bit and I figured would be frowned upon by the community as you really shouldn’t access request stuff in your models like that. You can read more about threads and Thread.current if you want.
Solution: SweeperI brainstormed a bit with Brandon Keepers and he suggested a few things. Eventually, we decided on a sweeper as they have access to controllers which would have access to the current user. Tada! User Stamp, the plugin, was born. I whipped it together last night (< 50 LOC), added a few specs, and put it up on github this morning.
InstallationInstallation is uber predictable.
script/plugin install git://github.com/jnunemaker/user_stamp.gitOnce plugin is installed and user_stamp call with list of models to track in application.rb.
class ApplicationController < ActionController::Base user_stamp Post, Asset, Job endIf you actually want to access this stuff through associations and show it in your app you could do something like this:
class Post < ActiveRecord::Base belongs_to :creator, :class_name => 'User' belongs_to :updater, :class_name => 'User' endThen, say in a view, you could do the following:
<h1><%=h @post.name %></h1> <div><%= @post.content %></div> <p>Posted by <%=h @post.creator.name %></p>Let me know what you think in the comments. Bugs can be reported in lighthouse.
In which I extol the virtues of Isaac for working with IRC in Ruby and at the same time beg library authors to rethink their APIs.
My favorite Campfire feature is the history. I love that it persists between Campfire sessions. On the opposite side of the spectrum, I hate that IRC doesn’t. I decided it would be nice to have a bot that sits in the room and stores all the chatter to the database. Once that was working, it would be handy to have a simple web front end that allowed searching and viewing by day. I have seen sites out there that do that but like any programmer decided to make something for myself.
Finding Some CodeFirst up, I needed to find a good IRC library for Ruby. I did research for about 30 minutes and found a ton of libraries on GitHub: Net/IRC, on_irc, irc4r, irkr, rbot, minibot, kirby and autumn. I even came across the code that runs rails.loglibrary.com, which is kind of what I want to do but not quite. Each library did things a bit differently and they all had their strengths and weaknesses, but one thing stood out: they almost all required that I was familiar with IRC protocols and terminologies.
The SolutionIf I was getting paid to do this, I would want to know inside and out how things work. Because this is a side project, I just wanted to get up and running quickly. At that moment, I remembered SearchParty (which incidentally runs on Sinatra) and headed over there to search for irc. Right at the top of my delicious items was Isaac, which I had totally forgotten about.
“You want to create an IRC bot quickly? Then Isaac is you.”
Yes, I want to create an IRC bot quickly. That is exactly what I want to do.
“Be aware…a large portion of the IRC standard has not been implemented, simply because I haven’t needed it yet.”
I don’t care if the entire spec is implemented. All I care about is whether or not the stuff I want is implemented and what the API is in Ruby to do that stuff.
The CodeA few minutes later, I had the following snippet of code running which allowed my bot to login to an IRC room and listen to all the chatter. Wow. Awesome.
require 'rubygems' require 'isaac' config do |c| c.nick = "fantasticalbot" c.server = "irc.freenode.net" c.port = 6667 end on :connect do join "#fantasticalroom" end on :channel, /.*/ do msg channel, "Got your message #{nick} (#{match[0]})" endIf you have used Sinatra, you can immediately see the similarities. You can even define helpers in the same way that you would with Sinatra. Now this doesn’t do everything I mentioned that I want to do, but it was a nice start. All that is left is to drop in ActiveRecord or DataMapper or implement some kind of a web hook to an app and I am good to go.
ConclusionThere are two points to this article. The first is that Isaac is really cool if you want to dabble with IRC from Ruby. The second point, and probably more important, is when you create a library, think about the API that other programmers will use more than you think about the spec you are implementing. I suspect few people out there want to learn every spec that they work with. Most people are probably like me and have a simple need and want a simple solution.
This is one of the reasons HTTParty was created and why I am now working on IMAParty. Spec is important, but every “to the spec” library needs a simplistic DSL on top that makes them easy to use for the 80% of people that only need 20% of the features.
In which I extol the virtues of Isaac for working with IRC in Ruby and at the same time beg library authors to rethink their APIs.
My favorite Campfire feature is the history. I love that it persists between Campfire sessions. On the opposite side of the spectrum, I hate that IRC doesn’t. I decided it would be nice to have a bot that sits in the room and stores all the chatter to the database. Once that was working, it would be handy to have a simple web front end that allowed searching and viewing by day. I have seen sites out there that do that but like any programmer decided to make something for myself.
Finding Some CodeFirst up, I needed to find a good IRC library for Ruby. I did research for about 30 minutes and found a ton of libraries on GitHub: Net/IRC, on_irc, irc4r, irkr, rbot, minibot, kirby and autumn. I even came across the code that runs rails.loglibrary.com, which is kind of what I want to do but not quite. Each library did things a bit differently and they all had their strengths and weaknesses, but one thing stood out: they almost all required that I was familiar with IRC protocols and terminologies.
The SolutionIf I was getting paid to do this, I would want to know inside and out how things work. Because this is a side project, I just wanted to get up and running quickly. At that moment, I remembered SearchParty (which incidentally runs on Sinatra) and headed over there to search for irc. Right at the top of my delicious items was Isaac, which I had totally forgotten about.
“You want to create an IRC bot quickly? Then Isaac is you.”
Yes, I want to create an IRC bot quickly. That is exactly what I want to do.
“Be aware…a large portion of the IRC standard has not been implemented, simply because I haven???t needed it yet.”
I don’t care if the entire spec is implemented. All I care about is whether or not the stuff I want is implemented and what the API is in Ruby to do that stuff.
The CodeA few minutes later, I had the following snippet of code running which allowed my bot to login to an IRC room and listen to all the chatter. Wow. Awesome.
require 'rubygems' require 'isaac' config do |c| c.nick = "fantasticalbot" c.server = "irc.freenode.net" c.port = 6667 end on :connect do join "#fantasticalroom" end on :channel, /.*/ do msg channel, "Got your message #{nick} (#{match[0]})" endIf you have used Sinatra, you can immediately see the similarities. You can even define helpers in the same way that you would with Sinatra. Now this doesn’t do everything I mentioned that I want to do, but it was a nice start. All that is left is to drop in ActiveRecord or DataMapper or implement some kind of a web hook to an app and I am good to go.
ConclusionThere are two points to this article. The first is that Isaac is really cool if you want to dabble with IRC from Ruby. The second point, and probably more important, is when you create a library, think about the API that other programmers will use more than you think about the spec you are implementing. I suspect few people out there want to learn every spec that they work with. Most people are probably like me and have a simple need and want a simple solution.
This is one of the reasons HTTParty was created and why I am now working on IMAParty. Spec is important, but every “to the spec” library needs a simplistic DSL on top that makes them easy to use for the 80% of people that only need 20% of the features.
In which I show how to create and integrate handy dandy bookmarklets with your Rails app.
If your application stores information, one of the most critical keys to success is allowing users to get that information in quick. If the process is a pain, they’ll move on to something else. One way to allow for easy and quick data entry is a bookmarklet. I recently created a couple for an app I am scratching an itch with and thought I would share the results with you.
Two FYIs: For some reason I sniffed twice during the recording, but I decided to leave them both in to add some “reality.” Also, the ND YouTube tab was open because I was going to show how the tumblr bookmarklet works, not because I forgot the tab open.
Creating and Integrating Bookmarklets with Rails
In which I beg you, the fair reader, to suggest topics for me to cover. Go on, it won’t hurt. I promise.
I get inspiration for topics on my own, but I thought I would also open it up to the populace. If you have a topic you’d like me to write about here, let me know. I’ve setup a topic forum on uservoice. I also put a link in the header of this site that links to the uservoice forum.
I’ve seen several applications try this out and I’m curious to see if it works for blogs. If I don’t get anything over the next while I’ll take it down, but who knows, maybe you all have some good ideas. If there is anything you don’t know how to do or would like to learn more about in ruby or rails, suggest a topic today.
Update (Oct 15): Wow. Already 10 topics suggested. All of them seem worthy of a post too. Fun thing is I’ll have to do some research for a couple of them as I’m not even up on the topic.
In which I show how to create and integrate handy dandy bookmarklets with your Rails app.
If your application stores information, one of the most critical keys to success is allowing users to get that information in quick. If the process is a pain, they’ll move on to something else. One way to allow for easy and quick data entry is a bookmarklet. I recently created a couple for an app I am scratching an itch with and thought I would share the results with you.
Two FYIs: For some reason I sniffed twice during the recording, but I decided to leave them both in to add some “reality.” Also, the ND YouTube tab was open because I was going to show how the tumblr bookmarklet works, not because I forgot the tab open.
Creating and Integrating Bookmarklets with Rails
In which I further extol the virtues of RubyConf with a wrap up post covering the final two days.
I lost the steam to write about each day individually as the last two days always seem to fly by much faster than the first. That said, here are the notes I could gather from my moleskin and varioius sheets of paper I scratched on.
ThursdayJon Dahl had an interesting talk on Aristotle and Software.
Ben Scofield talked about All I Really Need to Know* I Learned by Writing My Own Web Framework. I can’t say that we need another web framework for ruby right now but I enjoyed this talk. Ben’s whole point was how much he learned by writing a web framework from scratch. I couldn’t agree more. I haven’t written my own web framework but writing pure ruby is really the best way to learn ruby. You can’t really learn ruby by just writing rails apps.
Dean Wampler talked about Better Ruby Through Functional Programming. Functional programming seems really interesting. Basically, variables are immutable. Because they don’t change state, it is easier to write “side effect free” concurrent code. Recursion is big in functional programming. Basically recursion in functional programming is equivalent to loops in sequential programming (ruby is sequential). I haven’t really looked at any functional languages and I thoroughly enjoy thinking about things in a different way so this talk was good.
Jim Weirich had an awesome presentation on “What Every Rubyist Should Know About Threads.” Threads were a hot topic as I mentioned in my day one summary. Jim explained that Moore’s Law is no longer true, so concurrency is going to be important. Instead of getting faster CPUs, computers are getting multiple CPUs. In order to fully take advantage of multiple CPUs, you have to be able to have native threads. Ruby 1.9 gets closer to native threads but isn’t there. In order to safely program concurrently in Ruby, Jim gave four tips:
Basically, threading is hard. He gave a really quick mention of Clojure, a dynamic programming language that targets the Java Virtual Machine.
Yehuda Katz gave a worthwhile presentation on “Writing Code That Doesn’t Suck: Interface Oriented Design.” The talk started pretty slow and I nearly tuned out as he just covered concepts, but gave no code examples. Once he finally got to the code, I enjoyed the thoughts and examples.
The premise is that most of us test implementation more than we test results, which is what we really care about. Test what you do not want to break. Unit testing is great for isolation but it is not regression testing. I’ve been thinking about something similar to this a lot lately since I started using RSpec on all projects, so it was interesting to hear this perspective. I’ll definitely be testing more based on results rather than on implementation in the future.
Rich Kilmer presented on OS X Application Development with HotCocoa and man was it hot. HotCocoa is an awesome wrapper around MacRuby that makes building cocoa apps sane. I cannot wait to try this out. It comes bundled with MacRuby so simple install and enjoy. There is not much online about HotCocoa as it is only about 3 months old but when the video comes out give this talk a watch. You’ll be amazed. It appears to make cocoa development as easy as HTTParty makes web services.
Dave Thomas’ keynote fricken rocked. Basically he said we should fork ruby and try out some crazy ideas. He then recanted at the end, but the notion that ruby should be extended and played around with more was pretty interesting. The ideas he mentioned were RubyLite, Parallel Ruby (Puby or Pruby), Optionally Typed Ruby (Otuby) and Closure Based Ruby (Cluby). Cluby was really interesting. It bordered on JavaScript in places but I am a fan of JS so that did not bother me. Dave really challenged the community to think differently and try some stuff out.
Thursday night after Dave’s keynote, Pivotal Labs threw a poolside party in honor of Tracker, which was a good time. I had a great discussion about Merb and about CouchDB with Matt Aimonetti and was nearly pushed into the pool, during a discussion of whether or not I should open source a sweet web analytics app I’m working on with my friend Chas.
FridayFriday I only attended one presentation, but it was possibly my favorite day. Over lunch and through most of the afternoon, I had a great chat with Ryan Daigle, Nathaniel Talbott and Geoff Grosenbach. I think often times at technical conferences we get caught up in code and miss out on a wealth of business knowledge. We talked about “to partner” or “not to partner”, predictable markets, passive income, productivity, efficiency, ideas and a whole lot more.
RubyConf was a blast this year. I finally felt comfortable pretty much the whole time and felt like I opened up a lot. Thanks to all who said hi and to those I did not get to meet…cheers to next year.
In which I further extol the virtues of RubyConf with a wrap up post covering the final two days.
I lost the steam to write about each day individually as the last two days always seem to fly by much faster than the first. That said, here are the notes I could gather from my moleskin and varioius sheets of paper I scratched on.
ThursdayJon Dahl had an interesting talk on Aristotle and Software.
Ben Scofield talked about All I Really Need to Know* I Learned by Writing My Own Web Framework. I can’t say that we need another web framework for ruby right now but I enjoyed this talk. Ben’s whole point was how much he learned by writing a web framework from scratch. I couldn’t agree more. I haven’t written my own web framework but writing pure ruby is really the best way to learn ruby. You can’t really learn ruby by just writing rails apps.
Dean Wampler talked about Better Ruby Through Functional Programming. Functional programming seems really interesting. Basically, variables are immutable. Because they don’t change state, it is easier to write “side effect free” concurrent code. Recursion is big in functional programming. Basically recursion in functional programming is equivalent to loops in sequential programming (ruby is sequential). I haven’t really looked at any functional languages and I thoroughly enjoy thinking about things in a different way so this talk was good.
Jim Weirich had an awesome presentation on “What Every Rubyist Should Know About Threads.” Threads were a hot topic as I mentioned in my day one summary. Jim explained that Moore’s Law is no longer true, so concurrency is going to be important. Instead of getting faster CPUs, computers are getting multiple CPUs. In order to fully take advantage of multiple CPUs, you have to be able to have native threads. Ruby 1.9 gets closer to native threads but isn’t there. In order to safely program concurrently in Ruby, Jim gave four tips:
Basically, threading is hard. He gave a really quick mention of Clojure, a dynamic programming language that targets the Java Virtual Machine.
Yehuda Katz gave a worthwhile presentation on “Writing Code That Doesn’t Suck: Interface Oriented Design.” The talk started pretty slow and I nearly tuned out as he just covered concepts, but gave no code examples. Once he finally got to the code, I enjoyed the thoughts and examples.
The premise is that most of us test implementation more than we test results, which is what we really care about. Test what you do not want to break. Unit testing is great for isolation but it is not regression testing. I’ve been thinking about something similar to this a lot lately since I started using RSpec on all projects, so it was interesting to hear this perspective. I’ll definitely be testing more based on results rather than on implementation in the future.
Rich Kilmer presented on OS X Application Development with HotCocoa and man was it hot. HotCocoa is an awesome wrapper around MacRuby that makes building cocoa apps sane. I cannot wait to try this out. It comes bundled with MacRuby so simple install and enjoy. There is not much online about HotCocoa as it is only about 3 months old but when the video comes out give this talk a watch. You’ll be amazed. It appears to make cocoa development as easy as HTTParty makes web services.
Dave Thomas’ keynote fricken rocked. Basically he said we should fork ruby and try out some crazy ideas. He then recanted at the end, but the notion that ruby should be extended and played around with more was pretty interesting. The ideas he mentioned were RubyLite, Parallel Ruby (Puby or Pruby), Optionally Typed Ruby (Otuby) and Closure Based Ruby (Cluby). Cluby was really interesting. It bordered on JavaScript in places but I am a fan of JS so that did not bother me. Dave really challenged the community to think differently and try some stuff out.
Thursday night after Dave’s keynote, Pivotal Labs threw a poolside party in honor of Tracker, which was a good time. I had a great discussion about Merb and about CouchDB with Matt Aimonetti and was nearly pushed into the pool, during a discussion of whether or not I should open source a sweet web analytics app I’m working on with my friend Chas.
FridayFriday I only attended one presentation, but it was possibly my favorite day. Over lunch and through most of the afternoon, I had a great chat with Ryan Daigle, Nathaniel Talbott and Geoff Grosenbach. I think often times at technical conferences we get caught up in code and miss out on a wealth of business knowledge. We talked about “to partner” or “not to partner”, predictable markets, passive income, productivity, efficiency, ideas and a whole lot more.
RubyConf was a blast this year. I finally felt comfortable pretty much the whole time and felt like I opened up a lot. Thanks to all who said hi and to those I did not get to meet…cheers to next year.
In which I cover the highs and lows of day one at RubyConf 2008 in Orlando.
So yesterday was day one of RubyConf in Orlando. I’m not keeping really detailed notes as I’m trying to pay attention more and note taking seems to hinder that but I’ll give a quick overview.
Matz KeynoteThe day started with Matz keynote. As always, he was pleasant and pretty funny. He spoke about his reasons for ruby and confessed his love for all of us. Search twitter for Matz and you can find a bunch of his good quotes from the keynote.
Gregg Pollack – Scaling RubyNext up was Gregg Pollack’s talk on Scaling Ruby (without Rails). Side note: scaling does not appear to be a direct topic at the conference but threads, concurrency and distributed programming are getting some heavy coverage. Gregg had possibly the best put together presentation I have ever witnessed. I talked to him later and he said it was all keynote but I think it was black magic.
He started by going through a wonderful explanation of threading and the benefits of single threaded vs. multi-threaded. After threading, he dove into message queues and did a wonderful demo of Starling. He closed the talk covering ruby prof, how to profile and some examples of what is expensive in ruby. The concepts he covered are not simple ones but Gregg did a phenomenal job of making them appear simple with great visual aides. He has a pdf on the RailsEnvy site and his talk has been released as an EnvyCast.
Scott Chacon – Using Git in Ruby AppsAt RailsConf Scott did a presentation on git that broke the record for number of slides. This talk was not as fast paced, but I enjoyed it a lot more. It was one of those talks that instantly started firing neurons in my brain, mostly because I hadn’t really thought a lot about using Git for storage in an app. Examples Scott gave were git-wiki, ticgit, sqlgit and grit (which powers github).
Jamis BuckJamis did a presentation on how to say goodbye to the enterprise and embrace Ruby’s idioms. I didn’t really come from the enterprise but that is not to say that I don’t have bad habits. He had a couple of good quotes.
I was on the dependency injection horse and riding it for all it was worth.
I’m not into dependency injection but that cracked me up. If you don’t know what DI is, it’s ok as Jamis said you are probably better off.
Code just in time, not just in case.
This hit home. Often times I think what I might need down the rode but I always end up with a more complex solution than when I just create something that I need. It is far easier to add more code than to remove code at a later date.
The EveningThere are always a few presentations that really get me thinking, but the best part of any conference is hanging out with people who share the same passions. In the evening, I went out to eat at Chili’s with Ryan Daigle, James Avery and Corey Haines. We had some rousing discussions about perfectionism, getting stuff out there, building apps, ideas, blogging and advertising.
ConclusionI have found it really interesting what a hot topic threading is this year. I have recently been reading up on Threads in ruby and how they work and I will post some stuff here at some point. It is kind of interesting to see how each conference kind of ends up with an overall theme, despite the lack of collaboration between presenters and no theme being stated by conference organizers.
Last year I blogged some suggestions for RubyConf. I have no idea if it helped but the name tag font size was markedly larger and it seems like things are starting a bit later. Not 10 but today’s talks started at 9:30 which is far easier to stumble stroll into. That is all for day one. Nunemaker out.
In which I cover the highs and lows of day one at RubyConf 2008 in Orlando.
So yesterday was day one of RubyConf in Orlando. I’m not keeping really detailed notes as I’m trying to pay attention more and note taking seems to hinder that but I’ll give a quick overview.
Matz KeynoteThe day started with Matz keynote. As always, he was pleasant and pretty funny. He spoke about his reasons for ruby and confessed his love for all of us. Search twitter for Matz and you can find a bunch of his good quotes from the keynote.
Gregg Pollack – Scaling RubyNext up was Gregg Pollack’s talk on Scaling Ruby (without Rails). Side note: scaling does not appear to be a direct topic at the conference but threads, concurrency and distributed programming are getting some heavy coverage. Gregg had possibly the best put together presentation I have ever witnessed. I talked to him later and he said it was all keynote but I think it was black magic.
He started by going through a wonderful explanation of threading and the benefits of single threaded vs. multi-threaded. After threading, he dove into message queues and did a wonderful demo of Starling. He closed the talk covering ruby prof, how to profile and some examples of what is expensive in ruby. The concepts he covered are not simple ones but Gregg did a phenomenal job of making them appear simple with great visual aides. He has a pdf on the RailsEnvy site and his talk has been released as an EnvyCast.
Scott Chacon – Using Git in Ruby AppsAt RailsConf Scott did a presentation on git that broke the record for number of slides. This talk was not as fast paced, but I enjoyed it a lot more. It was one of those talks that instantly started firing neurons in my brain, mostly because I hadn’t really thought a lot about using Git for storage in an app. Examples Scott gave were git-wiki, ticgit, sqlgit and grit (which powers github).
Jamis BuckJamis did a presentation on how to say goodbye to the enterprise and embrace Ruby’s idioms. I didn’t really come from the enterprise but that is not to say that I don’t have bad habits. He had a couple of good quotes.
I was on the dependency injection horse and riding it for all it was worth.
I’m not into dependency injection but that cracked me up. If you don’t know what DI is, it’s ok as Jamis said you are probably better off.
Code just in time, not just in case.
This hit home. Often times I think what I might need down the rode but I always end up with a more complex solution than when I just create something that I need. It is far easier to add more code than to remove code at a later date.
The EveningThere are always a few presentations that really get me thinking, but the best part of any conference is hanging out with people who share the same passions. In the evening, I went out to eat at Chili’s with Ryan Daigle, James Avery and Corey Haines. We had some rousing discussions about perfectionism, getting stuff out there, building apps, ideas, blogging and advertising.
ConclusionI have found it really interesting what a hot topic threading is this year. I have recently been reading up on Threads in ruby and how they work and I will post some stuff here at some point. It is kind of interesting to see how each conference kind of ends up with an overall theme, despite the lack of collaboration between presenters and no theme being stated by conference organizers.
Last year I blogged some suggestions for RubyConf. I have no idea if it helped but the name tag font size was markedly larger and it seems like things are starting a bit later. Not 10 but today’s talks started at 9:30 which is far easier to stumble stroll into. That is all for day one. Nunemaker out.
In which I discuss AstroTrain, a Merb/DataMapper, email web hook app and how I added a users controller with specs to it.
I think web hooks are sweet. The idea of making micro apps that take the pain out of typically painful things and allow for ridiculous re-use is really intriguing to me. In my receiving email research, I came across a few web hook apps that work with email (ie: MailHook). Who wants to keep messing with postfix for every app they want to receive email with? I don’t, that is for sure. That is why I got pretty stoked when I saw technoweenie start working on an email web hook app astutely named AstroTrain. I almost immediately forked it and started playing around.
Astrotrain is written with Merb and DataMapper. Merb has changed a lot since I last played with it so it took me a while to get my bearings. Now that I have, I’m feeling more comfortable, yet still occasionally frustrated. Because the API has changed so much, it’s kind of hard to find up to date examples of how to get things done in Merb. I’m not going to go in depth on why I did what I did, but I thought I would show the simple users controller I added to Astrotrain and the specs to make sure it is behaving. If there are any Merbists out there who have suggestions for making this more merb-ish, let me know in the comments and I’ll update accordingly.
app/controllers/users.rb class Users < Application before :ensure_authenticated before :ensure_admin def index @users = User.all render end def show(id) @user = User.get(id) raise NotFound unless @user @mappings = @user.mappings render end def new @user = User.new render end def create(user) @user = User.new(user) if @user.save redirect url(:users), :message => {:notice => "User was successfully created"} else render :new end end def edit(id) @user = User.get(id) raise NotFound unless @user render end def update(user) @user = User.get(params[:id]) raise NotFound unless @user if @user.update_attributes(user) redirect url(:users), :message => {:notice => "User was successfully updated"} else render :show end end def destroy(id) @user = User.get(id) raise NotFound unless @user if @user.destroy redirect url(:users) else raise InternalServerError end end end spec/controllers/users_spec.rb require File.join(File.dirname(__FILE__), '..', 'spec_helper.rb') describe "UserNotFound", :shared =&g