How to determine if Rails is running from CLI, console or as server?
Asked Answered
Y

8

43

I have a middleware for announcing my application on the local network app using Bonjour, but it's also announcing the service when Rails is invoked from rake or through the console.

I'd like to exclude these cases, and only use the Bonjour middleware when Rails is running as a server.

The middleware configuration accepts a proc to exclude middlewares under certain conditions using a proc:

config.middleware.insert_before ActionDispatch::Static, Rack::SSL, :exclude => proc { |env| 
  env['HTTPS'] != 'on' 
}

But how do I determine if Rails was invoked from the CLI, console or as a server?

Yonyona answered 22/11, 2012 at 6:1 Comment(0)
Y
52

Peeking at the Rails module using pry reveals that console invocations can be detected like this:

Rails.const_defined? 'Console'

And server invocations like this:

Rails.const_defined? 'Server'
Yonyona answered 23/11, 2012 at 9:15 Comment(6)
Interestingly, this only works if the commands "rails s" or "rails c" are invoked. If you're running a server via a different command (e.g., "unicorn_rails"), these constants never get defined. Rails::Server looks like it's defined as part of the command-parsing process, even though it inherits from ::Rack::Server.Foamy
This is not working for me with Rails 4 even with rails c. I am getting Server and Console defined in the console.Lorenzetti
@MarkTabler @DanHerman try this if starting Rails with unicorn? (Rails.const_defined? 'Server') || ($0.include? 'unicorn')Aerography
Rails::Server is still defined in generator scripts like rails g migration.Gourley
Server is not definded when use passengerInternationalist
Also doesn't work when used in an initializer.Kangaroo
G
21

Summary of the environment for each command.

I found the existing answers to be either incomplete, redundant or not exhaustive. So here is a table format of each command and what the resulting environment looks like.

Rails 7.0

| Command                            |  Rails.const_defined?( "Console" )  |  Rails.const_defined?( "Server" ) |               ARGV              | Rake.application.top_level_tasks |
|------------------------------------|-------------------------------------|-----------------------------------|---------------------------------|----------------------------------|
| `rake db:migrate:status`           |  false                              |  false                            |  ["db:migrate:status"]          | ["db:migrate:status"] 
| `rails console`                    |  true                               |  false                            |  []                             | []
| `rails server`                     |  false                              |  true                             |  []                             | []
| `rails g migration new_migration`  |  false                              |  false                            |  ["migration", "new_migration"] | []
| `rails r "puts 'Hi'"`              |  false                              |  false                            |  ["puts 'hi'"]                  | []

Rails 4.2

| Command                            |  Rails.const_defined?( "Console" )  |  Rails.const_defined?( "Server" )  |               ARGV              |
|------------------------------------|-------------------------------------|------------------------------------|---------------------------------|
| `rake db:migrate:status`           |  false                              |  true                              |  ["db:migrate:status"]          |
| `rails console`                    |  true                               |  true                              |  []                             |
| `rails server`                     |  false                              |  true                              |  []                             |
| `rails g migration new_migration`  |  false                              |  true                              |  ["migration", "new_migration"] |
| `rails r "puts 'Hi'"`              |  false                              |  true                              |  []                             |

You can see that just checking for "Server" being defined as a Rails constant will not catch generators, like rails g migration. You need to check the ARGV to do that.

I hope this helps. I only had immediate access to Rails 4.2 but feel free to add sections for other Rails versions, as well as add any additional commands that need "catching".

NOTE: I found in Rails 7 (and maybe in some other version between 4.2 and 7) this changed quite dramatically and a few of our checks were failing because of it, so I updated the answer for Rails 7.0 and had to include a new command Rake.application.top_level_tasks to make things work on our end again. Hope it helps.

Gourley answered 28/12, 2018 at 19:44 Comment(3)
In Rails 5.2 Rails.const_defined?( "Server" ) is true only when running rails server. When the server is started not with the Rails command, an additional check for the program name will help: Rails.const_defined?(:Server) || $PROGRAM_NAME.include?('puma')Staid
Actually, with Puma it's better to check additionally for Puma::Server: Rails.const_defined?(:Server) || ($PROGRAM_NAME.include?('puma') && Puma.const_defined?(:Server))Staid
what about rails test ?Jameejamel
S
16

Super helpful. Thanks @crishoj.

I wanted to examine the Console object more closely for another problem I am working on and found out that the Console constant can be reached with Rails::Console, so another option for checking would be to use:

defined? Rails::Console
defined? Rails::Server
Simmer answered 4/12, 2014 at 17:57 Comment(1)
Rails::Server is still defined in generator scripts like rails g migration. Also, Rails::Console is defined when running rails s.Gourley
B
12

Using Rails 5 with or without an app-server like Puma/Passenger, here are three ways to determine how your app is running:

# We are running in a CLI console
defined?(Rails::Console)

# We are running as a Rack application (including Rails)
caller.any?{|l| l =~ %r{/config.ru/}}

# We are running as a CLI console
caller.any?{|l| l =~ %r{/lib/rake/task.rb:\d+:in `execute'}}
Baalbek answered 1/4, 2018 at 12:59 Comment(3)
caller.any?{|l| l =~ %r{/config.ru/}} -- Shouldn't the trailing slash be removed? A fixed line is:caller.any? {|l| l =~ %r"/config\.ru" }Radial
A slightly cleaner version: caller.grep(%r{/config.ru}).any?Subirrigate
The second line doesn't work in initializers.Presidency
P
3

'Server' isn't defined when Rails 5 runs under Passenger.

The best solution I've found is a variant of this answer:

if %w(rails rake).include?(File.basename($0))
   <console or runner>
else
   <server>       
end
Piers answered 6/3, 2017 at 6:48 Comment(1)
Rails::Server is still defined in generator scripts like rails g migration. Also, Rails::Console is defined when running rails s.Gourley
S
1

In our project I had to detect console mode in boot.rb, for that I used:

in_console = (ARGV & ['c', 'console']).any?

Not a fool-proof solution, but good enough for our use case.

Spite answered 3/12, 2018 at 3:59 Comment(1)
Thanks for introducing me to ARGV. It was the only way to detect when rails g was called and not rails s.Gourley
A
0

Here is my version that detects sidekiq or running server on passenger/puma. Given the previous answers, it is not 100% sure that it would work in all cases (I haven't tested what it's like when running a rails runner or a rake task in general)

@running_app = begin
  if defined?(Rails::Console)
    'Console'
  elsif Sidekiq.server?
    'Worker'
  elsif defined?(::PhusionPassenger) || defined?(Rails::Server) 
    'Server'
  else
    nil # unknown
  end
end
Alter answered 27/10, 2021 at 8:20 Comment(0)
D
-7

For Padrino:

Console check:

if Padrino::constants.include? :Cli
    #your code
end

Server Check:

if !Padrino::constants.include? :Cli
    #your code
end
Drier answered 18/11, 2018 at 18:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.