We're busy adding support for Internet Explorer 6, but if you've been considering an upgrade you can upgrade Internet Explorer, or download Firefox for free.

Our site is best viewed on standards-compliant browsers: Firefox, Safari, Internet Explorer 7.0+, etc.

Stephanie Sharp Buck Sharp Kim Landrum Travis Roberts Colin Jones Natalie Glenn Andrew Reifman Charlie Maffitt Kelly C. Jones Juli Tredwell
Colin

Colin's Blog

RSS

Piggybacking on link_to_unless

Posted on 08/26/2008
0 Comments

We needed to add CSS to HTML links based on certain conditions (for instance, if you're already there). That's pretty easy to do by using link_to_unless, but the easy way isn't very DRY (Don't Repeat Yourself):

	<%= link_to_unless(@current_controller=='faq', "Frequently Asked Questions", faq_path){ 
			link_to("Frequently Asked Questions", faq_path, :class => 'active') 
	} %>

Hear how the text "Frequently Asked Questions" is screaming at you to stop typing it over & over? Well, this pattern (adding an "active" class to say YOU ARE HERE) happens often enough that it had to be broken out into a helper:

def link_to_active_if( condition, link_title, link_path = {}, opts = {} )
  if condition
    classes = opts.delete(:class) || ""
    classes.rstrip!    

    # checking to see if "active" is already one of the classes assigned, and if NOT, append it to the classes string
	
    unless classes =~ /^(\w*\s+)*active(?!\w)/ 
      if classes.blank? 
        classes = 'active'
      else
        classes << " active"
      end         
    end    
  end

  old_opts = opts.dup

  link_to_if( condition, link_title, link_path, opts.merge( {:class => classes} ) ) {
    link_to( link_title, link_path, old_opts )
  }
end

As you may see, there's kind of a hack at the regex beginning ("unless classes =~ " etc.) Ruby 1.9 users can get around that with the new hotness Regex engine Oniguruma (which allows negative lookbehind assertions), but we're a bit more restricted. At any rate, the craziness checking for "active" means you can send the class "active" in through the opts hash and only get 1 "active" back in the class string.

The new helper call is quite a bit cleaner, even if it doesn't make the questions REAL FAQ's:

<%= link_to_active_if( @current_controller=='faq', "Frequently Asked Questions", faq_path ) %>

That's great in cases where we want the link active for multiple actions in a controller (for instance), but since the current page/action being the exact link location is another common pattern, we can easily add another helper that uses the new link_to_active_if:

def link_to_active_if_current( link_title, link_path = {}, opts = {} )  	  
 	  link_to_active_if current_page?(link_path), link_title, link_path, opts
end

Giving us:

<%= link_to_active_if_current("Frequently Asked Questions", faq_path) %>

Tagged:  rails, helpers, helper method, active, css, link to unless current

Back to top

private method `split' called for Symbol

Posted on 08/12/2008
0 Comments

Thank God for Lighthouse.

I got this error (private method `split' called for :id:Symbol, in my case) because my has_many statement had :order => :id specified (yes, it looks a trivial order; it's legacy code, so give me a break).

Aha! We shouldn't be using symbols to represent table columns in our has_many statements. We're really talking about an SQL fragment, anyway, so it seems more sensible to use a string anyway. Consider a case where you want to include another table:

class Organization < ActiveRecord::Base
  has_many :users, :order => "accounts.number", :include => :account
end
class User < ActiveRecord::Base
  belongs_to :organization
  belongs_to :account
end
class Account < ActiveRecord::Base
  has_one :user
end

Certainly there's no way to do :accounts.number or something like that, and it doesn't make sense anyway. Long story short, it's OK to use Symbols for table names, but leave the columns to the strings, please!

Tagged:  private method symbol errors rails

Back to top

Command Line Navigation: Keyboard Shortcuts

Posted on 07/24/2008
0 Comments

How's about some handy-dandy command-line keyboard shortcuts for *nix? (*nix = Unix, Linux, Mac OSX, etc.)

These are all based on Emacs, which I never use (I prefer Textmate for most coding and vim/vi for changes on remote servers). A dash (-) means hold the first button down while you press the second, and a comma (,) means press the first, release it, then press the second.

  • Go to the start of the line: Ctrl-a
  • Go to the end of the line: Ctrl-e
  • Go back a word: Esc,b
  • Go forward a word: Esc,f
  • Delete everything from the cursor to the beginning of the line: Ctrl-u
  • Delete everything from the cursor to the end of the line: Ctrl-k

And don't forget that the up and down arrows are your friend when you want to do something again!

Enjoy your extra 3 seconds per messed-up command!

Tagged:  command line, keyboard shortcuts, linux, unix

Back to top

rake aborted! Access denied

Posted on 06/26/2008
1 Comment

This blog of mine is quickly becoming an encyclopedia of all the crazy problems that can happen if you're not careful. I'll have to do some more right-brained thinking for my next entry... At any rate, if you've been using Rails with MySQL, there's a hair-pulling problem you may run across when generating a new project from scratch, now that Rails 2.0 has SQLite3 as the default database.

Fire up a new rails application and add :

rails test_app

and then pop a simple migration in there:

cd test_app/
./script/generate model User login:string password:string

Now, being up on our Rails news, we know that config/database.yml is set up by default for SQLite3, so let's change it to work properly (being careful to avoid tabs---only spaces allowed in YAML). Here's a development section as an example (please read the whole article before trying to use this, though):

development:
  adapter: mysql
  database: test_app_development
  user: test_user
  password: test_password
  host: localhost

Now, we can just

rake db:migrate

and be off on our merry way, right? Well, of course not---we know we need to create the database using mysql or mysqladmin first:

$ mysql -p 
> create test_app_development;
> grant all privileges on test_app_development.* to 'test_user'@'localhost' identified by 'test_password';

But there's still a problem somewhere! Because you get

rake aborted!
Access denied for user 'root'@'localhost' (using password: YES)

when you try to rake db:migrate. Why is it looking for 'root' when you've already specified 'test_user' in the database.yml and your config/environment.rb designates that you are indeed in development mode?!?

Well, I was dismayed to find out that the hours I spent researching this problem were because of a typo in config/database.yml above:

  user: test_user

NO!

  username: test_user

YES!

So, long story short, if you get the dreaded

Access denied for user 'root'@'localhost'

using rake db:migrate or anything else in rails, and you have the database created and the user there matches the user in database.yml, PLEASE check well for typos in database.yml, because it's finicky and Rails won't let you know if there's a problem.

Tagged:  rails, mysql, rake, migrate, database, access, denied

Back to top

Arrays: Iterating + Deleting = BAD

Posted on 06/19/2008
0 Comments

Going through some legacy Ruby code that I'm updating for a client, I came across a seemingly random problem where some elements of an array weren't being removed properly. Here's a simplified version. Can you see the problem?

@example_array = ["a","b","c","d","e","f"]
@example_array.each do |example_element|         
  @example_array.delete(example_element)
end

The element after each element that got deleted successfully doesn't get deleted. Why? The delete call re-indexes the array in place before the iterator comes around again. The same is true, incidentally, of the insert method, which in the same context could continue infinitely.

Moral of the story: don't mess with the number of items in an enumerable as you're iterating through it. If you need this functionality, maybe just make a copy and modify that:

@example_array = ["a","b","c","d","e","f"]
@example_array_copy = @example_array.dup
@example_array.each do |example_element|         
  @example_array_copy.delete(example_element)
end
@example_array = @example_array_copy

Tagged:  array, iterate, delete

Back to top