Debug into method from production irb - ruby-on-rails

When I look for a problem, for example with a specific ActiveRecord object, I often find myself doing the following on my production system:
# RAILS_ENV=production bundle exec
irb(main)> article = Article.find(123)
=> #<Article id: 123, title: "Foobar">
irb(main)> article.do_something(3)
NoMethodError: undefined method `id' for nil:NilClass
Sometimes I can't reproduce, why the line article.do_something(3) throws an error, so I want to debug it directly on my server, in production mode.
The problem now is: How do I step into the method #do_something with the argument 3 on the object / instance article?
Of course, one could set a breakpoint in that method, reload production and let all their customers wait on that breakpoint till I'm done debugging... But that wouldn't be the best idea.
So, is there a way to debug into a method of a specific instance from a running irb / pry session? (both would be ok)

After trying around and more googling, I think I found a solution that works for me.
Log in to your rails console / irb / pry session
Setup your case (e.g. load your models, require dependencies...), so that you can execute the code you want to debug in one line
require 'byebug' (or require 'debugger' for older ruby versions)
Now the interesting part: Put a debugger statement in front of the line you want to debug like this binding.pry; user.do_something or debugger; user.do_something
Now you are in your debugger. Maybe you have to jump to the next line with next (or just n if you have shortcuts enabled) to step into your method.
Here is a complete example from our production system:
[1] pry(main)> require 'byebug'
=> true
[2] pry(main)> user = User.find(2)
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
=> #<User id: 2, name="XXX XXX">
[3] pry(main)> user.full_name
NameError: undefined local variable or method address for #<User:0x0055b168663590>
[4] pry(main)> binding.pry; user.full_name
[68, 73] in /usr/src/app/app/models/user.rb
68: end
69:
70: def full_name
=> 71: "#{address.firstname} #{address.last_name}"
72: end
73: end
(byebug)

sure pry, byebug, etc. are awesome BUT you don't need a gem
Ruby 3 (and newer versions of Ruby 2.x) has irb debugging built in
require 'irb'
def run
a = "hello"
binding.irb # debug starts here, eg puts a
a = "something else"
a
end
run

You can use pry-debugger (through ruby 1.9.3) or pry-byebug (Ruby >= 2).
Both of these allow you to set breakpoints allowing you to interactively step through your code as it runs, inspecting variable values, method return values, etc.
How you'll manage this with production data I'm not exactly sure, but this will allow you to debug a particular method.

Related

Use ActiveSupport::Cache::FileStore directly in a model class

I tried to use ActiveSupport::Cache::FileStore dirctly in a model class:
#backend_cache = ActiveSupport::Cache::FileCache.new Rails.root.join("tmp", "cache")
The program reports a NameError
NameError: uninitialized constant ActiveSupport::Cache::FileCache
Did you mean? FileTest
I added
require "active_support"
require "active_support/core_ext"
It still shows the error. I know that I can use Rails.Cache for the purpose, but the object I cached must be on the disk, which is different from other parts of the application.
The application is written in Rails 6.
I tried this inside a rails 6 console and it works just fine.
#backend_cache = ActiveSupport::Cache::FileStore.new(Rails.root.join("tmp", "cache"))
#backend_cache.write('x', 1) # => true
#backend_cache.read('x') # => 1
It's just typo I mentioned in the comment. It's ::FileStore.new instead of ::FileCache.new

Rails console can find model instances but app doesn't. How?

Something unusual is happening with my app. I have a model called User and I made one instance from the Rails console. I can get it from the console, but not from the app.
Any hint on what may cause this behaviour?
If I run User.count in console I get 1, in app I get 0.
Running Rails.configuration.database_configuration[Rails.env] gives the same result in console and app: {"adapter"=>"sqlite3", "pool"=>5, "timeout"=>5000, "database"=>"db/development.sqlite3"}
(Running Ruby 2.6.0 and Rails 5.2.3)
I'm starting to think that Rails is making a fool of me 😹
Edit. My controller method:
def index
puts "DB CONF: #{Rails.configuration.database_configuration[Rails.env]}"
puts "USER COUNT: #{User.count}" #prints 0 to console
render plain: "#{User.count}" #prints 0 on page
end
Code in console:
Loading development environment (Rails 5.2.3)
2.6.0 :001 > User.count
(0.5ms) SELECT COUNT(*) FROM "users"
=> 1

How to figure out which Ruby gem has hijacked an ActiveRecord association method

Given this definition (using Rails 3.2.13 on Ruby 2.0.0-p195)...
class Food < ActiveRecord::Base
has_many :recipe_foods, foreign_key: :food_id
.reset is not acting as documented (it's supposed to reset the #loaded flag but instead it's re-querying the database and returning results)...
2.0.0-p195 :037 > f = Food.last
Food Load (1.6ms) ...
=> #<Food ...
2.0.0-p195 :038 > f.recipe_foods
RecipeFood Load (9.4ms) ...
=> [#<RecipeFood ...
2.0.0-p195 :039 > f.recipe_foods.reset
RecipeFood Load (10.0ms) ...
=> [#<RecipeFood ...
I suspect some other gem has hijacked the method, but this is what I get from .method ...
2.0.0-p195 :040 > f.recipe_foods.method(:reset).source_location
NameError: undefined method `reset' for class `Array'
How do I figure out what version of .reset is actually executing?
UPDATE:
When I try to call a non-existent method I get this chaos (in case that helps with the mystery):
2.0.0-p195 :052 > f.recipe_foods.snafu
NoMethodError: undefined method `snafu' for #<ActiveRecord::Relation:0x007fdaef6315b0>
2.0.0-p195 :053 > f.recipe_foods.method(:snafu)
NameError: undefined method `snafu' for class `Array'
My guess is that reset is actually a method on the AssociationProxy object, not the Array, which is why you're getting the undefined method. Rails 4 seems to be smarter about this:
> c = Company.first
> c.users.method(:find)
=> # <Method: ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_User(ActiveRecord::Associations::CollectionProxy)#find>
> c.users.method(:find).source_location
=> ["/Users/me/.rvm/gems/ruby-2.0.0-p195/gems/activerecord-4.0.0/lib/active_record/associations/collection_proxy.rb", 140]
I'm not sure of the best solution here, but I'd see if any of the tools in pry can be helpful.
Use a debugger. ruby-debug worked up until Ruby 1.9; byebug works for Ruby 2.0.
Write a script with a debugger breakpoint right before the call that's breaking:
f = Food.last
rf = f.recipe_foods
byebug # or debug
rf.reset
Then execute the script. The debugger will break right at before the call, which you can then step into to find out what code is actually being executed.

Rails: Me or them, files not being required in files from config/initializers/*.rb

I'm having really odd behavior with Rails, and I can't seem to figure out the problem. When I do require inside of a file in config/initializers nothing gets required...at all, here is an example:
From: /home/jordon/development/test1/config/initializers/test1.rb # line 6:
1: Dir[Test1::Application.config.root + '/lib/test1/**/*.rb'].each do |file|
2: # Test1::Patches::Redirecting
3: require file
4: end
5:
* 6: binding.pry
[1] pry(main)> Test1::Patches
^> NameError: uninitialized constant Test1::Patches
^> From (pry):1:in `<top (required)>'
[2] # The required file is from lib/test1.
[3] pry(main)> require 'rails/actionpack/lib/action_controller/metal/redirecting'
^> Return: true
Can anyone explain what is happening? Is there some kind of anti-require faerie built into Rails? No seriously, all joking aside can anyone seriously explain why Rails is not actually allowing my files to be required and how can I convince it to require my files so that I can attempt to extend redirect_to with wrappers.
Try to add
require file
In your environment.rb, and restart your server.

Rails3 Engine: Gems (paperclip and inherited_resources) not loaded

In my rails3 engine gemfile, I added:
gem 'paperclip'
gem 'inherited_resources'
I also added this to my gemspec:
s.add_dependency "paperclip"
s.add_dependency "inherited_resources"
I then ran bundle install for both my engine and the client app and started up the console for the client app in order to first test paperclip, to which I get:
Using /Users/ynkr/.rvm/gems/ruby-1.9.2-p180 with gemset rails31beta
ynkr % rails c
/Users/ynkr/.rvm/gems/ruby-1.9.2-p180#rails31beta/gems/actionpack-3.1.0.rc4/lib/action_dispatch/http/mime_type.rb:101: warning: already initialized constant YML
Loading development environment (Rails 3.1.0.rc4)
ruby-1.9.2-p180 :001 > b=Blog::Blog.first
Blog::Blog Load (0.2ms) SELECT `blogs`.* FROM `blogs` LIMIT 1
=> #<Blog::Blog id: 1, user_id: 1, context_id: 2, title: "Cmd Line Blog Title", title_for_url: "cmd-line-blog-title", teaser: "This is the teaser for the command line blog", content: "Some content for the cmd line blog", created_at: "2011-06-28 06:06:55", updated_at: "2011-06-28 06:06:55">
ruby-1.9.2-p180 :002 > b.photos
NoMethodError: undefined method `has_attached_file' for #<Class:0x00000102a57fc8>
from /Users/ynkr/.rvm/gems/ruby-1.9.2-p180#rails31beta/gems/activerecord-3.1.0.rc4/lib/active_record/base.rb:1078:in `method_missing'
from /websites/gems/blog/app/models/blog/photo.rb:6:in `<class:Photo>'
from /websites/gems/blog/app/models/blog/photo.rb:1:in `<top (required)>'
from /Users/ynkr/.rvm/gems/ruby-1.9.2-p180#rails31beta/gems/activesupport-3.1.0.rc4/lib/active_support/dependencies.rb:452:in `load'
OK, so it appears the has_attached_file method from the paperclip gem cannot be found. Why? I'm not sure.
Moving on to inherited_resources, I altered a scaffold generated controller to look like the following:
class Blog::ContextsController < InheritedResources::Base
before_filter :redirect_unless_admin
end
and load up the index page for that to which I am greeted (in the logs) with:
Started GET "/blog/contexts" for 127.0.0.1 at 2011-06-28 12:06:25 -0700
ActionController::RoutingError (uninitialized constant InheritedResources):
Rendered /Users/ynkr/.rvm/gems/ruby-1.9.2-p180#rails31beta/gems/actionpack-3.1.0.rc4/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (0.5ms)
My question is why are these not working? My hunch is that there is something about engines, namespacing and loading up gems that I am totally unaware of.
You need to require each gem within your engine in an initializer file, eg. lib/<your_engine_name>/engine.rb
Bit more of an explanation over here...
Rails Engine - Gems dependencies, how to load them into the application?

Resources