How to check for errors in Ruby as IntelliJ does? - ruby-on-rails

Recently I had a problem with a Rails application with the following code:
class MyBaseController < ApplicationController
def error(a, b)
# ...
end
end
class MyController < MyBaseController
def my_action
begin
another_method
rescue e
# The next line had a typo, it should
# have been "e" instead of "error" and
# hence it caused and unhandled exception
logger.error("the error was #{error}")
# ...
end
# ...
end
end
As you can see the logging statement will fail as it will try to call the error method from MyBaseController instead of getting the value of e.
This was an honest mistake but from what I see it could have been prevented: when I opened my application in IntelliJ with the Ruby plugin it marked the error with a red squiggle. Is not the first time I've seen one of these errors
My question is: Is there any Gem or tool (besides Intellij) to detect this kind of problems so I can add to my Rakefile and run it in my toolchain before my application gets deployed?

You could add debugger anywhere before or after any code you would like to trace.
Once you do the action from the browser, your running server in shell will pause the work and give you the ability to trace your code and test it.
I would recommend you to read more about debugging Rails applications.
Click here to read more about rails debugging

Related

Rails console executing a stale copy of the code

I have a strange issue with rails console. In fact, I am modifying the code of class function (static class).
class SomethingWorker
#queue = :resque_queue
def self.perform(method, *args)
send(method, *args)
end
def self.async(method, *args)
Resque.enqueue(SomethingWorker, method, *args)
end
def self.process_data
puts "hello"
end
end
Sometimes, when I change the function code. It contain to execute stale (old) code. Even restarting rails console doesn't solve the issue.
I verified that the files were saved and killed all the ruby processes.
PS. the self.process_data isn't queued and I am just calling it from rails console:
SomethingWorker.process_data.
I discard any issue with resque (not running) and redis (down)
spring stop
Solved the issue and rails console is running the latest code.

Executing a command every time the rails console starts

I have a setup command that I want executed every time I start the rails console -
MyClass.some_method()
I get tired of retyping it each time I fire up rails c - is there a way to have it automatically get run every time a new console is started?
Thanks!
We do this in order to ask for the tenant every time the console starts. It took a bit of investigation, but we got it working fairly elegantly. Note that this works with Rails 5.2 but it has worked mostly the same way since Rails 4.
Another thing to note is that this is written specifically because we wanted to be able to run the method once on start and then be able to run it again while using the console, say if we wanted to switch the tenant during a session.
The first step is to create a set of modules and classes in a lib file. Here is an example extracted from ours:
# lib/console_extension.rb
module ConsoleExtension
# This module provides methods that are only available in the console
module ConsoleHelpers
def do_someting
puts "doing something"
end
end
# This is a simple class that allows us access to the ConsoleHelpers before
# we get into the console
class ConsoleRunner
include ConsoleExtension::ConsoleHelpers
end
# This is specifically to patch into the startup behavior for the console.
#
# In the console_command.rb file, it does this right before start:
#
# if defined?(console::ExtendCommandBundle)
# console::ExtendCommandBundle.include(Rails::ConsoleMethods)
# end
#
# This is a little tricky. We're defining an included method on this module
# so that the Rails::ConsoleMethods module gets a self.included method.
#
# This causes the Rails::ConsoleMethods to run this code when it's included
# in the console::ExtendCommandBundle at the last step before the console
# starts, instead of during the earlier load_console stage.
module ConsoleMethods
def included(_klass)
ConsoleExtension::ConsoleRunner.new.do_someting
end
end
end
The next step is to add the following into your application.rb file:
module MyApp
class Application < Rails::Application
...
console do
require 'console_extension' # lib/console_extension.rb
Rails::ConsoleMethods.send :include, ConsoleExtension::ConsoleHelpers
Rails::ConsoleMethods.send :extend, ConsoleExtension::ConsoleMethods
end
end
end
Now, every time you run rails console, it will do something:
If you're just looking to run something once every time the console starts, this is more complicated than it needs to be. Instead, you can just use the console() method in MyApp::Application and it will run whatever code you want as part of the load_console step.
module MyApp
class Application < Rails::Application
...
console do
puts "do something"
end
end
end
One issue we had with this was that it runs the code before it prints out the environment, so if you're doing any printing or interaction it feels a bit weird:
You may not be as picky as we are though. Do whatever makes you and your team the happiest.
I dont know if its a good practice, but you can check if server is running on Console, like Aditya awnsered
if defined?(Rails::Console)
MyClass.some_method()
end
Note that this won't work during Rails initialization when running Spring like Swartz said.
I would try creating a Rake task for it and invoke it with after_initialize:
config.after_initialize do
IndividualProject::Application.load_tasks
Rake::Task[ 'foo:bar' ].invoke
end

rails resque and resque-send-later plugins causing "unitialized constant ClassName::Resque" error

i'm using the resque and resque-send-later PLUGINS (not gems) in my project.
I haven't put 'require' statements anywhere in the code at all (since they're plugins and so they must be included upon initialization).
the app is working perfectly locally, but on heroku, it shows an error
"const_missing: unitialized constant User::Resque"
my User model:
class User < ActiveRecord::Base
include Resque::Plugins::SendLater
def self.testingWorker1
# code to be run in the background
end
end
my User_controller: (where i'm calling the above method from)
class UserController < ApplicationController
def testingResqueWorker
User.send_later(:testingWorker1)
end
end
so I removed the line include Resque::Plugins::SendLater from the my model
it still works perfectly locally, but now on heroku it gives an error saying "method_missing: send_later"
my question is:
1. how do we 'include' or 'require' plugins in rails? are they automatically available to all controllers and models?
2. any ideas for how to fix the above errors?
Two thoughts
any reason why you aren't using the gems?
are you sure the plugins have been added to the git repository and therefore have been deployed to heroku?

How do I call the Rails console's reload! command programmatically?

When using the Rails console, there's a handy reload! function which reloads models and such. How do I call this from another part of my program?
Edit I've been asked for the use case a bit. It was that I had a long running JVM process running Jruby and a clojure repl. I could run RSpec tests from the REPL and could run arbitrary Ruby code from there too. But I couldn't figure out how to reload the Ruby classes so that I could edit the code and see it changed in the Ruby runtime. I no longer use this setup, principally because testing it was such a pain.
(I'm using Jruby and can access the Ruby VM programatically from my backend).
Have you tried touching restart.txt? Unfortunately, I have no experience with JRuby, but confirmed it works on my app.
FileUtils.touch('tmp/restart.txt')
You probably want to do something other than a Get request, and secure it behind some authentication.
I threw it in an Admin controller and added the route to config/routes.
# app/controllers/admin.rb
class AdminController < ApplicationController::Base
##time = Time.now # This value gets cached with the model.
def reboot
FileUtils.touch('tmp/restart.txt')
#restarted_time = ##time
end
end
# config/routes.rb
namespace :admin
get 'reboot'
end
# app/views/admin/reboot.html.erb
<%= #restarted_time.to_s %>

How to setup a generic error/exception handler callback in Ruby?

I’m working on this issue: Rails exception notifier in rake tasks
My question: Is there any function/plugin/gem/whatever to setup a generic error/exception handler callback as in PHP with set_error_handler and set_exception_handler?
I need a way to register a callback function used as a catchall outside any begin .. rescue .. end block. For example:
def my_handler *args
# exception processing code here
end
some_magic_method my_handler
raise "An Exception" # this will be handled by my_handler
In PHP this could be achieved with the set_exception_handler function. Is there any such function in Ruby/Rails?
If such feature exists I could solve my previous issue in a simple way.
A Rails-only solution would be fine for my needs.
I don't believe Ruby provides a way to do this, either with exceptions or with throw/catch. In general, doing something this way is a code smell and something to avoid. It makes control flow extremely hard to figure out. I would try to find some other way to approach the problem if at all possible.
If you want to do this in the HTTP Request-handling cycle you may use an around filter in your application controller:
class ApplicationController < ActionController::Base
around_filter do |controller, action|
action.call
rescue ExceptionXPTO
# ... handle the exception ...
end
end
I found a partial solution to my issue which works for the simple case I mentioned in the question. However this can not catch the exception, but it can be useful if someone needs only exception logging or reporting.
#!/usr/bin/env ruby
at_exit do
if $!
puts "Program ended with an exception #{$!.message}"
puts $!.backtrace.join("\n")
# or log the exception here
end
end
loop do
value = rand(3)
puts "Value is #{value}"
break if value == 2
raise "An Exception" if value == 0
end
puts "Program ended normally"

Resources