Recipe 10.1. Exploring Rails from the Console


Problem

You want to debug your Rails application by inspecting objects and their methods interactively. You also want the ability to create and execute Ruby code in real time as you explore, and hopefully fix your application's internals.

Solution

Use the Rails console to dive into the inner workings of your application so you can debug it or just see how things are working. From your application's root, start up a console session with:

$ ./script/console              

Once at the console prompt, you can instantiate model objects, inspect object relationships, and explore object methods. With an example cookbook application you can create a new Chapter object and inspect its properties such as title, return the Recipes objects associated with that object, and return the title of each of the associated Recipe objects:

$ ./script/console  Loading development environment. >> c = Chapter.find(1) => #<Chapter:0x14a5bf8 @attributes={"sort_order"=>"1", "title"=>"Cooking Chicken", "id"=>"1"}> >> c.title => "Cooking Chicken" >> c.recipes => [#<Recipe:0x13f4b50 @attributes={"sort_order"=>"1",   "body"=>"fire it up...", "title"=>"BBQ Chicken", "id"=>"1",   "chapter_id"=>"1"}>, #<Recipe:0x13f4ac4 @attributes={"sort_order"=>"2",    "body"=>"pre-heat to 400...", "title"=>"Oven Roasted", "id"=>"2",    "chapter_id"=>"1"}>, #<Recipe:0x13f4704 @attributes={"sort_order"=>"3",    "body"=>"health warning: ...", "title"=>"Deep Fried", "id"=>"3",    "chapter_id"=>"1"}>] >> c.recipes.map {|r| r.title} => ["BBQ Chicken", "Oven Roasted", "Deep Fried"]

Perhaps you're debugging a NoMethodError error that you get when you view the chapter list in a browser. The ASCII version of the HTML error message might look something like:

NoMethodError in Chapters#list Showing app/views/chapters/list.rhtml where line #5 raised: undefined method `find_fried_recipe_titles' for Chapter:Class Extracted source (around line #5): 2:  3: Frying Recipes: 4: <ul> 5: <% Chapter.find_fried_recipe_titles.each do |t| %> 6:   <li><%= t %></li> 7: <% end %> 8: </ul> ...

This error is telling you that your application is trying to call a class method named find_fried_recipe_titles that doesn't seem to be defined. You can verify this by trying to call the method from your console session:

>> Chapter.find_fried_recipe_titles   NoMethodError: undefined method 'find_fried_recipe_titles'    for Chapter:Class from    /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.2/lib/   active_record/base.rb:1129:in    'method_missing'         from (irb):2

Sure enough, the method is undefined, perhaps because you forgot to implement it. You could create that implementation now by adding its method definition to the Chapter model class directly, but try coding it in the console first. After a little manipulation, you come up with the following expression that seems like it could serve as the body of the find_fried_recipe_titles method:

>> Chapter.find(:all, :include => :recipes).map {|c| c.recipes.map{|r| r \ ?> if r.title =~ /fried/i}}.flatten.compact.collect {|r| r.title} => ["Deep Fried", "Fried Zucchini"]

Once you're confident with the implementation you've played with in the console, you can add a cleaned-up version to the method body in the Chapter model class definition, inside of the class method definition for self.find_fried_recipe_titles.

app/models/chapter.rb:

class Chapter < ActiveRecord::Base   has_many :recipes   def self.find_fried_recipe_titles     Chapter.find(:all, :include => :recipes).map do |c|        c.recipes.map do |r|         r if r.title =~ /fried/i       end     end.flatten.compact.collect {|r| r.title}   end en

Now, within the same console prompt from before, you can reload your application and attempt to call find_fried_recipe_titles again, this time based on the class method you just defined in the Chapter model. To reload your application, type reload! at the console prompt, and then try invoking your new method:

>> reload! Reloading... => [ApplicationController, Chapter, Recipe] >> Chapter.find_fried_recipe_titles => ["Deep Fried", "Fried Zucchini"]

The reload! method (a handy wrapper around Dispatcher.reset_application!) reloads your application's classes and then waits for input in a "refreshed" environment. Calling Chapter.find_fried_recipe_titles this time works as expected; returning an array of recipe titles containing the word "fried." Viewing the list view in your browser works as expected too, now that you've defined the missing class method.

Discussion

The solution walks you through a typical debugging session using the Rails console, often referred to as script/console. The console is really just a wrapper around a standard Ruby irb session, with your Rails application environment preloaded. Developers unfamiliar with Ruby's irb or the Python command interpreter will soon wonder how they got by in other languages without such a seemingly indispensable tool.

/usr/local/lib/ruby/gems/1.8/gems/rails-1.1.2/lib/commands/console.rb:

#exec "#{options[:irb]} #{libs} --simple-prompt" exec "#{options[:irb]} #{libs}"             

$ ./script/console  Loading development environment. irb(main):001:0> Chapter.find(:all, :include => :recipes).map do |c| irb(main):002:1*   c.recipes.map do |r| irb(main):003:2*     r if r.title =~ /fried/i irb(main):004:2>   end irb(main):005:1> end.flatten.compact.collect {|r| r.title} => ["Deep Fried", "Fried Zucchini"] irb(main):006:0> 

See Also

  • For more on use of the Rails console, see http://wiki.rubyonrails.com/rails/pages/Console




Rails Cookbook
Rails Cookbook (Cookbooks (OReilly))
ISBN: 0596527314
EAN: 2147483647
Year: 2007
Pages: 250
Authors: Rob Orsini

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net