diff options
Diffstat (limited to 'railties')
-rw-r--r-- | railties/doc/guides/debugging/debugging_rails_applications.txt | 220 | ||||
-rw-r--r-- | railties/doc/guides/routing/routing_outside_in.txt | 86 |
2 files changed, 291 insertions, 15 deletions
diff --git a/railties/doc/guides/debugging/debugging_rails_applications.txt b/railties/doc/guides/debugging/debugging_rails_applications.txt new file mode 100644 index 0000000000..4182821c90 --- /dev/null +++ b/railties/doc/guides/debugging/debugging_rails_applications.txt @@ -0,0 +1,220 @@ +Debugging Rails applications +============================ + +You may have heard about debugging: + +_Debugging is a methodical process of finding and reducing the number of bugs, or defects, in a computer program or a piece of electronic hardware thus making it behave as expected._ + +Many times your code may not behave has you expect, sometimes you will try to print in logs or console values to make a diagnostic of the problem. + +Unfortunately, you won't find always the answer you are looking for this way. In that case, you will need to know what's happening and adventure into Rails, in this journey the debugger will be your best companion. + + +== Introducing the debugger + +=== Rails debugging history + +Rails has built-in support for ruby-debug since April 28, 2007. When the Breakpoint library was removed in favor of ruby-debug, the reason? + +The breakpointer, included in the Breakpoint library, and Binding.of_caller were removed in favor of relying on ruby-debug by Kent Sibilev. + +The problem was a bug in Ruby 1.8.4, that was fixed in Ruby 1.8.5 but left unusable the breakpointer. The Breakpoint library is also no longer being maintained, so it's effectively dead. + +=== Start debugging your rails app + +Inside any Rails application you can invoke the debugger by calling the *debugger* method. + +Let's take a look at an example: + +[source, ruby] +---------------------------------------------------------------------------- +class PeopleController < ApplicationController + def new + debugger + @person = Person.new + end +end +---------------------------------------------------------------------------- + +If you see the message in the console or logs: + +[source, shell] +---------------------------------------------------------------------------- +***** Debugger requested, but was not available: Start server with --debugger to enable ***** +---------------------------------------------------------------------------- + +Make sure you have started your web server with the option --debugger: + +[source, shell] +---------------------------------------------------------------------------- +~/PathTo/rails_project$ script/server --debugger +---------------------------------------------------------------------------- + +In order to use Rails debugging you'll need to be running either *WEBrick* or *Mongrel*. For the moment, no alternative servers are supported. + + +== The debugger +=== The debugger shell + +As soon as your application calls the *debugger* method, the debugger will be started in a debugger shell inside the terminal window you've fired up your application server and you will be placed in the ruby-debug's prompt (rdb:n). The n is the thread number. + +If you got there by a browser request, the browser will be hanging until the debugger has finished and the trace has completely run as any normal request. + +For example: + +[source, shell] +---------------------------------------------------------------------------- +@posts = Post.find(:all) +(rdb:7) +---------------------------------------------------------------------------- + +Now it's time to play and dig into our application. The first we are going to do is ask our debugger for help... so we type: *help* (You didn't see that coming, right?) + +[source, shell] +---------------------------------------------------------------------------- +(rdb:7) help +ruby-debug help v0.10.2 +Type 'help <command-name>' for help on a specific command + +Available commands: +backtrace delete enable help next quit show trace +break disable eval info p reload source undisplay +catch display exit irb pp restart step up +condition down finish list ps save thread var +continue edit frame method putl set tmate where +---------------------------------------------------------------------------- + +The second command before we move on, is one of the most useful command: *list* (or his shorthand *l*) + +This command will give us a starting point of where we are by printing 10 lines centered around the current line; the current line here is line 6 and is marked by =>. + +[source, shell] +---------------------------------------------------------------------------- +(rdb:7) list +[1, 10] in /PathToProject/posts_controller.rb + 1 class PostsController < ApplicationController + 2 # GET /posts + 3 # GET /posts.xml + 4 def index + 5 debugger +=> 6 @posts = Post.find(:all) + 7 + 8 respond_to do |format| + 9 format.html # index.html.erb + 10 format.xml { render :xml => @posts } +---------------------------------------------------------------------------- + +If we do it again, this time using just *l*, the next ten lines of the file will be printed out. + +[source, shell] +---------------------------------------------------------------------------- +(rdb:7) l +[11, 20] in /Users/miloops/Workspace/rails_edge_app/app/controllers/posts_controller.rb + 11 end + 12 end + 13 + 14 # GET /posts/1 + 15 # GET /posts/1.xml + 16 def show + 17 @post = Post.find(params[:id]) + 18 + 19 respond_to do |format| + 20 format.html # show.html.erb +---------------------------------------------------------------------------- + +And so on until the end of the current file, when the end of file is reached, it will start again from the beginning of the file and continue again up to the end, acting as a circular buffer. + +=== The context +When we start debugging your application, we will be placed in different contexts as you go through the different parts of the stack. + +A context will be created when a stopping point or an event is reached. It has information about the suspended program which enable a debugger to inspect the frame stack, evaluate variables from the perspective of the debugged program, and contains information about the place the debugged program is stopped. + +At any time we can call the *backtrace* command (or alias *where*) to print the backtrace of the application, this is very helpful to know how we got where we are. If you ever wondered about how you got somewhere in your code, then *backtrace* is your answer. + +The available variables are the same as if we were running the code line by line, after all, that's what debugging is. + +=== Inspecting variables + +In the following example we will print the instance_variables defined within the current context. + +[source, shell] +---------------------------------------------------------------------------- +@posts = Post.find(:all) +(rdb:11) instance_variables +["@_response", "@action_name", "@url", "@_session", "@_cookies", "@performed_render", "@_flash", "@template", "@_params", "@before_filter_chain_aborted", "@request_origin", "@_headers", "@performed_redirect", "@_request"] +---------------------------------------------------------------------------- + +As you may have figured out, all variables that you can access from a controller are displayed, lets run the next line, we will use *next* (we will get later into this command). + +[source, shell] +---------------------------------------------------------------------------- +(rdb:11) n +Processing PostsController#index (for 127.0.0.1 at 2008-09-04 19:51:34) [GET] + Session ID: BAh7BiIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNoSGFzaHsABjoKQHVzZWR7AA==--b16e91b992453a8cc201694d660147bba8b0fd0e + Parameters: {"action"=>"index", "controller"=>"posts"} +/PathToProject/posts_controller.rb:8 +respond_to do |format| +------------------------------------------------------------------------------- + +And we'll ask again for the instance_variables. + +[source, shell] +---------------------------------------------------------------------------- +(rdb:11) instance_variables +["@_response", "@action_name", "@url", "@_session", "@_cookies", "@performed_render", "@_flash", "@template", "@_params", "@before_filter_chain_aborted", "@posts", "@request_origin", "@_headers", "@performed_redirect", "@_request"] +---------------------------------------------------------------------------- + +Now @posts is a included in them, because the line defining it was executed. + +[NOTE] +You can also step into *irb* mode with the command *irb* (of course!). This way an irb session will be started within the context you invoked it. But you must know that this is an experimental feature. + +To show variables and their values the *var* method is the most convenient way: + +[source, shell] +---------------------------------------------------------------------------- +var +(rdb:1) v[ar] const <object> show constants of object +(rdb:1) v[ar] g[lobal] show global variables +(rdb:1) v[ar] i[nstance] <object> show instance variables of object +(rdb:1) v[ar] l[ocal] show local variables +---------------------------------------------------------------------------- + +This is a great way for inspecting the values of the current context variables. For example: + +[source, shell] +---------------------------------------------------------------------------- +(rdb:9) v l + __dbg_verbose_save => false +---------------------------------------------------------------------------- + +You can also inspect for an object method this way: + +[source, shell] +---------------------------------------------------------------------------- +(rdb:9) v instance Post.new +@attributes = {"updated_at"=>nil, "body"=>nil, "title"=>nil, "published"=>nil, "created_at"... +@attributes_cache = {} +@new_record = true +---------------------------------------------------------------------------- + +== Everything as an end +=== Let it be + +* *continue* [line-specification] (or alias *c*): resume program execution, at the address where your script last stopped; any breakpoints set at that address are bypassed. The optional argument line-specification allows you to specify a line number to set a one-time breakpoint which is deleted when that breakpoint is reached. +* *finish* [frame-number]: execute until selected stack frame returns. If no frame number is given, we run until the currently selected frame returns. The currently selected frame starts out the most-recent frame or 0 if no frame positioning (e.g up, down or frame) has been performed. If a frame number is given we run until frame frames returns. + + +=== Quitting +To exit the debugger, use the *quit* command (abbreviated *q*), or alias *exit*. + +A simple quit tries to terminate all threads in effect. Therefore your server will be stopped and you will have to start it again. + +== References + +* link:http://www.datanoise.com/ruby-debug[ruby-debug Homepage] +* link:http://www.sitepoint.com/article/debug-rails-app-ruby-debug/[Article: Debugging a Rails application with ruby-debug] +* link:http://brian.maybeyoureinsane.net/blog/2007/05/07/ruby-debug-basics-screencast/[ruby-debug Basics screencast] +* link:http://railscasts.com/episodes/54-debugging-with-ruby-debug[Ryan Bate's ruby-debug screencast] +* link:http://bashdb.sourceforge.net/ruby-debug.html[Debugging with ruby-debug] +* link:http://cheat.errtheblog.com/s/rdebug/[ruby-debug cheat sheet]
\ No newline at end of file diff --git a/railties/doc/guides/routing/routing_outside_in.txt b/railties/doc/guides/routing/routing_outside_in.txt index 7817fa66d3..aecfb949e9 100644 --- a/railties/doc/guides/routing/routing_outside_in.txt +++ b/railties/doc/guides/routing/routing_outside_in.txt @@ -10,7 +10,7 @@ This guide covers the user-facing features of Rails routing. By referring to thi == The Dual Purpose of Routing -Rails routing is a two-way piece of machinery - rather as if you could turn pigs into sausage, and then turn sausage back into pigs. Specifically, it both connects incoming HTTP requests to the code in your application's controllers, and helps you generate URLs without having to hard-code them as strings. +Rails routing is a two-way piece of machinery - rather as if you could turn trees into paper, and then turn paper back into trees. Specifically, it both connects incoming HTTP requests to the code in your application's controllers, and helps you generate URLs without having to hard-code them as strings. === Connecting URLs to Code @@ -34,6 +34,8 @@ Routing also works in reverse. If your application contains this code: Then the routing engine is the piece that translates that to a link to a URL such as +http://example.com/patient/17+. By using routing in this way, you can reduce the brittleness of your application as compared to one with hard-coded URLs, and make your code easier to read and understand. +NOTE: Patient needs to be declared as a resource for this style of translation via a named route to be available. + == Quick Tour of Routes.rb There are two components to routing in Rails: the routing engine itself, which is supplied as part of Rails, and the file +config/routes.rb+, which contains the actual routes that will be used by your application. Learning exactly what you can put in +routes.rb+ is the main topic of this guide, but before we dig in let's get a quick overview. @@ -45,7 +47,7 @@ In format, +routes.rb+ is nothing more than one big block sent to +ActionControl * RESTful Routes * Named Routes * Nested Routes -* Regular (old-style) Routes +* Regular Routes * Default Routes Each of these types of route is covered in more detail later in this guide. @@ -81,9 +83,9 @@ map.resources :assemblies do |assemblies| end ------------------------------------------------------- -=== Regular (old-style) Routes +=== Regular Routes -In many applications, you'll still see the older-style (non-RESTful) routing, which explicitly connects the parts of a URL to a particular action. For example, +In many applications, you'll also see non-RESTful routing, which explicitly connects the parts of a URL to a particular action. For example, [source, ruby] ------------------------------------------------------- @@ -102,9 +104,9 @@ map.connect ':controller/:action/:id.:format' These default routes are automatically generated when you create a new Rails application. If you're using RESTful routing, you will probably want to remove them. -== RESTful Routing: the New Default +== RESTful Routing: the Rails Default -RESTful routing is the new standard for routing in Rails, and it's the one that you should prefer for new applications. It can take a little while to understand how RESTful routing works, but it's worth the effort; your code will be easier to read and you'll be working with Rails, rather than fighting against it, when you use this style of routing. +RESTful routing is the current standard for routing in Rails, and it's the one that you should prefer for new applications. It can take a little while to understand how RESTful routing works, but it's worth the effort; your code will be easier to read and you'll be working with Rails, rather than fighting against it, when you use this style of routing. === What is REST? @@ -262,7 +264,7 @@ This declaration constrains the +:id+ parameter to match the supplied regular ex ==== Using :conditions -Conditions in Rails routing are currently used only to set the HTTP verb for individual routes. Although in theory you can set this for RESTful routes, in practice there is no good reason to do so. (You'll learn more about conditions in the discussion of old-style routing later in this guide.) +Conditions in Rails routing are currently used only to set the HTTP verb for individual routes. Although in theory you can set this for RESTful routes, in practice there is no good reason to do so. (You'll learn more about conditions in the discussion of classic routing later in this guide.) ==== Using :as @@ -440,8 +442,8 @@ You can nest resources within other nested resources if you like. For example: [source, ruby] ------------------------------------------------------- -map.resources :publisher do |publisher| - publisher.resources :magazine do |magazine| +map.resources :publishers do |publisher| + publisher.resources :magazines do |magazine| magazine.resources :photos end end @@ -461,8 +463,8 @@ The +:shallow+ option provides an elegant solution to the difficulties of deeply [source, ruby] ------------------------------------------------------- -map.resources :publisher, :shallow => true do |publisher| - publisher.resources :magazine do |magazine| +map.resources :publishers, :shallow => true do |publisher| + publisher.resources :magazines do |magazine| magazine.resources :photos end end @@ -530,11 +532,11 @@ This will allow the new action to be invoked by any request to +photos/new+, no If you find yourself adding many extra actions to a RESTful route, it's time to stop and ask yourself whether you're disguising the presence of another resource that would be better split off on its own. When the +:member+ and +:collection+ hashes become a dumping-ground, RESTful routes lose the advantage of easy readability that is one of their strongest points. -== Regular (Old-Style) Routes +== Regular Routes -Before there was RESTful routing, there was simple Rails routing - a way to map URLs to controllers and actions. With regular routing, you don't get the masses of routes automatically generated by RESTful routing. Instead, you must set up each route within your application separately. +In addition to RESTful routing, Rails supports regular routing - a way to map URLs to controllers and actions. With regular routing, you don't get the masses of routes automatically generated by RESTful routing. Instead, you must set up each route within your application separately. -While RESTful routing has become the Rails standard, there are still plenty of places where the simpler regular routing works fine. You can even mix the two styles within a single application. +While RESTful routing has become the Rails standard, there are still plenty of places where the simpler regular routing works fine. You can even mix the two styles within a single application. In general, you should prefer RESTful routing _when possible_, because it will make parts of your application easier to write. But there's no need to try to shoehorn every last piece of your application into a RESTful framework if that's not a good fit. === Bound Parameters @@ -742,7 +744,11 @@ map.connect '', :controller => "pages", :action => "main" TIP: If the empty route does not seem to be working in your application, make sure that you have deleted the file +public/index.html+ from your Rails tree. -== Dumping Routes with rake +== Inspecting and Testing Routes + +Routing in your application should not be a "black box" that you never open. Rails offers built-in tools for both inspecting and testing routes. + +=== Seeing Existing Routes with rake If you want a complete list of all of the available routes in your application, run the +rake routes+ command. This will dump all of your routes to the console, in the same order that they appear in +routes.rb+. For each route, you'll see: @@ -761,3 +767,53 @@ formatted_users GET /users.:format {:controller=>"users", :action=>"index"} ------------------------------------------------------------------------------------------------------- TIP: You'll find that the output from +rake routes+ is much more readable if you widen your terminal window until the output lines don't wrap. + +=== Testing Routes + +Routes should be included in your testing strategy (just like the rest of your application). Rails offers three link:http://api.rubyonrails.com/classes/ActionController/Assertions/RoutingAssertions.html[built-in assertions] designed to make testing routes simpler: + +* +assert_generates+ +* +assert_recognizes+ +* +assert_routing+ + +==== The +assert_generates+ Assertion + +Use +assert_generates+ to assert that a particular set of options generate a particular path. You can use this with default routes or custom routes + +[source, ruby] +------------------------------------------------------- +assert_generates("/photo/1", { :controller => "photos", :action => "show", :id => "1" }) +assert_generates("/about", :controller => "pages", :action => "about") +------------------------------------------------------- + +==== The +assert_recognizes+ Assertion + +The +assert_recognizes+ assertion is the inverse of +assert_generates+. It asserts that Rails recognizes the given path and routes it to a particular spot in your application. + +[source, ruby] +------------------------------------------------------- +assert_recognizes({ :controller => "photos", :action => "show", :id => "1" }, "/photo/1") +------------------------------------------------------- + +You can supply a +:method+ argument to specify the HTTP verb: + +[source, ruby] +------------------------------------------------------- +assert_recognizes({ :controller => "photos", :action => "create" }, { :path => "photos", :method => :post }) +------------------------------------------------------- + +You can also use the RESTful helpers to test recognition of a RESTful route: + +[source, ruby] +------------------------------------------------------- +assert_recognizes(new_photo_url, { :path => "photos", :method => :post }) +------------------------------------------------------- + +==== The +assert_routing+ Assertion + +The +assert_routing+ assertion checks the route both ways: it tests that the path generates the options, and that the options generate the path. Thus, it combines the functions of +assert_generates+ and +assert_recognizes+. + +[source, ruby] +------------------------------------------------------- +assert_recognizes({ :path => "photos", :method => :post }, { :controller => "photos", :action => "create" }) +-------------------------------------------------------
\ No newline at end of file |