Posts filed under "Rails"

Using Helper Methods in Your Model? Yes.

At one point I found myself wanting to use Rails' auto_link helper in a to_html method on one of my models. If you need this functionality, here's how you would do it:

class Formatter

  include ActionView::Helpers::TagHelper
  include ActionView::Helpers::TextHelper

  def initialize(content)
    @content = content
  end

  def to_html
    auto_link(@content)
  end

end

I had to include TagHelper to satisfy dependencies for the h() and content_tag() methods. Though I ended up writing a custom formatter class instead in this case, this is still a useful approach.

Dead Simple Delegation in Rails

I can't believe I didn't see this when it came out. Instead of this:

class Child < ActiveRecord::Base
  belongs_to :parent

  def parent_name
    parent.name
  end
end

Or this:

require 'forwardable'
class Child < ActiveRecord::Base
  extend Forwardable

  belongs_to :parent
  def_delegator :parent, :name, :parent_name
end

You can now do this (as of Rails 2.2.2)

class Child < ActiveRecord::Base
  belongs_to :parent
  delegate :name, :to => :parent, :prefix => true
end

Check out some more detailed examples in the documentation

Fleakr In The Wild: Flittr

James just launched a Twitter / Flickr mashup that matches tweets with relevant photos from Flickr and he's using Fleakr to make it happen:

Flittr Announcement

Very cool. Check out the app and vote for your favorite combos:

Flittr

Using Fleakr to Log API Calls

I just added a new feature to the fleakr gem that gives you the ability to log all calls to the API. To get started just point it to a logger:

Fleakr.logger = Logger.new('/tmp/fleakr.log')

This is great when just using the gem, but it's more useful when you're using it as part of your Rails app:

# config/initializers/fleakr.rb
Fleakr.logger = RAILS_DEFAULT_LOGGER

By default, this logs all traffic (including file data if you're doing uploads), so you may want to turn down logging in development to see just the requests:

# config/environments/development.rb
config.log_level = :info

If you missed it, check out my recent post to get started using Fleakr in your Rails app.

Connect Your Rails App to Flickr With The Fleakr Gem

Fleakr started out as a simple way for me to download photos through the console (something it does quite well), but it is also really easy to use inside your Rails application.

Let's build a sample app that displays the latest photos for a specific Flickr user. First, install the gem and create your Rails app:

$ sudo gem install fleakr
$ rails fleakr-demo

Configure the gem inside your application:

# config/environment.rb
config.gem 'fleakr'

Since we're doing read-only calls, we only need an API key - let's set that in an initializer:

# config/initializers/fleakr.rb
Fleakr.api_key = 'your_api_key_here'

Now we'll create a simple action that will accept a Flickr user as a parameter and pull back the recent photos:

$ script/generate controller users show

Then, add a route (and remember to delete public/index.html):

# config/routes.rb
map.user ':username', :controller => 'users', :action => 'show'

Add a line to retrieve the specified user:

class UsersController < ApplicationController

  def show
    @user = Fleakr.user(params[:username])
  end

end

Finally, create some simple view code to pull back the latest photos (limited to 100) in groups of 10

<% # app/views/users/show.html.erb %>
<% @user.photos.each_slice(10) do |photos| %>
  <div>
  <% photos.each do |photo| %>
    <%= link_to image_tag(photo.square.url), 
          photo.url, 
          :width => photo.square.width, 
          :height => photo.square.height %>
  <% end %>
  </div>
<% end %>

You're all set - start up your server and point your browser to a URL containing a Flickr username (e.g. http://localhost:3000/teamviget).

Warning: This is extremely inefficent and is designed only to show you what's possible and shouldn't be used in a production application. The rendering of this view can take up to a minute because it has to do N + 1 API calls (where N is the number of recent photos, capped at 100).

Rails Rumble '08: Redux

It's been a few weeks since Rob, Nic, Doug, and I competed in this year's RailsRumble - after the dust settled from the 48-hour competition we had created an app (Qflip) that went on to take 2nd place. From what I can remember, it was both fun and stressful - check out the Flickr photos for proof.

Doug shared his take from the event on the Viget Inspire blog and described a technique that I think shows a lot of promise for design and development teams working together:

Do you know what all the pages do? How they're structured, and what they communicate? Great, now build them. Using just markup and some gray backgrounds, you can make a working version of your site in no time flat.

I documented my experience over at Extend and reinforced the importance of "shipping":

...Our codes were far from perfect, but we realized that the real value was in getting a product out there that could be used in the way it was intended by a real audience. As a result we now have real feedback and focused ideas on how to make the application even better.

Since the event, we've increasingly seen continued usage and coverage of the application:

QFlip - Get strangers to influence your Netflix queue. Sounds scary, but you might end up with some interesting picks! Developed by the wonderfully named "Scatapult" team.

Rails Inside

Qflip is an interesting service that uses Netflix’s open API to help subscribers make movie choices. What I like about this service:

  • It’s quick and easy
  • It provides value to my Netflix membership
  • It’s fun in that it has an element of surprise and randomness
  • It’s based on people, not algorithms

Tom Willerer

If you are a Netflix user with friends' of the same movie-renting persuasion, and you have an evil sense of humor, this is your app.

NetworkWorld

QFlip is a Netflix hack that enables other people to mess with your queue. I'm not brave enough to try it, but if you do let us know what you think in the comments.

Hacking Netflix.com

We plan to continue working on the app and reacting to feedback that we get from our users. As part of that work, we will be extracting the Netflix-specific functionality into a publicly-available Gem. Stay tuned.

Unit Testing Your ApplicationController

Do it!

class ApplicationControllerTest < ActiveSupport::TestCase
  context "An instance of ApplicationController" do

    setup { @controller = ApplicationController.new }

    should "return nil when there is no :user_id in session" do
      @controller.stubs(:session).returns({})
      assert_nil @controller.current_user
    end

    should "retrieve the current user when there is a :user_id in session" do
      user = Factory(:user)
      @controller.stubs(:session).returns({:user_id => user.id})

      assert_equal user, @controller.current_user
    end

    should "return nil when the :user_id in session can't be found in the database" do
      @controller.stubs(:session).returns(:user_id => 1)

      assert_nil @controller.current_user
    end

  end
end

Setting Session Data the Old-School Way

Rails provides an easy way to send session data in functional tests when accessing an action (the 3rd parameter is session data):

get :index, {}, {:user_id => 1}

As you add to your functional test suite, this becomes quite tedious and doesn't play well with tools like Shoulda. Here's where doing it the old-school way helps:

context "A GET to :index" do
  context "as a logged-in user" do
    setup do
      @request.session[:user_id] = Factory(:user).id
      get :index
    end

    should_assign_to :messages      
    should_render_template 'index'
  end
end

Thanks to Matt for giving me a hand with this today.

The Inevitable MySQL Gem Install

Got your new box all set up? Let's do some Rails:

$ rake db:create
!!! The bundled mysql.rb driver has been removed from Rails 2.2. Please 
install the mysql gem and try again: gem install mysql.

rake aborted!
no such file to load -- mysql

If you're on Ubuntu, do this:

$ sudo apt-get install libmysqlclient15-dev 
$ which mysql_config
/usr/bin/mysql_config

$ sudo gem install mysql -- --with-mysql-config=/usr/bin/mysql_config
Building native extensions.  This could take a while...
Successfully installed mysql-2.7
1 gem installed

If you're running on OSX and have installed mysql from MacPorts, mysql_config is already installed:

$ sudo gem install mysql -- --with-mysql-config=/opt/local/bin/mysql_config5

Done.

Fun With Association Proxies

Not only are tags great, they're a requirement of Web 2.0 (read the handbook). Here's a quick way to pull out those tags in a meaningful way:

class Post < ActiveRecord::Base
  has_many :taggings
  has_many :tags, :through => :taggings do
    def to_s
      self.map(&:name).join(', ')
    end
  end
end

Now, calling @post.tags.to_s will return the list of tag names separated by commas. The real magic is when you do this:

puts "#{@post.tags}"

Freezing Just a Single Gem

Sometimes you don't want them all frozen (maybe you want to build Hpricot on your target system instead):

$ rake gems:unpack GEM=coderay
(in /Users/preagan/Projects/sneaq)
Unpacked gem: '/Users/preagan/Projects/sneaq/vendor/gems/coderay-0.7.4.215'