Archive for August, 2008

Upgrade to rails 2.1 from 2.0.2 – Postgres Adapter fails on create/drop database

August 31st, 2008  |  Published in Uncategorized

We recently upgraded from ruby 1.8.6 and rails 2.0.2 to 1.8.7/2.1.0 respectively. This guide was incredibly helpful but one small caveat I ran into after the upgrade was related to postgresql.

It seemed that the new postgres_adapter.rb didn’t properly quote several of the commands: drop database and create database.
For example:


def drop_database(name) #:nodoc:
  execute "DROP DATABASE IF EXISTS #{name}"
end

should be something like:


def drop_database(name)
  execute "DROP DATABASE IF EXISTS \"#{name}\""
end

And same goes for create_databse.

It looks like there are fixes in edge for create_database and “drop_database.

map.resource nested routes ignore requirements

August 30th, 2008  |  Published in Uncategorized

In our application we try to use friendly URLs wherever we can. We decided to use user names instead of IDs but ran into the need to permit certain usually forbidden characters.

Initially our routes.rb had a section that looked as follows:


map.resources :users, :requirements => { :id => /[a-zA-Z0-9.@:%+;:?&=_+-]+/ } do |user|
  user.resources :messages
  user.resources :books
  user.resources :contacts
end

However, we soon realized that the requirements portion wasn’t adhered to when the nested resources were called. For example:

  • /users/joe = ok
  • /users/joe/books = ok

However

  • /users/joe+B.+black = ok BUT
  • /users/joe+B.+black/books = not ok.

The solution for now was to just rewrite each nested route separatly and repeat the requirements but that felt redundant and wrong…
For more gory details or to keep track of the issue I opened a ticket.

ruby-debug to the rescue

August 29th, 2008  |  Published in Uncategorized

Having used gdb many ages ago for debugging some C code, I really missed being able to just pause the execution of my java programs and muck around. I was really thrilled to discover “ruby-debug”:http://rubyforge.org/projects/ruby-debug/ which is an incredibly powerful debugging tool.

* You install it like any other gem

$ sudo gem install ruby-debug

* Add require ‘ruby-debug’ to your environment configuration
* To enter the debugger mode simply add the ‘debugger’ statement anywhere you see fit.
Example:


def login
  debugger
  user = User.authenticate...
end

* Be sure to start your server with the –debugger flag as follows:


$ ruby script/server --debugger

When you’re in the debugger, here are some useful commands you can use:
* list – shows you where you are in context. Example:


(rdb:2) list
[54, 63] in ./script/../config/../app/controllers/user_controller.rb
   54      end
   55    end
   56
   57    def login
   58      debugger
=> 59      user = User.authenticate...

* p – prints any ruby statement. So ‘p params’ will print the params (so will just params by the way) but p is_true == is_false will evaluate the expression and then output it.
* where – gives you the stack trace and your position in it
* step – takes the next single step
* next – goes to the next line

To see the rest of the commands just run help at any point.
I find that some of the most helpful things to look at are my params and request objects.

Hope this was helpful

In_Place_Editing in Rails 2.1

August 28th, 2008  |  Published in Uncategorized

I haven’t had a chance to play with in place editing since before Rails 2.* and so I discovered that the feature was now a plugin.
I didn’t have much luck finding very good documentation for it and so I will attempt to summarize a few of the steps I had to take to get it working.

  1. Install the plugin:
    ruby script/plugin install http://svn.rubyonrails.org/rails/plugins/in_place_editing
  2. Apply the authentication patch:
    1. Download it here
    2. From your plugin directory (RAILS_APP/vendor/plugins/in_place_editing) apply the patch:
      
      patch -p0 <in_place_editing_should_work_with_csrf_and_rjs
      
  3. Your in place edit field will be added to (most likely) one of your show views. Open the view in question (the one that currently only displays the information) and modify it as follows:
    1. Create a span (or any other element that will contain the updated text) with id X
      Example:
      
      <span id="edit_profile"><%= @user.profile %></span>
      
    2. Create an in_place_editor field. You have to provide a url parameter. This is the url to which the updated text will be posted to. Note that the name of the in_place_editor is identical to the ID of the element you created in the previous section, that is important as well.
      Example:
      
      <%= in_place_editor "edit_profile", {:url => url_for(:action => "update", :id => @user.id) } %>
      

      Some additional elements you might want to set besides url can be found here

  4. Once you actually have the element in place, you need to handle the update action in your controller. In this example, lets say we have a UsersController to which we add an update method:
    Example:
    
      def update
        if params[:editorId] && params[:editorId]  "edit_profile"
          if @user.id  params[:id]
            new_profile_text = ""
            new_profile_text = params[:value] if params[:value]
            @user.profile = new_profile_text
            @user.save!
          end
        end
        render :text => @user.profile
      end
    

    Some important things to note about the code above:

    1. The params[:editorId] will contain the ID you assigned your in_place_edit. This is useful if you have more than one of them.
    2. the params[:value] will actually have the new value you wish you replace. I highly recommend cleaning it up with something like hpricot but you already know that ;)
    3. The method must end with rendering as text the result you wish to redisplay. I messed around with rjs and even saw a great tutorial (unfortunately only available as a Google cache) that extends this plugin to return json but found this to work the best.

In my next post I’ll talk a little bit about how I modified/extended my in_place_editor to take additional arguments I felt made more sense for my configuration. Hopefully someone will find that useful =)