I'm using Rails 5.1. How do I get my initialization file (located at config/my_init.rb) to recognize when it is being run in the context of server startup versus when it is run in the context of a rake task? I thought the below would do it ...
puts "iniitializing ... #{(!Rails.env.test?) } defined; #{!defined?(::Rake)}"
if(!Rails.env.test?) && !defined?(::Rake)
And when I'm running a rake task, the " !defined?(::Rake)" correctly returns false ...
localhost:myproject davea$ rake db:seed
iniitializing ... true defined; false
but when I start up my server, that clause is still returning false
localhost:myproject davea$ rails s -b 127.0.0.1
=> Booting Puma
=> Rails 5.1.5 application starting in development
=> Run `rails server -h` for more startup options
iniitializing ... true defined; false
How can I make a distinction between teh two?
You can check of $0 or $PROGRAM_NAME which is an alias
if $PROGRAM_NAME.end_with?("rake")
puts "I am running under rake"
elsif $PROGRAM_NAME.end_with?("rails")
puts "I am running under rails"
end
Running it
$ rake db:seed
I am running under rake
$ rails s -b 127.0.0.1
=> Booting Puma
=> Rails 5.2.0 application starting in development
=> Run `rails server -h` for more startup options
I am running under rails
The short explanation is:
Rails core team decided to have consistency by enabling rails command to support everything that rake does.
By running rails --help, in Rails 5, you can to see all the commands that is supported by rails, a long list of options.
You can still choose to use rake to run those commands, as it you can do in Rails 4. This is because Rails community has introduced Rake Proxy instead of completely moving the command options from rake to rails.
Internally, by running rails routes, Rails checks if routes is something that rails natively supports or not. In this case routes is not natively supported by rails, so Rails delegates the execution to Rake via Rake Proxy.
A detailed explanation
EDIT
You can check if the extension is .rake using File.extname
# config/initializers/my_init.rb
Rails.application.config.after_initialize do
# tweak this as required...
if File.extname($0) =='.rake'
#Doing some stuff
end
end
$0 holds the current ruby program being run.
So this check should work for you:
File.basename($0) == 'rake'
$0 is a globally defined variable in Ruby - Ruby Doc for Global Variables
Contains the name of the script being executed. May be assignable.
After upgrading our team's rails application to 4.2, as the release note mentioned, the default ip rails server binds to is changed to localhost from 0.0.0.0.
We develop with Vagrant, and want the development server to be accessible directly from browser on the host machine.
Instead of typing rails s -b 0.0.0.0 every time from now on, I wonder if there's any more elegant solution, so that we can still use sth as simple as rails s to start the server. Perhaps:
a config file rails s reads where I can modify the default binding ip (without using -c)
port forward with vagrant (tried but failed, see problem encountered below)
a monkey patch to rack, that changes the default binding ip
The real goal behind this is that I want the upgrade to be smooth among our team, avoiding the glitch that people will have to constantly restarting their rails server due to the missing -b 0.0.0.0 part.
I tried vagrant port forwarding, but still get Connection Refused when I visit localhost:3000 on the host machine. The two configuration lines I tried was:
config.vm.network "forwarded_port", guest: 3000, host: 3000
config.vm.network "forwarded_port", guest: 3000, guest_ip: '127.0.0.1', host: 3000
Didn't find any relevant instructions in the official docs. Any help will be appreciated.
I'm having the same issue here and I found today a better solution. Just append this code to your config/boot.rb and it should work with vagrant.
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0', Port: 3000)
end
end
end
ps: Its based on: this answer
You can use foreman to run a Procfile with your custom commands:
# Procfile in Rails application root
web: bundle exec rails s -b 0.0.0.0
Now start your Rails application with:
foreman start
The good thing about foreman is that you can add other applications to the Procfile (like sidekiq, mailcatcher).
The bad thing about foreman is that you have to train your team to run foreman start instead of rails s.
Met the same problem. Found the blog Make Rails 4.2 server listens to all interfaces.
Add the following to config/boot.rb
require 'rails/commands/server'
module Rails
class Server
alias :default_options_bk :default_options
def default_options
default_options_bk.merge!(Host: '0.0.0.0')
end
end
end
For Rails 5.1.7 with Puma 3.12.1 the selected answer does not work, but I accomplished it by adding the following to my config/puma.rb file:
set_default_host '0.0.0.0' # Note: Must come BEFORE defining the port
port ENV.fetch('PORT') { 3000 }
I determined this by inspecting the dsl file. It uses instance_eval on that file, so there are probably other ways to do it, but this seemed the most reasonable to me.
If you put the default options on config/boot.rb then all command attributes for rake and rails fails (example: rake -T or rails g model user)! So, append this to bin/rails after line require_relative '../config/boot' and the code is executed only for the rails server command:
if ARGV.first == 's' || ARGV.first == 'server'
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0', Port: 3000)
end
end
end
end
The bin/rails file loks like this:
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
# Set default host and port to rails server
if ARGV.first == 's' || ARGV.first == 'server'
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0', Port: 3000)
end
end
end
end
require 'rails/commands'
If you use docker or another tool to manage the environment variables, you can set the HOST environment variable to the IP you need to bind.
Example:
HOST=0.0.0.0
Add it to docker.env file if you use Docker or .env if you use foreman.
Here's a simpler solution that I'm using. I already like/need dotenv and puma-heroku, so if using those doesn't work for you then this might not be for you.
/config/puma.rb
plugin :heroku
Gemfile
gem 'dotenv-rails', groups: [:development, :test]
.env
PORT=8080
Now I can start both dev and production with rails s.
For Rails 5 with Puma the selected answer does not work. You may get such error: cannot load such file -- rails/commands/server
For proper solution add following to config/puma.rb:
bind 'tcp://0.0.0.0:3000'
Switch to Puma and specify port in config/puma.rb, e.g.:
port ENV.fetch("PORT") { 3000 }
Apparently it will bind to 0.0.0.0 for the specified port: https://github.com/puma/puma/issues/896
I know that I can start a rails server on another port via -p option. But I'd like to setup another port per application as long as I start webrick.
Any ideas?
Regards
Felix
Append this to config/boot.rb:
require 'rails/commands/server'
module DefaultOptions
def default_options
super.merge!(Port: 3001)
end
end
Rails::Server.send(:prepend, DefaultOptions)
Note: ruby >= 2.0 required.
Quick solution: Append to Rakefile
task :server do
`bundle exec rails s -p 8080`
end
Then run rake server
Option 1:
You can launch WEBrick like so:
rails server -p 8080
Where 8080 is your port. If you like, you can throw this in a bash script for convenience.
Option 2:
You could install $ gem install foreman, and use foreman to start your production webserver (e.g. unicorn) as defined in your Procfile like so: $ foreman run web. If unicorn is your web server you can specify the port in your unicorn config file (as with most server choices). The benefit of this approach is not only can you set the port in the config, but you're using an environment which is closer to production.
If you put the default options on config/boot.rb then all command attributes for rake and rails fails (example: rake -T or rails g model user)! So, append this to bin/rails after line require_relative '../config/boot' and the code is executed only for the rails server command:
if ARGV.first == 's' || ARGV.first == 'server'
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0', Port: 3000)
end
end
end
end
The bin/rails file loks like this:
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot'
# Set default host and port to rails server
if ARGV.first == 's' || ARGV.first == 'server'
require 'rails/commands/server'
module Rails
class Server
def default_options
super.merge(Host: '0.0.0.0', Port: 3000)
end
end
end
end
require 'rails/commands'
For Rails 5.1:
# config/boot.rb
# ... existing code
require 'rails/command'
require 'rails/commands/server/server_command'
Rails::Command::ServerCommand.send(:remove_const, 'DEFAULT_PORT')
Rails::Command::ServerCommand.const_set('DEFAULT_PORT', 3333)
I'm using delayed_job to process some files and then create some activerecord objects with the results. The activerecord objects are being indexed with acts_as_ferret which is running as a drb server. When delayed_job processes the job, everything goes fine until it reaches the point when active record tries to talk to ferret via the drb server.
The stack trace is here: http://pastie.org/693588
Calling the same process via the console or without delayed_job is successful. My guess is that for some reason, possibly permissions related, delayed_job doesn't have the ability to talk to the drb server, but not sure. Any ideas what's going on?
Wow - I posted the same question on Nov 5th. So, I must be on the right track at least! :)
DelayedJob with acts_as_ferret in production mode
To help with giving some more context to the question:- there is no special code I had written. The models all have
acts_as_ferret :remote => true
The ferret_server initializer is as usual:
$ cat config/ferret_server.yml
# configuration for the acts_as_ferret DRb server
# host: where to reach the DRb server (used by application processes to contact the server)
# port: which port the server should listen on
# pid_file: location of the server's pid file (relative to RAILS_ROOT)
# log_file: log file (default: RAILS_ROOT/log/ferret_server.log
# log_level: log level for the server's logger
production:
host: localhost
port: 9010
pid_file: log/ferret.pid
log_file: log/ferret_server.log
log_level: warn
I am able to run other delayed_job which do NOT modify the records but gather data - so delayed_job works. This is the delayed_job spawner I have:
$ cat script/delayed_job
#!/usr/bin/env ruby
ENV['RAILS_ENV'] = 'production'
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'boot'))
require 'delayed/command'
Delayed::Command.new(ARGV).daemonize
Agreed with the commenter, post some code! :-)
However, in the absense of code, it's too hard to figure out what went wrong. And how or why is DJ talking to the drb server, which is used for user searches? Is it restarting it? AAF takes care of indexing on each request, so if you are processing some job in the background, how does that effect the index in a database?
I'm getting this error when I'm trying to connect to a mysql database. The problem is that the application works for weeks, and then randomly I get this message. When I get this error message the application is not able to reconnect to the database until I restart it.
I'm using a configuration file to connect to the database, and the adapter is specified...the database configuration is not generated at runtime.
Do you have any idea on what is going on?
when I tried to run a command line script (let's say 'my_script' here), the same error happened. The reasons were:
There is only production environment there.
I missed to set RAILS_ENV for the command line.
So, the following is the solution in my case:
$ RAILS_ENV=production my_script
I just had this problem, and it was caused by a typo in my configration.yml.
I originally had this:
production:
adapter:mysql
When I meant to have this:
production:
adapter: mysql
That one little space between adapter: and mysql makes the difference.
Another possible cause:
In Rails 3.2.x, establish_connection has a default argument set from the environment:
From connection_specification.rb:
def self.establish_connection(spec = ENV["DATABASE_URL"])
resolver = ConnectionSpecification::Resolver.new spec, configurations
spec = resolver.spec
The way ConnectionSpecification::Resolver works depends on ENV['DATABASE_URL'] giving a nil if not set. (Normally, it would be something like 'postgres://...').
So, if you happen to have misconfigured DATABASE_URL such that ENV['DATABASE_URL'] == '', that will give you database configuration does not specify adapter.
I had this error when I mistakenly started rails server with
sudo rails s -e "Production" -p 80
and I should have started rails with
sudo rails s -e "production" -p 80
I found another thing that can cause this problem: "mixing in" another YAML node using & and *.
I was originally doing something like the following to facilitate local, per-develop, Git-ignored config files:
http://blog.lathi.net/articles/2006/03/02/config-database-yml-goodness-for-teams
But, after some debugging, I came to find out that establish_connection was for some reason being called with only the mixed-in key-value pairs and not the main ones. I.e. adapter, host, and database were not being passed in. I have no idea why, and this used to work for me.
Anyhow, instead of mixing in another YAML node, I now put the entire development and test hashes in the local config file, and establish_connection is once again being called correctly.
For me, this command resolved the issue.
rake db:migrate RAILS_ENV=production
I've found a couple of clues that this might be related to older library (ActiveRecord) or gem versions. For example, problems with fixtures even though rest of app seems okay (after an upgrade) or this trac ticket, which "stops gems from requiring an adapter from an old Active Record gem". Both of these are old, though, but it might be worth making sure your gems are up to date (if possible).
Are you using the native rails MySQL adapter by any chance? This is now deprecated under rails, but it's conceivable it's still limping along.
I've taken a very quick look at connection_specification.rb, too, which is where this error is coming from, and my best guess is that a reconnect is failing... but why (since it was obviously okay when you first started the app)? Are you doing something wild like calling ActiveRecord::Base.establish_connection in your application controller (or elsewhere)?
Or perhaps something like: script runner is called from cron in the dead of night when the connection has dropped. Unfortunately, the runner is invoked with an incorrect RAILS_ENV. Thus the wrong stanza is read from database.yml, and that stanza contains an invalid adapter:?
I got the same error, by typing in the following command:
db:migrate RAILS_ENV=product
Should've been:
db:migrate RAILS_ENV=production
If you get this error while deploying with Capistrano. Make sure you are setting the correct RAILS_ENV via
set :rails_env, 'production'
For example I was not explicitly setting the Rails environment in for the Capistrano staging deployment configuration. And thus Capistrano used 'staging' as the RAILS_ENV, resulting in the above error. Setting it to production like above in the staging.rb file solved the issue.
Do remember that RAILS_ENV=staging will look for a staging specification in your database.yml just as setting RAILS_ENV=production will look for a production specification in database.yml file.
Provide database configs, as shown below, for every rails environment you target using, for example
bundle exec cap staging deploy
production:
adapter: mysql2
encoding: utf8
database: rails
username: rails
password: pass
host: 127.0.0.1
port: 3306
pool: 5
timeout: 5000
staging:
adapter: mysql2
encoding: utf8
database: rails
username: rails
password: pass
host: 127.0.0.1
port: 3306
pool: 5
timeout: 5000
Remember to use the C-Based ruby gem for mysql. The ruby-based is unstable for production.
Try installing the gem
gem install mysql
Remember to copy libmySQL.dll into the ruby bin directory.
I had this error with another problem; I had specified 'development' twice, and 'test' not at all.
There are alot of bad tutorials out there on the internet that show yaml files like so:
development:
encoding: utf
database: dbname
...etc
YAML files are case sensitive and require TWO SPACES for the inner contents of each given db-type attribute. Like so:
development:
encoding: utf
database: dbname
...etc
UPDATE: I got this error again today. My VPS server had installed Rails 3.2.8 when my app was running Rails 3.2.6.
Definitely check your Gemfile and your database.yml file (of course). The problem here is clearly stated---Rails is not communicating with your database specifically due to an adapter (aka gem)
We had this issue with one of our older apps. Someone had created a boutique named environment, that even if RAIL_ENV was set to production, it was looking for a database configuration called legacy_<RAIL_ENV>, so I had to make a database environment called legacy_production for this app to work.
If you are maintain someone else's app, I would look for a copy of this app's database.yml that is working, perhaps it has some oddly named configuration. You can search your codebase for establish_connection to see if it is defining some strange variant.
I met this problem due to the 'multiple database support issue'. In my app/model folder, there is a file defined a redundant database connection:
class CacheCleanerActiveRecord < ActiveRecord::Base
establish_connection "cache_cleaner_#{Rails.env}"
self.abstract_class = true
end
but this database is not found in my database.yml ( because it's not used at all ).
so the solution is quit simple: remove this file and everything is fine !
You may have an error like:
RAILS_ENV= test
A space after the equals sign is not allowed, change it to:
RAILS_ENV=test
This happens to me, finally I found that RAILS_ENV is case sensitive, in my enviroment I set
RAILS_ENV=DEVELOPMENT , which is wrong, the value of RAILS_ENV must be lowercase.
$ RAILS_ENV=DEVELOPMENT rails server webrick
=> Booting WEBrick
=> Rails 4.2.5 application starting in DEVELOPMENT on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:
* development - set it to false
* test - set it to false (unless you use a tool that preloads your test environment)
* production - set it to true
Exiting
/home/fangxing/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/connection_adapters/connection_specification.rb:248:in `resolve_symbol_c
onnection': 'DEVELOPMENT' database is not configured. Available: ["default", "development", "test", "production"] (ActiveRecord::AdapterNotSpecified)
from /home/fangxing/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/connection_adapters/connection_specification.rb:211:in `res
olve_connection'
$ RAILS_ENV=development rails server webrick
RubyDep: WARNING: Your Ruby is outdated/buggy. (To disable warnings, set RUBY_DEP_GEM_SILENCE_WARNINGS=1)
RubyDep: WARNING: Your Ruby is: 2.3.0 (buggy). Recommendation: install 2.3.1.
=> Booting WEBrick
=> Rails 4.2.5 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2016-07-20 16:41:09] INFO WEBrick 1.3.1
[2016-07-20 16:41:09] INFO ruby 2.3.0 (2015-12-25) [x86_64-linux]
[2016-07-20 16:41:09] INFO WEBrick::HTTPServer#start: pid=19881 port=3000
rails -e "production" is okay
only rails -e production returns error
database configuration does not specify adapter (ActiveRecord::AdapterNotSpecified)
call rake assets:precompile:all
This is probably not the most likely issue to cause this error, but here it is just in case.
My problem was that I was building the database settings in a Hash using symbols as keys and then serializing it with #to_yaml to database.yaml. ActiveRecord expects the environment names to be Strings, not Symbols, so it wasn't picking up the database settings when reading the generated file. I fixed it by using string keys in the hash.
For Rails4, commenting the line fetch(:default_env).merge!(rails_env: 'production') in production.rb and adding set :rails_env, :production fixed it.
You need to specify the environment when running the server or command as your database.yml file may have only production adapter while simply runnig rake db:migrate for example will take environment variable as development.
Just for the sake of completeness, I just got this error because I natively created a parametrised Rails runner script that takes an email address, and named the command line option -e -- which of course is the one the Rails runner uses for the environment. So it was trying to find an environment configuration that matched the email address!
Luckily, just before the ActiveRecord error mentioned in the title, it gave me an error message that helped me twig what the problem actually was:
You did not specify how you would like Rails to report deprecation notices for your test#example.com environment, please set config.active_support.deprecation to :log, :notify or :stderr at config/environments/test#example.com.rb
Check the spelling of adapter I had adaptor and got this error.
I had this error message when upgrading from Rails 4 to 5. I was calling
establish_connection "myconnection"
where "myconnection" is a valid key in my database.yml. However, passing this parameter as a string is apparently no longer supported. Using a symbol instead got rid of the problem.
I got this from copying and pasting sudo rails server webrick –e production -d from documentation into the CLI.
I'll shut the door on my way out 😔