posts by tag

rails (82)
Rails' StringInquirer

A recent commit to Rails. When the last method of a method chain ends with a question mark, the entire chain reads like a question.

$> Rails.env == 'production'
$> # => true

$> Rails.env.production?
$> # => true

The latter is much better. I love these smart little additions. Any string wrapped up in a StringInquirer has this functionality.

Rails plugin: has_params

This is yet another edition of pointless programming. Ready. Set. Go!

To me, checking if parameters exist via the params hash is ugly. My fingers start to quiver when I type params[:whatever] more than once on the same line. Sometimes I’ll add a private method to simply check if parameters exist. It just reads better, IMHO.

if using_open_id?
  # process OpenID authentication
end

private
  def using_open_id?
    !params[:openid_url].blank?
  end

Maybe you’ve done something similar, maybe you haven’t. Being the pointless programmer that I am, I wrote a plugin to take care of this for any and all parameters. I called it, has_params. You can find it on GitHub.

Example(s)

I suppose there’s no harm in duplicating the README, huh? Anyway, here’s how it works:

# the "old" way
Project.new(params[:project]) unless params[:project].blank?
Project.new(params[:project]) if params[:project]

# the "has_params" way
Project.new(params[:project]) unless blank_project_params?
Project.new(params[:project]) if has_project_params?
Project.new(params[:project]) if project_params?

You basically just plug the key that you’d otherwise use for params into the standard “has_params” format. So, for params[xxx] you’d have one of the following to choose from:

  • blank_xxx_params?
  • has_xxx_params?
  • xxx_params?

Personally, I think it cleans up controller code a little. Brick-by-brick my friends, brick-by-brick.

Gotcha!

If you’re using method_missing in your controller(s), make sure you call super at some point. This plugin also uses method_missing and at a higher point in the inheritance chain (unless you’re also mixing into ActionController::Base), so if super isn’t called, Rails will be perfectly satisfied with your version of method_missing, ignoring the has_params’ version. At least, I’m pretty sure that’s what would happen. Consider yourself warned.

Installation

I can only imagine how excited you are to install this sucker. Here’s how:

>> cd project_root/vendor/plugins
>> git clone git://github.com/rpheath/has_params.git 

And that concludes this edition of pointless programming. I hope you’ve enjoyed it :-)

Rails plugin: EasySearch

Have you ever written a plugin or a piece of code that was more fun to write than it was actually worth? I seem to do that a lot—I enjoy experimenting with Ruby. Recently, I needed to search ActiveRecord models individually, and was in the mood to write a simple DSL. It’s now in plugin form, called EasySearch, and can be found on GitHub.

It doesn’t support joins or shared indexes or anything else you might come to expect from a search plugin. I’m posting about it not because I think you should use it, but because I think it’s a pretty cool API for searching.

So, install the plugin and do something like this:

class Search
  include RPH::EasySearch
end

(I originally had a nice acts_as_easy_search class method that hooked up the behavior, but I didn’t feel right about mixing that into Object. I wanted this plugin to work without the need of an ActiveRecord superclass. Plus, AR would then be expecting a corresponding table in the database, which is another unnecessary need. So, manual inclusion is the answer until I come to terms with a better alternative. Continuing…)

The Search class now has the means to easily search any ActiveRecord model within an application. Let’s say I want to find all of the users who mention ‘ruby’. Let’s reword that: search users with the term ‘ruby’.

$> Search.users.with('ruby')
$> # => [<#User ...>, <#User ...>, ...]

Makes sense, huh?

I have a confession to make: I lied about only having to include the module. Before anything will actually work, I’ll need to tell EasySearch about the tables I want to easily search.

EasySearch Configuration

For any generic search plugin to work, there needs to be a way to specify which database columns the search terms should be matched against. Here’s an example of how it works:

# in Rails 2.0+ you could put this in 
# config/initializers/easy_search_setup.rb
# (otherwise just use config/environment.rb)

RPH::EasySearch::Setup.config do
  setup_tables do
    users    :first_name, :last_name, :email, :bio
    projects :title, :description
    groups   :name
  end
end

There, that’s it (for real this time).

If you notice, it looks like there are “users”, “projects”, and “groups” methods that are called from within the block. And actually, that’s correct. The only difference is those methods don’t exist until they’re called, and even then they don’t “exist” (which is kind of weird, I know, but incredibly awesome nonetheless). Don’t worry about how it works (read through the code if you’re interested), just follow the pattern (use the table names instead of the model names).

After this one-time configuration is done, I can do things like:

$> Search.users.with('ryan')
$> # => [<#User ...>]
$> Search.projects.with('design')
$> # => [<#Project ...>]
$> Search.groups.with('friends')
$> # => [<#Group ...>]

If you try to search a model that hasn’t been configured, EasySearch will let you know. After all, how else would it know which columns to look in? It’s not that magical.

And getting a hold of the current table configuration is easy:

$> RPH::EasySearch::Setup.table_settings
$> # => {"users" => [:first_name, :last_name, :email, :bio], "projects" => ...}

How it Works

Really, all EasySearch is doing is building a WHERE clause and using conventions to pass that on to the appropriate finder. So Search.users is really doing User.find with a custom conditions clause.

Let’s say I want to search my User model for “ryan heath ruby”.

Search.users.with('ryan heath ruby')

This would not only compare “ryan heath ruby” with each of the specified columns (you know, from the configuration), but it’d compare “ryan”, “heath”, and “ruby” individually against each of the specified columns, providing more accurate results.

This, however, is an incredible performance limitation and is why this plugin is not meant for those gigantic applications with tons and tons of database records. It builds a potentially large WHERE clause using LIKE, which is quite slow in the computer world. For those large applications, it’s far better to use a full text solution. But again, this is all (more-or-less) for fun with little profit. I had a need to search individual models separately in a small application, so there you go. I can always go back and rework the back-end to operate differently/more efficient.

Oh, and since a rather large WHERE clause is being constructed, checking each term individually, I want to ignore meaningless words to avoid the extra overhead. For example, let’s say I tweak my search to be:

Search.users.with('ryan heath is a ruby')

EasySearch would still only search “ryan”, “heath”, and “ruby”, ignoring the “is” and “a” (because they’re dull). You can easily see what keywords are considered “dull” by doing:

$> RPH::EasySearch::Setup.dull_keywords
$> # => ['the', 'a', ...]

Now I know what you’re thinking, “Who gets to decide what keywords are dull keywords?” The programmer, of course! By default, EasySearch has a predefined list of keywords that it thinks are meaningless. But you can add to that list quite easily. Using the same Setup.config block:

RPH::EasySearch::Setup.config do
  setup_tables do
    # ...
  end

  strip_keywords do
    ['other', 'words', 'you', 'do', 'not', 'want', 'to', 'search']
  end
end

That will append those keywords to the default list (and will only count a dull keyword once, so don’t worry about duplication). If I wanted to ignore the default list completely (instead of appending to it), I’d just have to pass true to the strip_keywords method, like so:

strip_keywords(true) do
  ['other', 'words', 'you', 'do', 'not', 'want', 'to', 'search']
end

So that’s about it. It’s a fun plugin to play with, and like I said, it was more fun to write than it’s probably worth. But honestly, I think this sort of experimentation is nothing but good for programmer experience. And besides, every now and then, an “experiment” turns into something awesome (see Ambition for a prime example).

Railscasts Contest: 5 Rails Tips

There’s a contest on Railscasts that has me feeling compelled to participate. So I am. To enter, the contest requires 5 tips concerning Rails, all in one post. So, this post will more than likely be one of the longest I’ve written in a while, but hopefully it will serve as a good resource/reference for other Rails developers. Without further ado, here are my five tips:

Note: I haven’t wrapped my View code examples in the ERB <%= -%> tags, as it currently makes the syntax highlighting terribly hard to read. I just wanted to make new comers aware until I can get this issue fixed.

Tip 1: Navigation Helper Plugin

Nearly every web application has some sort of navigation. Albeit tabs, menus, plain links, whatever, there needs to be a way to click through the application. And more often than not, keeping track of the current section/tab is a desired feature. Well, I wrote a Rails plugin called navigation_helper to assist with these needs.

Basic Usage

Once installed, here’s how the plugin works:

# somewhere in your view (typically your layout)
navigation [:home, :about, :contact]

# HTML output:
#   <ul class="nav_bar">
#     <li class="current"><a href="/home">Home</a></li>
#     <li><a href="/about">About</a></li>
#     <li><a href="/contact">Contact</a></li>
#   </ul>

You pass an array of symbols representing the sections that the links will navigate to. The link text will be a capitalized version of the symbol passed in. So :home becomes ‘Home’; :contact_me becomes ‘Contact Me’; and so on.

An important thing to be aware of: the helper will be expecting a named route mapped to the section passed in the array. For instance, for the :home section, the navigation helper will use home_path to build the link. And for :about, it will look for about_path. And so on. You need to make sure those routes are defined in your routes.rb file (it’s good practice to use named routes, this plugin just enforces that practice).

And as you can see, the markup is very extensible (in terms of CSS) with the use of an unordered list. The list item that holds the current section will get a CSS class of “current”. And the unordered list itself gets a CSS class rather than an ID, so that it can be used multiple times on the same page and not break your strict XHTML markup :-)

Adding Subtitles

Sometimes it’s a nice touch to add subtitles to your navigation (see my portfolio for example). This plugin has support for that. All you have to do is pass a string of the subtitle right after the section that the subtitle should be associated with. For example:

navigation [:home, 'Start Here', :about, 'Learn More', :contact, 'Get In Touch']

# HTML output:
#  <ul class="nav_bar">
#    <li class="current">
#      <a href="/home">Home</a>
#      <span>Start Here</span>
#    </li>
#    <li>
#      <a href="/about">About</a>
#      <span>Learn More</span>
#    </li>
#    <li>
#      <a href="/contact">Contact</a>
#      <span>Get In Touch</span>
#    </li>
#  </ul>

As you can see, the markup generated is clean and is ready for some CSS love. Now, what if you would rather those subtitles just be hover text on the link instead of full-blown span elements? No problem, just let the navigation helper know with the :hover_text => true option:

navigation [:home, 'Start Here', :about, 'Learn More', :contact, 'Get In Touch'], :hover_text => true

# HTML output:
#  <ul class="nav_bar">
#    <li class="current"><a href="/home" title="Start Here">Home</a></li>
#    <li><a href="/about" title="Learn More">About</a></li>
#    <li><a href="/contact" title="Get In Touch">Contact</a></li>
#  </ul>

The span elements will transform into title attributes on the links, so the text will only show up on hover.

Authorized Sections

Now, a definite need (for me at least) is to have certain tabs show up depending on some condition, such as a user being logged in. For instance, on this very site, the public sees ‘Portfolio’, ‘Words’, ‘Archives’, and ‘About’ tabs. But if I’m logged in, there’s also an ‘Admin’ tab, which allows me to access the area to post new entries, add categories, edit/delete comments, etc. But I only want that tab visible based on me being logged in. Well, I’ve added support for that, too. Just specify which sections should be “authorized” sections, like so:

navigation [:home, :about, :admin, :reports], :authorize => [:admin, :reports]

# HTML output:
#   <ul class="nav_bar">
#     <li class="current"><a href="/home">Home</a></li>
#     <li><a href="/about">About</a></li>
#     <li class="authorized_nav_link"><a href="/admin">Admin</a></li>
#     <li class="authorized_nav_link"><a href="/reports">Reports</a></li>
#   </ul>

By default, the link will be “authorized” by checking a logged_in? method. If you don’t have a logged_in? method, or need some other means of authorization (such as checking if the current_user has the admin role), then you can specify which method you’d like the navigation helper to check against by using the :with option:

navigation [:home, :about, :admin, :reports], :authorize => [:admin, :reports], :with => :administrator?

Now the plugin will only show the ‘Admin’ and ‘Reports’ tabs if the administrator? method exists and returns true. (Note: if the authorization method doesn’t exist, the helper won’t crash, it will simply not show the authorized tabs)

Also notice how the admin links get a special “authorized_nav_link” CSS class. That’s because sometimes you want your “admin” tabs to appear differently, and this gives you the power to do so. For instance, you may have your common tabs to the left, but your admin tabs floating to the right. And just to be clear, if an authorized link happens to be the current section, it will simply append the CSS classes (i.e. class=”authorized_nav_link current”).

I’ll admit, the “authorized_nav_link” isn’t the best CSS class name, but it’s best to keep defaults such as that awkward so they don’t interfere with your current CSS classes. However, you can pass another option to override that class, like so:

navigation [:home, :about, :contact, :admin], :authorize => [:admin], :authorize_css => 'custom_css'

There’s one more thing to mention about authorized links. Let’s say you’re using this for an admin menu, where all of the links are to be “authorized”. Rather than list out all of the authorized links again, you can pass an :all to the :authorize option, like so:

navigation [:users, :reports, :logs], :authorize => [:all]

Now all tabs will be authorized. Pretty simple, huh?

Setting Current Tab

Up to this point, you may be wondering how the helper knows which tab/section is the “current” tab/section. Well, it’s simple. By default the plugin uses the controller’s name to determine the current tab (or link or section) you’re on. But as we all know, that’s not always feasible. Just because you have a PublicController doesn’t mean you want your link to be “Public” in the navigation menu. To fix that issue, you can specify the current tab for any controller by doing:

class PublicController < ApplicationController
  current_tab :home
end

Now something like this will work as intended:

navigation [:home, :about, :contact]

The PublicController will be seen as :home to the navigation helper, and will choose the current tab accordingly. This is also very handy for namespaced controllers.

Install via Git

You can find this plugin on GitHub (and see the README for more/better examples), and can be installed by doing:

$> cd path/to/your/rails/project/vendor/plugins
$> git clone git://github.com/rpheath/navigation_helper.git

You can download a tarball if you don’t have Git installed. And for completeness, here’s the original announcement of the navigation_helper plugin.

Tip 2: Input CSS Plugin

This next tip is more for designers who work with Rails applications. As any designer would know, designing Forms can be somewhat of a pain, as there are many different types of INPUT tags (text boxes, password fields, submit buttons, file fields, etc). Obviously, you would not want to apply the same text box styling to a submit button, which means it requires extra work on every form to make sure you’re styling the correct INPUT tag.

Since I personally design and develop Rails applications, I’ve decided that it was time to attack this problem at its core. I wrote a plugin that will automatically add a CSS class based on the “type” attribute of any INPUT tag. And I’ve called it, input_css.

How it Works

Just install it. Then your standard form helpers will automatically have a class assigned to them. For example:

f.text_field :name
# => <input type="text" class="text" name="user[name]" value="" />

submit_tag 'Create', :class => 'button'
# => <input name="commit" type="submit" class="button submit" value="Create" />

f.check_box :is_preview
# => <input type="checkbox" class="checkbox" name="article[is_preview]" value="" />

So once the plugin is installed, the CSS to style your INPUT tags is simple:

input.text     { ... }
input.submit   { ... }
input.file     { ... }
input.checkbox { ... }
input.radio    { ... }
...

Install via Git

This plugin can be found on GitHub, and you can install it by doing:

$> cd path/to/your/rails/project/vendor/plugins
$> git clone git://github.com/rpheath/input_css.git

Once installed, you’re good to go. There’s no setup, customization, etc. It taps directly into the existing Rails tag helper, so all of your existing form elements will be updated! Now you have an easy and consistent way to style your forms.

Remember, if you don’t have Git installed, you can download a tarball. Just put the source in your vendor/plugins directory.

Tip 3: Acts As Lookup Plugin

Maybe I’m alone on this one, but do you find it a pain to deal with select (i.e. drop down) lists? If you’re like me, I don’t always remember the proper Rails syntax, or I want to add a default nil option to the list, etc. They always just feel awkward to me. Here’s a typical select field you might find in one of my forms. It’s simply a lookup to choose a category:

f.select :category_id, [['--', nil]] + Category.find(:all).collect { |m| [m.name, m.id] }

Yikes! That’s sort of nasty to have that right in your views. At least, to me it is. So I wrote a plugin that assists with this “lookup table” issue. I’ve so cleverly called it, acts_as_lookup.

How it Works

Once installed, you need to tell your model(s) that they should be acting as a lookup table. This is pretty straightforward, though:

class Category < ActiveRecord::Base
  acts_as_lookup :name
end

You have to pass it the field/column name you want to show up in your drop down list. So in the example above, I want to be able to choose from a list of category names, hence the :name parameter.

From there, you get two things: 1) a lookup_for helper (used in your views) and 2) an options_for_select class method for any model that is “acting as a lookup table”. Here’s how you use both:

Using options_for_select

This is a clean way to get rid of that collect nonsense I showed previously. So, redoing my above example using this plugin (and using options_for_select), we have:

f.select :category_id, Category.options_for_select

That’s much cleaner. And it automatically adds the nil ”- -” option as the default in your list. Arguably, though, there’s even a better way: the lookup_for helper.

Using lookup_for

The lookup_for helper automatically generates the above, but it’s a little cleaner:

lookup_for :product, :category_id

And if you’re using a FormBuilder (read: “f.” in front of your form helpers), it’s even better. You only have to give it the foreign key to the lookup:

f.lookup_for :category_id

Viola! The above example(s) will automagically generate something similar to (of course depending on the real data):

<select>
  <option value="" selected="selected">--</option>
  <option value="1">Appliances</option>
  <option value="2">Furniture</option>
</select>

One thing to note, though: the foreign key must follow the traditional Rails convention for foreign keys. Meaning, for a Category, you’d have category_id foreign key reference; for a Task, you’d have task_id foreign key reference; and so on. The reason is because the plugin uses that foreign key to get at the Model in which it represents. But since that’s pretty standard to most Rails developers, I don’t think it bears too much constraint :-)

Customization

Now, you may be asking “what if I don’t want ’- -’ as my default option?” or “what if I don’t want every category to show up?” or “what if I have a category order, other than alphabetical?”. Not a problem. This plugin supports that sort of customization.

Changing the Default Text

class Category < ActiveRecord::Base
  acts_as_lookup :name, :default_text => "- Choose Category -" 
end

And if you don’t want a default nil option at all, just set the :default_text option to :first (meaning, the first option of your data returned):

class Category < ActiveRecord::Base
  acts_as_lookup :name, :default_text => :first
end

Now there will be no default option in your drop down (in this example, it would be set to the first category of the collection instead).

Limiting the Options

# only show categories from within the last 4 months
class Category < ActiveRecord::Base
  acts_as_lookup :name, :conditions => ["created_at > ?", 4.months.ago]
end

Displaying in a Different Order

By default, the plugin will sort your options alphabetically, but you can change that, too:

class Category < ActiveRecord::Base
  acts_as_lookup :name, :order => 'category_order ASC'
end

And of course, you can combine the options and pass all three at once, I’ve just shown them separately to emphasize each point.

Install via Git

You can find this plugin on GitHub, and it can be installed by doing:

$> cd path/to/your/rails/project/vendor/plugins
$> git clone git://github.com/rpheath/acts_as_lookup.git

Remember, if you don’t have Git installed, you can download a tarball. Just put the source in your vendor/plugins directory.

Tip 4: Automatic Fading Flash Messages

This next tip is rather minor, but I think it adds a nice touch, and I seem to use it in all of my Rails applications. Basically, the idea is to show a flash message for a predetermined amount of time, then slowly fade the message out. (I personally think it’s tacky to leave it there, waiting on the user to navigate away from that area)

So, using a tip from a prior Railscast, we put this somewhere in our layout:

<% flash.each do |key, msg| -%>
  <%= content_tag :p, msg, :id => key -%>
<% end -%>

This will create a <p> tag with an id of the flash type. Meaning, flash[:notice] = '...' will give <p id="notice">...</p> and flash[:error] = '...' will give <p id="error">...</p> and so on. Now, what we want to do is fade this <p> element out. We’ll use JavaScript to do this, and we’ll want to put that JavaScript in public/javascripts/application.js of our main Rails project root.

Fading Messages using jQuery

$(document).ready(function() {
  setTimeout(hideFlashMessages, 10000);
});

function hideFlashMessages() {
  $('p#notice, p#warning, p#error').fadeOut(5000)
}

Fading Messages using Prototype/Scriptaculous

document.observe("dom:loaded", function() {
  setTimeout(hideFlashMessages, 10000);
});

function hideFlashMessages() {
  $$('p#notice, p#warning, p#error').each(function(e) { 
    if (e) Effect.Fade(e, { duration: 5.0 });
  });
}

(Note: the above examples were based on jQuery 1.2.3 and Prototype 1.6)

The above functions will allow the message to be shown for 10 seconds (10000 milliseconds) in full, then begin to fade the message out over a 5 second duration. Of course, just change the values to fit your needs/desires.

Tip 5: Interfacing with SOAP Web Services

This tip might actually target a small niche of Rails developers, but it’s something that I couldn’t find too much about when “Googling” for some help. So I eventually just came up with my own solution. It deals with creating an interface for legacy .NET SOAP web services. Rather than go into the explanation, I’m going to provide an example skeleton class that you can tailor to your needs:

require 'digest/sha1'
require 'soap/wsdlDriver'

module WebServices
  class SOAPInterface
    attr_accessor :endpoint, :service

    def initialize(endpoint='www.yoursite.com', service='YourWebServices', options={})
      @endpoint = endpoint
      @service  = service
    end

    # --
    # your methods go here
    # -- 

    private
      def wsdl
        SOAP::WSDLDriverFactory.new("http://#{@endpoint}/services/#{@service}.asmx?WSDL")    
      end    
  end

  # pulls out the diffgram of SOAP::Mapping::Object's into an array
  class DataSetParser
    def initialize(soap_response, data_set)
      @response = soap_response
      @data_set = data_set
    end

    # allows for @obj['CourseListing'] to be @obj.course_listing
    def method_missing(name, *args)
      @response.send(:diffgram).send(@data_set.to_sym).send(:[], name.to_s.camelize)
    end
  end
end

We’ll talk about about what goes in “your methods go here” in just a second. I wanted to mention what the DataSetParser is all about. Firstly, it’s specific to the .NET framework, so if you’re wanting to use this for SOAP services coming from something other than .NET, you can wipe out the DataSetParser class entirely. Now, onto what it does.

.NET returns it’s data collections as a DataSet, which then gets wrapped in a DiffGram. I know, goofy. From the Microsoft site:

A DiffGram is an XML format that is used to identify current and original versions of data elements. The DataSet uses the DiffGram format to load and persist its contents, and to serialize its contents for transport across a network connection.

What does that mean to us? It means that it’s another level of tedious parsing that we need to deal with when getting a SOAP response. If your API is returning a DataSet, then you can pass the result to the DataSetParser class, and it will return the collection as an array of SOAP::Mapping::Object. It also will allow you to access the data via an underscored method based on the camelized name of the DataSet returned. If that’s confusing, see the comment above the method_missing definition in the DataSetParser class.

Now, here’s an example of how you might use this skeleton module. Here, we’ll be replacing the “your methods go here” comment.

# returns a user in the form of a SOAP object
def authenticate(username, password)
  soap = wsdl.create_rpc_driver
  response = soap.Authenticate(:username => username, :password => password)
  result = response.authenticateResult
  soap.reset_stream
  DataSetParser.new(result, 'user').user
rescue
  # do your graceful error catching/logging stuff
end

This would allow you to do something like:

$> api = WebServices::SOAPInterface.new('www.mysite.com', 'MyWebServices')
$> api.authenticate('login', 'password')
$> # => <#SOAP::Mapping::Object ... >

The Authenticate and authenticateResult is dependent on the WSDL of the SOAP service, but the rest is pretty close to what each of your methods might look like. For more info, you can visit an earlier post of mine which discusses the same issues, and provides a more Rails-esque example.

Again, I realize that this is for a rather niche group of Rails developers, but like I said, I had a hard time finding any information on this, so maybe someone else will find my solution to this problem useful.

Conclusion

That concludes my 5 tips related to Rails. Hopefully they’ve proven to be worthwhile. Let me know if you have any trouble implementing any of these tips, as I’d be glad to help you make use of them. Thanks for reading my first novel :-)

Hulu: Online Movies and TV Shows

I just came across an awesome site for streaming TV shows and movies. It’s called Hulu. Apparently it’s a site supported (or built?) by NBC/Fox, so the videos are all of incredible quality. I came across it while looking at a list of high-traffic Rails applications (and it’s one of them).

So if you’re looking for another way to be distracted, check out Hulu. Here’s one to get you started: 2008 Tostitos Fiesta Bowl.

Testing block helpers with Rspec

One of the many great things about Rspec is that it allows you to test helper methods. Helpers can be complex at times. And when it matters, they definitely need some testing love.

An example of a typical helper may be something like:

def h1(text)
  "<h1 class='heading'>#{text}</h1>"
end

Then you can do <%=h1 'Text Here' -%> in your views. That’s trivial to test, so I won’t go into that. The tricky tests (I think) deal with block helpers. Block helpers are extremely useful and can improve the readability of what’s going on in your view(s). Probably the most useful case is when you have <% if current_user.admin? %> scattered all over the place. Wouldn’t it be better (and DRYer) to wrap that “admin condition” up in one place?

def content_for_admin(&block)
  yield if current_user.admin?
end

Pretty simple. But, how would you test that? Initially, I had somewhat of a hard time writing tests to see if the block was actually yielded or not. Here’s what I do now, but I’m open to (and seeking more) alternatives. Using the content_for_admin helper as the guinea pig:

describe ApplicationHelper do
  attr_accessor :_erbout
  fixtures :users

  before(:each) do
    self._erbout = ''
    @block = "This is the block content"
    @current_user = users(:admin)
  end

  # current_user.admin? # => true
  it "should yield block for an admin" do
    should_receive(:current_user).and_return(@current_user)
    @current_user.should_receive(:admin?).and_return(true)

    html = content_for_admin do
      self._erbout << "<div>#{@block}</div>"
    end
    html.should have_tag('div', @block)
  end

  # current_user.admin? # => false
  it "should not yield block for a non-admin" do
    should_receive(:current_user).and_return(@current_user)
    @current_user.should_receive(:admin?).and_return(false)

    html = content_for_admin do
      self._erbout << "<div>#{@block}</div>"
    end
    html.should_not have_tag('div', @block)
  end
end

Another, similar, approach is to use eval_erb, which let’s you actually write out the ERB as a string (or heredoc) and evaluate the output. I think that’s a little messy, but then again, I’ve never actually tried it.

But other than that, this is the only way I know to test the yielded output of a block helper with Rspec. Do you know of a better way? Or at least, a different way?

Navigation Helper on GitHub

For those who are interested, I’ve moved my navigation helper Rails plugin over to GitHub.

http://github.com/rpheath/navigation_helper/tree/master

You can follow the changes there if you’d like. To install (from your project root):

git clone git://github.com/rpheath/navigation_helper.git vendor/plugins/navigation_helper

I doubt I’ll be pushing changes to the subversion repo anymore, so use the above method if you want the latest and greatest.

Rails plugin: navigation helper

This plugin is now available at GitHub. Follow all plugin modifications there (the SVN repo will soon be obsolete).

It seems like I’ve been going on and on about navigation in Rails lately. That’s probably because I have been. But it’s one of those things that presents itself in every app I work on. And since I usually go about it close to the same way, it makes a good case for a plugin, don’t you think? I shall call it, navigation helper. Clever, I know.

It’s pretty basic, but I’ll go through a few examples, anyway. Before I continue, two notes about these examples:

  1. whenever you see navigation(...), think of <%= navigation(...) -%> as that method is a helper used in a view
  2. assume the current page will always be ‘Home’

Now that we have that settled, let’s see a few examples.

Basic Usage

This is how most people would probably use this plugin:

navigation [:home, :about, :contact_me]

# HTML output:
# <ul class="nav_bar">
#   <li class="current"><a href="/home">Home</a></li>
#   <li><a href="/about">About</a></li>
#   <li><a href="/contact_me">Contact Me</a></li>
# </ul>

You must use symbols as the links/sections, and we’ll see why in just a bit. Also, notice how :contact_me turns into ‘Contact Me’ as link text. You can use CSS to transform it to all lowercase or all uppercase, but the default is to capitalize each word (which you can’t do with CSS).

Oh, and the above example would be looking for the following named routes: home_path, about_path, and contact_me_path. So make sure you have a named route for each section you pass to the helper.

Authorized Sections

I don’t know about you, but a lot of the time I have one or two tabs that only appear based on some sort of authorization. For example, this very site has ‘Portfolio’, ‘Words’, ‘Archives’, and ‘About’ at the top. But if I’m logged in it also has ‘Admin’. Again, that’s a common need for me, so I added in support for that. Use it like so:

# Example 1: single section
navigation [:home, :about, :admin], :authorize => [:admin]

# Example 2: multiple sections
navigation [:home, :about, :users, :reports], :authorize => [:users, :reports]

The plugin will only add those sections to the list if they are authorized. And how does it “authorize”? Well, by default the plugin will check against a logged_in? method. If that method either doesn’t exist or fails (returns false), those tabs will not be added. “But Ryan, don’t you think it’s kind of wrong of you to assume that we’re using a logged_in? method?” Well, maybe, maybe not. Either way, you can override that by telling the helper which method to use, like so:

navigation [:home, :about, :admin], :authorize => [:admin], :with => :auth_method

Now auth_method will be checked instead of logged_in?.

One more thing. In the case that the entire navigation is to be authorized, there is a way to avoid re-typing all of those sections in :authorize option.

navigation [:home, :about, :admin], :authorize => [:all]

Adding Subtitles

This was a recent need of mine (in the Portfolio). What I mean by subtitles is text that supports each link, but is not part of the link itself. That may have not helped you at all. Maybe this example will:

navigation [:home, 'Start Here', :about, 'Learn More']

# HTML output:
# <ul class="nav_bar">
#   <li class="current">
#     <a href="/home">Home</a>
#     <span>Start Here</span>
#   </li>
#   <li>
#     <a href="/about">About</a>
#     <span>Learn More</span>
#   </li>
# </ul>

Then you can do some fancy CSS :hover styling or whatever. Sometimes that adds just enough spice to a boring navigation bar.

But wait, there’s a second option. If you want the subtitles to appear as hover text instead, just let the helper know:

navigation [:home, 'Start Here', :about, 'Learn More'], :hover_text => true

# HTML output:
# <ul class="nav_bar">
#   <li class="current"><a href="/home" title="Start Here">Home</a></li>
#   <li><a href="/about" title="Learn More">About</a></li>
# </ul>

And as I briefly mentioned above, that is why you have to pass symbols as the link/section and strings as the subtitles. The plugin understands symbols and strings differently (the positions matter, too: even for sections, odd for subtitles).

Setting Current Tab

OK, the last thing. By default the plugin uses the controller’s name to determine the “current” tab (or link or section) you’re on. But since that’s not always feasible, you can specify the current tab for any controller by doing:

class PublicController < ApplicationController
  current_tab :home
end

Now something like this will work as intended:

navigation [:home, :about, :contact_me]

The PublicController will be seen as :home to the navigation helper, and will choose the current tab accordingly.

Documentation

All (or most) of the above is in the README. It’s on the agile web development site, too (although it doesn’t provide much info).

Installation

If you think this plugin could help you out, by all means install it. Here’s how:

ruby script/plugin install http://svn.rpheath.com/code/plugins/navigation_helper

...or…

piston import http://svn.rpheath.com/code/plugins/navigation_helper vendor/plugins/navigation_helper 

Conclusion

I have a few more things I want to do with this plugin (such as sub-navigation), but I didn’t want to get unnecessarily complex just yet. Feel free to modify the code to your needs, and let me know if there’s something you absolutely think should be added/changed/fixed. Who knows, I just might do it! Enjoy.

Apache, attachment_fu, and production

We got a new production server for Rails apps at work. In its early life, it’s running Ubuntu and Apache (no mongrels yet, but fcgi instead). But the issue, here, is with Apache. Sort of.

In a recent deployment, I noticed that the image uploads quit working. So I glanced through the logs, and noticed that it was going from new straight to index, essentially neglecting create. Rather than POSTing to /files, it was GETting /files. I wasn’t sure what was going on. After all, it worked fine in development. (can’t keep track of how many times I’ve said that)

Then I remembered something: the action in the form (/files) matches the database table name, which attachment_fu then uses as the public directory to store the files in. So Apache was seeing /files and was trying to show that directory, in which Rails was then catching and routing to the index action. So, what now?

Well, it turns out that /files/ works just fine, whereas /files does not (notice the trailing slash). Some people say this is the fix:

# application.rb
def default_url_options(options)
  { :trailing_slash => true }
end

But that didn’t work for me. Maybe default_url_options only gets called on url_for, and not named routes? Or maybe it’s because I use files_path instead of files_url? Whatever the reason, setting the :trailing_slash option didn’t work for me. I could only get this to work in production by ignoring the named route (ugh) and using :url => '/files/' instead.

Anyway, you’ve been warned.

Tabbed navigation in Rails (refactored)

This is in relation to an older post about tabbed navigation. No matter the implementation, I always seem to match controller names with tab/link/section names. But I’m realizing that’s simply too coupled.

These days, I name my controllers in the context of a resource. And now that I’m adopting namespaces for privileged access, it’s likely that I’ll have controllers having the same controller_name but different intentions, and I wouldn’t necessarily want a section highlighted in both cases. Besides, adding a controller should not force me to consider a tab, or navigation at all for that matter. It’s more important that it makes sense within the code base.

So I’ve updated my implementation.

# views/layouts/application.html.erb
navigation :home, :projects, :about, :contact, :admin

# helpers/application_helper.rb
def navigation(*links)
  items = ''
  links.each do |link| 
    css = (link == @current_tab ? 'current' : '')
    link != :admin ? items << tab(link, css) : (items << tab(link, css) if logged_in?)
  end
  content_tag :ul, items
end

The tab(link, css) helper just constructs the link. And to set the current tab:

# controllers/application.rb
class ApplicationController < ActionController::Base
  before_filter :set_current_tab
  protected
    def set_current_tab
      # will default to controller_name if @current_tab
      # has not been set by another controller
      @current_tab ||= controller.controller_name.to_sym
    end
end

# override the 'set_current_tab' method in any controller
# if a name other than the controller_name is desired
#
# For example:
# controllers/admin/authorized_controller.rb
class Admin::AuthorizedController < ApplicationController
  before_filter :authenticate
  protected
    def set_current_tab
      @current_tab = :admin
    end
end

By implementing the tabs this way I’ve banned the directory authentication and reverted back to an AuthorizedController, as that allows me to easily authenticate and set the admin tab for all administrative controllers.

Another solution would be to leave it as it were and override controller_name, but that didn’t feel right since it would’ve completely distorted the point of the controller_name in the first place. And so I didn’t do it.

It’s not like this is rocket science, I just thought I’d give an update.

Directory-based authentication in Rails

I think it’s safe to assume any Rails developer is familiar with something like before_filter :login_required at the top of any controller that, well, requires a login. One can’t complain about how tremendously easy that is. But I recently did something terribly stupid that has provoked me to take it a step further.

Don’t be Stupid

As you may know, I cleaned up my site for 2008. Well, in doing so I stripped out the inline admin interface in favor of a more organized (and RESTful) approach by adding an admin namespace. I love namespaces. But anyway, with the addition of these new namespace’d controllers, I forgot to add the one-liner: before_filter :login_required. And to top it off, I just realized this 2 nights ago. So all of my admin functionality was open to the public since December 31. Way. To. Go.

Putting a Directory on Lock-down

Granted that was completely my fault, I wanted to remove that worry, as well as the need for the login_required method to be called per controller. With namespaces, you get a nested directory within your controllers directory. In my case, I have: app/controllers/admin. That’s where all of my (you guessed it) admin functionality goes. It’d be much easier for me to just restrict access to that directory, so that any controller that finds its way in there automatically requires a login. Apparently, I just can’t trust myself anymore.

Now, this is the first run-through and I haven’t had the “go back the next day and clean it up” moment yet, but here’s essentially what I’m doing…

# controllers/application.rb
class ApplicationController < ActionController::Base    
  include Authentication
  before_filter :should_authenticate?
  # ...
end

# lib/authentication.rb
module Authentication
  RESTRICTED_NAMESPACES = %w(admin)

  protected

  def authenticate
    # choose your flavor...
    # (I'm using HTTP basic authentication)
  end

  def should_authenticate?
    RESTRICTED_NAMESPACES.each do |directory|
      if controller_path.match(/(^.+)\//)
        authenticate if directory.downcase == $1.downcase #&&controller_exists?($1)
      end
    end
  end

  #def controller_exists?(dir)
  #  controllers = []
  #  Dir.glob("#{RAILS_ROOT}/app/controllers/#{dir}/*_controller.rb").each do |f|
  #    controllers << $1.downcase if f.match(/^.+\/(.+)_controller.rb$/) 
  #  end
  #  controllers.include?(controller_name.downcase)
  #end
end

Note: I’m not sure if adding a :path_prefix in the route declarations will screw with the controller_path (I’m pretty sure it doesn’t), but that may be something to keep in mind.

Conclusion

I’m currently using this on my new portfolio, and so far it seems to work very well. It’s nice to just generate an admin::whatever controller and know that it’s automatically protected. I’ll probably modify this a bit for a plugin and start using it in other applications, so feel free to chime in if you see any obvious flaws that I may have missed.

Rails tip: handling a random sidebar

As you may or may not know, I’m working on a new portfolio. And while designing out the pages, I realized that there are times when I want a sidebar and times when I don’t. “Oh, I know, I know! content_for, right?” Yes and no.

content_for is a drop-in solution when content is always there, but changes dynamically depending on the template. It can’t really be responsible for structural changes, but rather the content represented within a structure (read: content within the sidebar, not the sidebar itself). Yes, I know I can use content_for to show/hide the sidebar as a whole, but what about the case when it’s not present? There’d be an empty sidebar area that my content may want to take advantage of, which is where my problem lies.

I didn’t want a javascript solution to stretch out the content if no sidebar exists (no matter how unobtrusive); I wanted it to be rendered as intended for that view. See the problem? The sidebar does change depending on the template (content_for), but I also need to handle the case where I don’t want the sidebar at all by stretching my content out to the distance of the space the sidebar would have taken up. Leave it up to me to make an easy concept confusing.

So, now that I’ve detailed the problem, let me just say that I’m completely aware that this isn’t the only way to do this. I’m not saying this is the best way, either. But so far it’s working well for me.

I approached the problem thinking of two “mini-layout” situations, where it really boiled down to a couple of CSS classes for the content and a “to be or not to be” sidebar. My two CSS classes: ‘medium’ and ‘large’. As one might deduce, the ‘medium’ content would be the view with the sidebar, and the ‘large’ content would extend the full width with no sidebar. Here’s a template that would contain a sidebar:

<% content :medium do -%>
  <!-- markup for the standard content area -->
<% end -%>

<% sidebar do -%>
  <!-- markup/partial for the sidebar -->
<% end -%>

Pretty straight forward, huh? Just to be complete, here’s a template that would not have a sidebar where the content would eat up that extra “wasted” space:

<% content :large do -%>
  <!-- markup for the expanded content area -->
<% end -%>

Again, this may or may not be the best way, but here’s the snippet from the layout:

<%= content_tag :div, :class => @size do -%>
  <%= yield -%>
<% end -%>

<%= yield :sidebar -%>

Pretty simple. Here are the content and sidebar helpers:

def content(size, &block)
  @size = size.to_s and yield
end

def sidebar(&block)
  content_for(:sidebar, content_tag(:div, capture(&block), :id => 'sidebar'))
end

Now, if I could only solve the problem that is wanting to build too many applications at once, I’d be set.

Consuming SOAP services in Ruby

I know, I know, REST is cool and SOAP sucks. Rails is awesome and .NET blows. But the reality is I have to do a little bit of both.

Things at work are moving more and more toward Rails, but there’s still a large investment in a few .NET systems that must be maintained (until the decision is made to rewrite them in Rails). With that means there are a few SOAP services that I still need to work with. It turns out, this isn’t so bad.

Originally I thought I’d bring back AWS and deal with it that way. But from my experience, AWS has more support for generating services rather than consuming services. While AWS isn’t a terrible approach, there’s an easier way this can be handled: SOAP::WSDLDriverFactory. This is a straight-up Ruby solution that comes shipped with the standard library. It’s straight-forward to use and requires no XML parsing (which sort of surprised me).

As an example, one of the Rails applications I’m currently working on needed to have the ability perform certain actions under that users’ .NET account. Mainly, since the applications are completely separate (read: separate DB, separate users table), I needed to get the user id from the .NET system via their credentials in the Rails system. While this isn’t the actual implementation, you can see how easy this is to do.

require 'soap/wsdlDriver'

class SomeDotNetWrapper
  attr_accesssor :endpoint, :service

  def initialize(endpoint=nil, service=nil)
    @endpoint = endpoint
    @service  = service
  end

  def get_user_id_from_credentials(username, password)
    soap = wsdl.create_rpc_driver
    response = soap.GetUserID(:username => username, :password => password)
    soap.reset_stream
    response.getUserIDResult
  end

  private
    def wsdl
      SOAP::WSDLDriverFactory.new("http://#{@endpoint}/services/#{@service}.asmx?WSDL"
    end
end

By creating a “factory” with the services’ WSDL, you can easily set things up for remote procedure calls (i.e. GetUserID(username, password)). What’s even nicer is that you can parse the response by chaining methods together. In this case, it put me right inside the response, where I only needed to call one level of nested XML (response.getUserIDResult). But if this were nested deeper, I’d just keep calling the methods that map to the XML nodes until I got to what I wanted. And of course, I could then write any Ruby code to do what I needed to do, but the point is it’s automatically method-like access, which is nice (think of Builder).

So, once you write your “wrapper” class, you’re ready to go.

class SomeDotNetWrapperController < ApplicationController

  def store_other_id
    raise InvalidCredentials if params[:username].blank? || params[:password].blank?
    service = SomeDotNetWrapper.new('http://example.com', 'authentication')
    other_id = service.get_user_id_from_credentials(params[:username], params[:password])
    current_user.update_attribute(:other_id, other_id) unless other_id.to_i == 0
  rescue InvalidCredentials
    # ...
  end
end

I’m sure there are a lot of different approaches, but this seemed the easiest to me. I had somewhat of a difficult time finding a solid solution online for easily consuming .NET SOAP services, so I decided to resort back to the standard library, as generally every language has support for this sort of thing. Anyway, maybe someone else with the same needs will find this useful.

Site updates

I spent the last day or two upgrading this site to run the latest and greatest Rails 2.0.2. Obviously, I didn’t want to upgrade without using what made me want to upgrade in the first place, so there I was, yet again, rewriting my code to be much leaner and meaner. This is probably the largest refactor I’ve done in terms of restructuring, but it desperately needed to happen.

Briefly, here are the (noteworthy) changes:

  • fixes/modifications for Rails 2.0.2 compatibility
  • complete revamp of the code base, now supporting a RESTful design
  • posts are now located at /posts/:id instead of /posts/:year/:month/:day/:permalink (sorry to break your bookmarks)
  • archives now act like real archives (you can no longer get to posts for December of 2007 by visiting /posts/2007/12, instead try /archives/2007/12 – the same goes for tags: /archives/tag/:name)
  • removed “featured project” from home page
  • added popular tags and recent comments in place of “featured project” on home page
  • removed popular tags from sidebar and increased del.icio.us bookmarks to show 12 instead of 8
  • implemented a new API module used to cache del.icio.us bookmarks and flickr photos (still have more changes to do there)
  • added an admin namespace to replace inline editing (feels much cleaner to me)
  • rearranged/removed several controllers/actions to make more sense

That’s basically it. Most of the changes were behind the scenes, except for the new addition to the home page. The only section that didn’t receive any attention was the portfolio. And that’s because I’m working on a new portfolio that will eventually let me get rid of the half-assed effort I have now. When I’m finished with it, it will be its own beast and live at its own (sub)domain.

UPDATE

I added support to map the old URLs, as well as the new ones. So bookmarks (like there are any) should still work.

Renaming views for Rails 2.0

Now that Rails 2.0 has officially been released, I’ve been porting a few choice applications to the new version. I’ve been maintaining a rake file with various tasks to assist me in the process. Here’s a particularly useful one that will rename your views to the new action.format.renderer format:

# $> rake upgrade:views:rename

namespace :upgrade do
  namespace :views do
    desc 'Renaming all views to new Rails 2.0 format: action.format.renderer'
    task :rename do
      Dir.glob('app/views/**/[^_]*.rhtml').each do |file|
        puts `svn mv #{file} #{file.gsub(/\.rhtml$/, '.html.erb')}`
      end

      Dir.glob('app/views/**/[^_]*.rxml').each do |file|
        puts `svn mv #{file} #{file.gsub(/\.rxml$/, '.xml.builder')}`
      end

      Dir.glob('app/views/**/[^_]*.rjs').each do |file|
        puts `svn mv #{file} #{file.gsub(/\.rjs$/, '.js.rjs')}`
      end

      Dir.glob('app/views/**/[^_]*.haml').each do |file|
        puts `svn mv #{file} #{file.gsub(/\.haml$/, '.html.haml')}`
      end
    end
  end
end

The existing .rhtml templates will still work in Rails 2.0, so this isn’t mandatory or anything. But it’s a good idea to get used to the new format, as it’s a nice convention for dealing with what your actions can respond_to.

Section content with Control.Tabs

Sometimes views can get unavoidably large (think eBay registration form). And sometimes it’s nice to group related content within a view. Well, in either case, here’s an option to do just that.

I found a prototype extension, Control.Tabs which basically gives you a menu to show certain pieces of markup. It suited my needs and here’s how I tied it into Rails.

I didn’t want to fiddle with javascript each time I needed this in a view, so I created a block helper to do the work for me1:

def tabbed_content(*links, &block)
  dom_id = links.last.is_a?(Hash) ? links.pop.values.last : 'tabbed-menu'

  list_items = links.inject([]) { |items, link| items << content_tag(:li, link_to(link.to_s.capitalize, "##{link.to_s.downcase}")) }
  tabs = content_tag(:ul, list_items, :id => dom_id)

  concat tabs, block.binding
  yield
  concat javascript_tag("new Control.Tabs('#{dom_id}');"), block.binding
end

Now when a view gets inherently too large (or needs grouped), I can make it scroll-friendly and simplify the code. As an example, here’s how I’d use it to section off someone’s online resume.

<% tabbed_content :education, :work, :references do -%>

  <div id='education'>
    <h2>Education Background</h2>
    <p>whatever you want</p>
  </div>

  <div id='work'>
    <h2>Work Experience</h2>
    <p>whatever you want</p>
  </div>

  <div id='references'>
    <h2>References</h2>
    <p>whatever you want</p>
  </div>

<% end -%>

This will place a set of links (capitalized versions of what was passed in) at the top of the content, defaulting to the first section. As expected, clicking a link will show only that section. And the javascript writes an “active” class to the appropriate link, which is nice for the