ruby rails binding.pry how to step - ruby-on-rails

What are the terminal commands to step over a line of code while using ruby rails 'binding.pry'? In addition do you know the command to step into, step out of, and continue?
Here is an example:
def add_nums
x = 5 + 5
binding.pry
x += 5
x += 7
return x
end
I'd like to know how to step through this method and in my terminal to see what the value of 'x' is until it is returned. Thanks

Inelegant Solution
Since you have access to the scope of x, manually enter each line (or anything you want) and see how it impacts your variable.
More Elegant Solution
Check out either PryDebugger (MRI 1.9.2+) or Pry ByeBug (MRI 2+) which give you controls to manually step through code. If you choose ByeBug the brief syntax example is:
def some_method
puts 'Hello World' # Run 'step' in the console to move here
end
binding.pry
some_method # Execution will stop here.
puts 'Goodbye World' # Run 'next' in the console to move here.
Hope this helps.

next executes that line of code and proceeds to the next line. step steps into a function. quit lets the program continue running.

Related

Rails skip byebug(s) for the rest of the execution

I am using inline byebug to stop the program execution and debug, from rails console or from a running rails server.
I have to debug a very repetitive loop, and I need to put a byebug in the middle of that loop.
After debugging, it seems my options are either to keep pressing c until I can get out of my loop, or abort the console execution execution with exit or something similar. But then I need to reload the whole environment.
Is it possible to just tell byebug to skip next byebug lines until the request (rails server) or until the command (rails console) finishes ?
I do this a couple ways:
1.
large_array.each.with_index do |item, index|
byebug if index == 0 # or any other condition, e.g. item.some_method?
# ...
end
byebug before the loop, set a breakpoint using b <line_number>. You can clear the breakpoint later at one of the prompts.

How to run script before every Rails console invocation?

I'm pretty tired of writing this line every time I want to open the Rails console:
irb(main):001:0> ActsAsTenant.current_tenant = User.find(1).account
Is there any way to run command/script before every "rails c"/"irb" invocation?
Thanks in advance!
Put the code you want to execute into .irbrc file in the root folder of your project:
echo 'ActsAsTenant.current_tenant = User.find(1).account' >> .irbrc
bundle exec rails c # ⇐ the code in .irbrc got executed
Sidenote: Use Pry instead of silly IRB. Try it and you’ll never roll back.
I wrote an extended answer to this in another question but the short answer is that if you are using Rails 3 or above you can use the console method on YourApp::Application to make it happen:
module YourApp
class Application < Rails::Application
...
console do
ActsAsTenant.current_tenant = User.find(1).account
end
end
end
You could put your setup code in a rb file, for example:
foo.rb:
def irb_setup
ActsAsTenant.current_tenant = User.find(1).account
end
launch irb like this:
irb -r ./foo.rb
and call the method (which will autocomplete pressing tab)
2.3.0 :001 > init_irb
In fact maybe you could put the code directly, without any method, and it would be executed when it is loaded. But I'm not sure if that would work or mess with the load order.

How to debug using rails console and puts in application

I want to get some lines printed in irb opened through rails console. I have seen a lot of SO questions of how to achieve it. But I get nothing in the irb.
below is the code--
def show
puts 'in show method'
#post = Feed.find_by_id params[:id]
puts #post.inspect
redirect_to root_path unless #post.present?
end
now I have opened server by command rails server. Also, In another terminal I gave the command rails console, it opened the irb prompt. when in browser I run localhost:3000/posts/82 it gives the correct post, but nothing is shown in the console. What step am I missing? I want to print something in the console when a particular method is called.
Best way to debug is to use the debugger command.
If you are using ruby 2.0 or above, you have to use the gem 'byebug' and if you are using 1.9 or below, then gem ruby-debug
then, when you run your server in development mode, your server will stop when it reaches the debugger allowing you to see your objects' state and modify them (much better than simply using puts
The program will stop in the same window that your server runs.
Some basic commands:
c continues the execution until next debugger is found
n runs the next command. If it is a function executes the
function
s step into the next command. If it is a
function, you will get into the function and see the variables
display expression on every step display the result of the
expression you write (very useful when debugging loops)
undisplay expression_number stops displaying the expresion
display shows all the expressions being displayed
list Displays the source code being executed
help shows the available commands help
command_name shows detailed info about a command
More info about debugging: http://guides.rubyonrails.org/debugging_rails_applications.html
The puts 'in show method' in line 2 won't show the output in rails console. Instead it shows the output in the same terminal where you did rails server. They might be lost with so much of output, so try to find it there itself.
Use Rails.logger.debug "in show method" etc.
In the second tab in terminal tail log/development.log like this
$ cd rails_app_root
$ tail -f log/development.log
or
$ cd rails_app_root
$ less +F log/development.log
There you will find all the output from the console.
Try to use Rails.logger
Rails.logger.info "Some debugging info I want to see in my
development log.------#{#post.inspect}"
It will print #post value in log file.
I am a big fan of puts debugging. e.g;
def index
method = Kernel.instance_method(:method)
p method.bind(request).call(:headers).source_location
#users = User.all
end
The above snippet helps you find where the method is implemented:
Processing by UsersController#index as */*
["/Users/aaron/git/rails/actionpack/lib/action_dispatch/http/request.rb", 201]
You can find more cool puts debugging here.

How to stop the Rails debugger for the current request

Say I have a loop in my code that calls the rails debugger a few times
def show
animals = ['dog', 'cat', 'owl', 'tiger']
for animal in animals
debugger
# do something else
end
Assuming I started my server with the --debugger option, when this page is viewed, the debugger is going to stop for every run of the loop.
I can type cont every time it stops so the request continues, but that's tedious, especially if we're not talking about it showing up 4 times as in this example, but 400.
Is there a way to let the debugger continue without pausing at each point of the loop?
My currently workaround is restarting the server, but that's time consuming.
Just put conditions on the debugger statement so that it stops only when you want it to, e.g.:
debugger if animal == 'tiger'
or if, say, you want to examine the code only on loop 384:
animals.each_with_index do |animal, i|
debugger if i == 384
# do something
end
or put in a variable that will let you continue ad hoc:
continue_debugger = false
animals.each do |animal|
debugger unless continue_debugger
# in the debugger type `p continue_debugger = true` then `c` when done
end
put your debugger statement somewhere before the iteration, then set a breakpoint inside the iteration which you can then clear later.
Example:
def index
debugger
#things = Thing.all
#things.each do |thing|
# ... something you want to check out in the debugger
thing.some_calculation
end
end
When you enter the debugger, set a breakpoint inside:
b app/controllers/things_controller.rb:42
(Where 42 is the line number you want to break at, like thing.some_calculation above. Note that it has to be an executable line of code -- comments, blank lines won't work). The debugger will show a breakpoint number and location:
Breakpoint 1 at .../app/controllers/things_controller.rb:42
Now, every time you continue, you will stop at the breakpoint. When you're done and want to complete the request, delete the breakpoint:
delete 1
continue once more, and you will complete the request!
It looks like in the source of ruby-debug, the call to debugger will always stop execution whenever it is hit. So one solution is to do as was suggested by Mori in his 'ad-hoc' solution, to make a conditional around the call to debugger that you can tweak inside the debugger session itself, such that you avoid calling debugger. This is probably the neatest solution, and what I would do unless you have some strong nagging purity issues with the code involved.
If you really want to only do this without some external conditional and inside the debugger session itself, it is possible. What you have to do is set a breakpoint in the code itself, then you can delete that breakpoint in the debugger when it is triggered:
require 'rubygems'
require 'ruby-debug'
Debugger.start
Debugger.add_breakpoint(__FILE__, __LINE__ + 2)
while true do
puts "Hi"
puts "mom"
end
Debugger.stop
This produces this sort of interaction:
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) c
Hi
mom
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) c
Hi
mom
Breakpoint 1 at debug_test.rb:10
debug_test.rb:10
puts "Hi"
(rdb:1) info b
Num Enb What
1 y at ./debug_test.rb:10
breakpoint already hit 3 times
(rdb:1) del 1
(rdb:1) c
Hi
mom
Hi
mom
Hi
mom
...and so on.
In this way, you are setting the breakpoint in code, then deleting it when you are done. Note that any time the line Debugger.add_breakpoint is called, it will re-set the breakpoint, so that's why it is outside of the loop and pointing 2 lines down. This technique can easily be extracted to require-ing a script that sets the breakpoint only when loading your server - Heck, you could write a whole framework class around controlling the Debugger module however you want. Of course, if you went this far, I would just create a singleton class that helps you implement Mori's ad-hoc solution and does or does-not call the debugger statement.
I came up with another answer to this today that I like even better:
debugger unless #no_debug
Use that on every line that has a debugger stop. When you want to stop stopping just set #no_debug to something.
I have another answer to this one: set a #debug on the class that you want to debug. That way you can do:
if (#debug && (the_condition)) then debugger end
or
debugger unless !#debug
then when you are done with the debugger just #debug = false and c.
However, I'm not really happy with having debugger 'hard stops' in live code. These are the kind of things that can be accidentally checked in and forgotten about until something breaks. The #debug would certainly fall under that as well. To that end I think my ideal solution would use Matt's idea and a script that sets up a breakpoint inside the object when the object is created. That way you'd have the debugging that you want but you wouldn't have any code in source control that is specifically for development. I'll update this answer if I find such a solution.
You can always comment out the debugger call from your code then type reload in your debug session. Then just cont once and the request will continue without triggering a debug session.
Because you're in development mode, you can just add the debugger call back in later and it will trigger correctly.
Putting this here as an alternative since this question showed up first in my own searches. Let's say you have a piece of code that isn't working under a specific circumstance, but works otherwise, and you have a whole slew of tests that exercise this but one specific test that fails. It's a PITA to have to continually type continue into the debug console until you get to the test you really want to debug, so I started using this convention:
In your code:
def some_common_function
debugger if defined? ::ASDF
# do something
end
Then in your test:
should "do this thing that it isn't doing under a specific circumstance" do
# setup the specific situation
::ASDF = true
# your tests
end
If I want control back, I just do
eval return
and I will exit the currently running function, which will usually kick me back to the IRB [rails console] prompt.
exit debugger out of the loop, use
exit-all
instead of
cont
Although, it will create an error and you might have to remove debugger and send request again but it will get you out of all the loops

"Printf" testing in Rails

I'm new to Rails and I'm aware it has things such as unit-testing built in. But I'm interested in doing some more simple tests that are equivalent to your "printf" in C. So I'm testing a login page I've written and want to trace the code to see what each line like my find methods are returning. I try outputting with "puts" but I don't get anything in the command-line.
I use puts statements all the time as well as the ruby debugger! It's great.
In rails you can do a couple things. I put "puts" in my code and when I run script/server at the command line, the output appears in my Terminal.app. I am running a Mac, but I am sure that there is a similar way to trace the activity of your app on your platform of choice.
The other option is to use the logger statement. you can call
logger.debug("My #{variable}")
and find these statements right in your log/development.log file.
Also, if you are running on a *nix system, you can use the "tail" command to trace the last statement written to your log one at a time.
tail -f log/development.log
This way you could write your statements and see them as they are happening. There are several levels of logging:
logger.warn
logger.info
logger.debug
logger.fatal
each environment (development, testing, production) will determine what "level" of logging will be called, so you may write log statements willy nilly with logger.debug while in development, but those log statements won't be written when you deploy based on the default log levels.
User something like this:
logger.info "method called with #{params.inspect}"
(you can put any variable inside the #{})
Once you're having fun with that, check out ./script/console and ruby-debug
Are you familiar with ruby-debug?
Install the ruby-debug gem.
Start your server with the -u option.
script/server -u
Put a debugger statement in your code where you want to stop.
You will have console access to your variables as well as the ability to step through your code.
Check the ruby-debug documentation for more details.
I've done this before - with Passenger, you don't have script/server's output, so I wrote this:
# extras/sexy_logging.rb
module SexyLogging
def log(text)
return true if RAILS_ENV == 'production'
string = "\e[0;32mLog:\e[m #{text}"
(100 - string.length).times do
string << ' '
end
string << "(#{caller.first})"
logger.debug string
end
end
ActiveRecord::Base.send :include, SexyLogging
ActionController::Base.send :include, SexyLogging
Then you can write
log variable
or
log 'Testing user'
tail -f log/development.log |grep Log:
and only see what you're logging, line by line and with colours.

Resources