I recently upgraded my application from Rails version 2.1.2 to version 2.2.2. It was tested in on development and on my staging system. When I moved to production it fails to load all the way through the environment.rb file. (Why, oh why, is it always on production!?!)
Below is my environment.rb file
# Be sure to restart your web server when you modify this file.
# Uncomment below to force Rails into production mode when
# you don't control web/app server and can't set it the proper way
# ENV['RAILS_ENV'] ||= 'production'
# Specifies gem version of Rails to use when vendor/rails is not present
#RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
RAILS_GEM_VERSION = '2.2.2' unless defined? RAILS_GEM_VERSION
puts "loading rails..."
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')
puts "require boot file"
require 'socket'
puts "require socket"
Rails::Initializer.run do |config|
puts "inside config section"
# Settings in config/environments/* take precedence over those specified here
# Skip frameworks you're not going to use (only works if using vendor/rails)
# config.frameworks -= [ :action_web_service, :action_mailer ]
# Only load the plugins named here, by default all plugins in vendor/plugins are loaded
# config.plugins = %W( exception_notification ssl_requirement )
# Add additional load paths for your own custom dirs
# config.load_paths += %W( #{RAILS_ROOT}/extras )
# Force all environments to use the same logger level
# (by default production uses :info, the others :debug)
# config.log_level = :debug
# Use the database for sessions instead of the file system
# (create the session table with 'rake db:sessions:create')
config.action_controller.session_store = :active_record_store
puts "setting session store type"
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
#config.gem "will_paginate", :source => "http://gems.rubyforge.org"
# Action Mailer configuration - from page 567-568 of the Agile Development book
# config.action_mailer.delivery_method = :smtp
#
config.action_mailer.smtp_settings = {
:address => "smtp.redacted.com",
:port => "25",
:domain => "redacted.com"
}
puts "setting smtp settings"
# See Rails::Configuration for more options
end
puts "outside config section ... before inflectors"
# Add new inflection rules using the following format
# (all these examples are active by default):
ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
inflect.uncountable %w( sid fcc )
end
puts "after inflectors"
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Mime::Type.register "application/x-mobile", :mobile
# Include your application configuration below
require 'will_paginate'
puts "require will paginate"
# insert at top of ActiveRecord::Base.rb
# Indicates whether field names should be lowercased for legacy databse fields.
# If true, the field Product_Name will be +product_name+. If false, it will remain +Product_Name+.
# This is false, by default.
#cattr_accessor :downcase_legacy_field_names, :instance_writer => false
###downcase_legacy_field_names = false
# insert into column_methods_hash of ActiveRecord::Base.rb
# attr_final = downcase_legacy_field_names ? attr.to_s.downcase : attr
puts "here comes the monkey patch"
module ActiveRecord
class Base
# Indicates whether field names should be lowercased for legacy databse fields.
# If true, the field Product_Name will be +product_name+. If false, it will remain +Product_Name+.
# This is false, by default.
cattr_accessor :downcase_legacy_field_names, :instance_writer => false
##downcase_legacy_field_names = false
end
end
puts "monkey patch part 2"
# set all accessor methods to lowercase (underscore)
# add set_columns_to_lower to each model that needs it
class << ActiveRecord::Base
# Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
# and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
# is available.
def column_methods_hash #:nodoc:
#dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
attr_final = downcase_legacy_field_names ? attr.to_s.downcase : attr
attr_name = attr_final
methods[attr_final.to_sym] = attr_name
methods["#{attr_final}=".to_sym] = attr_name
methods["#{attr_final}?".to_sym] = attr_name
methods["#{attr_final}_before_type_cast".to_sym] = attr_name
methods
end
end
# adapted from: http://wiki.rubyonrails.org/rails/pages/HowToUseLegacySchemas
def downcase_legacy_field_methods
column_names.each do |name|
next if name == primary_key
a = name.to_s.underscore
define_method(a.to_sym) do
read_attribute(name)
end
define_method("#{a}=".to_sym) do |value|
write_attribute(name, value)
end
define_method("#{a}?".to_sym) do
self.send("#{name}?".to_sym)
end
end
end
end
puts "monkey patch part 3"
ActiveRecord::Base.downcase_legacy_field_names = true
puts "monkey patch part 4"
module ActiveSupport
module Inflector
def textize(str)
str.to_s.gsub(/'/, '').downcase
#gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
#gsub(/([a-z\d])([A-Z])/,'\1_\2').
#tr("-", "_").
#downcase
end
end
end
puts "monkey patch part 5"
module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module String #:nodoc:
module Inflections
def textize
Inflector.textize(self)
end
end
end
end
end
###################################################################
### Code moved to the specific environment files.
### This way the schema gets reloaded on a deploy
###################################################################
## Establishes connections for the root classes of the various databases that
## must be connected to for SUI.
puts "load the database if we are in test mode"
if RAILS_ENV == "test" then
puts "if I see this and I'm not loading test, we have a problem"
Ird.load_database
end
puts "setting up the execption notifier"
ExceptionNotifier.exception_recipients = %w(me#redacted.com)
if RAILS_ENV == "Production"
ExceptionNotifier.sender_address = %("SUI Service" <service#redacted.com>)
ExceptionNotifier.email_prefix = "[SUI ERROR] "
else
ExceptionNotifier.sender_address = %("SUI #{RAILS_ENV.to_s.humanize} Service" <service#redacted.com>)
ExceptionNotifier.email_prefix = "[#{RAILS_ENV.to_s.humanize}: SUI ERROR] "
end
puts "local_ip function"
def local_ip
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
UDPSocket.open do |s|
s.connect '64.233.187.99', 1
s.addr.last
end
ensure
Socket.do_not_reverse_lookup = orig
end
puts "I am located at:#{local_ip}:"
puts "environment.rb is loaded"
If I set the rails gem to be used to version 2.1.2 everything loads and all the puts statements print as expected. When I change the gem version to 2.2.2 the last statement that I see printed is "setting smtp settings".
When I move the Rails::Initializer do |config| section to the bottom it fails in ways worse than where it is right now.
The ruby version that is loaded on the system is Ruby 1.8.6 patchlevel 111. It is running on RHEL5-64bit.
I'm stumped. Ideas? Suggestions?
Did you run rake rails:update?
Also, you might want to move most of the code into config/initializers/[anything].rb, allthough I hardly think that itself will solve your problems.
Related
I deployed discourse applicattion in rails on heroku.
deployed succesfully
Getting error when i do heroku run rake db:migrate db:seed_fu
alse getting an other error on heroku run rake db:create
config/discourse_defaults.conf
# message bus redis server address
message_bus_redis_host = redis://h:p27179a7ac96b0d215c36e5d5a4bda0c0565e1e6d96cdf043b9f5481d68dd1541#ec2-3-219-59-76.compute-1.amazonaws.com:27969
# message bus redis server port
message_bus_redis_port = 27969
# message bus redis slave server address
message_bus_redis_slave_host =
# message bus redis slave server port
message_bus_redis_slave_port = 27969
config/intializer/001-redis.rb
if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS']
puts "Flushing redis (development mode)"
$redis.flushall
end
application.rb
# frozen_string_literal: true
# note, we require 2.5.2 and up cause 2.5.1 had some mail bugs we no longer
# monkey patch, so this avoids people booting with this problem version
begin
if !RUBY_VERSION.match?(/^2\.(([67])|(5\.[2-9]))/)
STDERR.puts "Discourse requires Ruby 2.5.2 or up"
exit 1
end
rescue
# no String#match?
STDERR.puts "Discourse requires Ruby 2.5.2 or up"
exit 1
end
require File.expand_path('../boot', __FILE__)
require 'active_record/railtie'
require 'action_controller/railtie'
require 'action_view/railtie'
require 'action_mailer/railtie'
require 'sprockets/railtie'
# Plugin related stuff
require_relative '../lib/discourse_event'
require_relative '../lib/discourse_plugin'
require_relative '../lib/discourse_plugin_registry'
require_relative '../lib/plugin_gem'
# Global config
require_relative '../app/models/global_setting'
GlobalSetting.configure!
unless Rails.env.test? && ENV['LOAD_PLUGINS'] != "1"
require_relative '../lib/custom_setting_providers'
end
GlobalSetting.load_defaults
if ENV['SKIP_DB_AND_REDIS'] == '1'
GlobalSetting.skip_db = true
GlobalSetting.skip_redis = true
end
require 'pry-rails' if Rails.env.development?
if defined?(Bundler)
bundler_groups = [:default]
if !Rails.env.production?
bundler_groups = bundler_groups.concat(Rails.groups(
assets: %w(development test profile)
))
end
Bundler.require(*bundler_groups)
end
module Discourse
class Application < Rails::Application
def config.database_configuration
if Rails.env.production?
GlobalSetting.database_config
else
super
end
end
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# this pattern is somewhat odd but the reloader gets very
# confused here if we load the deps without `lib` it thinks
# discourse.rb is under the discourse folder incorrectly
require_dependency 'lib/discourse'
require_dependency 'lib/es6_module_transpiler/rails'
require_dependency 'lib/js_locale_helper'
# tiny file needed by site settings
require_dependency 'lib/highlight_js/highlight_js'
# mocha hates us, active_support/testing/mochaing.rb line 2 is requiring the wrong
# require, patched in source, on upgrade remove this
if Rails.env.test? || Rails.env.development?
require "mocha/version"
require "mocha/deprecation"
if Mocha::VERSION == "0.13.3" && Rails::VERSION::STRING == "3.2.12"
Mocha::Deprecation.mode = :disabled
end
end
# Disable so this is only run manually
# we may want to change this later on
# issue is image_optim crashes on missing dependencies
config.assets.image_optim = false
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir["#{config.root}/app/serializers"]
config.autoload_paths += Dir["#{config.root}/lib/validators/"]
config.autoload_paths += Dir["#{config.root}/app"]
if Rails.env.development? && !Sidekiq.server?
config.autoload_paths += Dir["#{config.root}/lib"]
end
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
config.assets.paths += %W(#{config.root}/config/locales #{config.root}/public/javascripts)
if Rails.env == "development" || Rails.env == "test"
config.assets.paths << "#{config.root}/test/javascripts"
config.assets.paths << "#{config.root}/test/stylesheets"
config.assets.paths << "#{config.root}/node_modules"
end
# Allows us to skip minifincation on some files
config.assets.skip_minification = []
# explicitly precompile any images in plugins ( /assets/images ) path
config.assets.precompile += [lambda do |filename, path|
path =~ /assets\/images/ && !%w(.js .css).include?(File.extname(filename))
end]
config.assets.precompile += %w{
vendor.js
admin.js
preload-store.js
browser-update.js
break_string.js
ember_jquery.js
pretty-text-bundle.js
wizard-application.js
wizard-vendor.js
plugin.js
plugin-third-party.js
markdown-it-bundle.js
service-worker.js
google-tag-manager.js
google-universal-analytics.js
preload-application-data.js
print-page.js
omniauth-complete.js
activate-account.js
auto-redirect.js
wizard-start.js
onpopstate-handler.js
embed-application.js
}
# Precompile all available locales
unless GlobalSetting.try(:omit_base_locales)
Dir.glob("#{config.root}/app/assets/javascripts/locales/*.js.erb").each do |file|
config.assets.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}"
end
end
# out of the box sprockets 3 grabs loose files that are hanging in assets,
# the exclusion list does not include hbs so you double compile all this stuff
initializer :fix_sprockets_loose_file_searcher, after: :set_default_precompile do |app|
app.config.assets.precompile.delete(Sprockets::Railtie::LOOSE_APP_ASSETS)
start_path = ::Rails.root.join("app/assets").to_s
exclude = ['.es6', '.hbs', '.js', '.css', '']
app.config.assets.precompile << lambda do |logical_path, filename|
filename.start_with?(start_path) &&
!exclude.include?(File.extname(logical_path))
end
end
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = 'UTC'
# auto-load locales in plugins
# NOTE: we load both client & server locales since some might be used by PrettyText
config.i18n.load_path += Dir["#{Rails.root}/plugins/*/config/locales/*.yml"]
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = 'utf-8'
config.assets.initialize_on_precompile = false
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [
:password,
:pop3_polling_password,
:api_key,
:s3_secret_access_key,
:twitter_consumer_secret,
:facebook_app_secret,
:github_client_secret,
:second_factor_token,
]
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.2.4'
# see: http://stackoverflow.com/questions/11894180/how-does-one-correctly-add-custom-sql-dml-in-migrations/11894420#11894420
config.active_record.schema_format = :sql
# per https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
config.pbkdf2_iterations = 64000
config.pbkdf2_algorithm = "sha256"
# rack lock is nothing but trouble, get rid of it
# for some reason still seeing it in Rails 4
config.middleware.delete Rack::Lock
# wrong place in middleware stack AND request tracker handles it
config.middleware.delete Rack::Runtime
# ETags are pointless, we are dynamically compressing
# so nginx strips etags, may revisit when mainline nginx
# supports etags (post 1.7)
config.middleware.delete Rack::ETag
unless Rails.env.development?
require 'middleware/enforce_hostname'
config.middleware.insert_after Rack::MethodOverride, Middleware::EnforceHostname
end
require 'content_security_policy/middleware'
config.middleware.swap ActionDispatch::ContentSecurityPolicy::Middleware, ContentSecurityPolicy::Middleware
require 'middleware/discourse_public_exceptions'
config.exceptions_app = Middleware::DiscoursePublicExceptions.new(Rails.public_path)
# Our templates shouldn't start with 'discourse/templates'
config.handlebars.templates_root = 'discourse/templates'
config.handlebars.raw_template_namespace = "Discourse.RAW_TEMPLATES"
require 'discourse_redis'
require 'logster/redis_store'
require 'freedom_patches/redis'
# Use redis for our cache
config.cache_store = DiscourseRedis.new_redis_store
$redis = DiscourseRedis.new
Logster.store = Logster::RedisStore.new(DiscourseRedis.new)
# we configure rack cache on demand in an initializer
# our setup does not use rack cache and instead defers to nginx
config.action_dispatch.rack_cache = nil
# ember stuff only used for asset precompliation, production variant plays up
config.ember.variant = :development
config.ember.ember_location = "#{Rails.root}/vendor/assets/javascripts/production/ember.js"
config.ember.handlebars_location = "#{Rails.root}/vendor/assets/javascripts/handlebars.js"
require 'auth'
if GlobalSetting.relative_url_root.present?
config.relative_url_root = GlobalSetting.relative_url_root
end
if Rails.env == "test"
if ENV['LOAD_PLUGINS'] == "1"
Discourse.activate_plugins!
end
else
Discourse.activate_plugins!
end
require_dependency 'stylesheet/manager'
require_dependency 'svg_sprite/svg_sprite'
config.after_initialize do
# require common dependencies that are often required by plugins
# in the past observers would load them as side-effects
# correct behavior is for plugins to require stuff they need,
# however it would be a risky and breaking change not to require here
require_dependency 'category'
require_dependency 'post'
require_dependency 'topic'
require_dependency 'user'
require_dependency 'post_action'
require_dependency 'post_revision'
require_dependency 'notification'
require_dependency 'topic_user'
require_dependency 'topic_view'
require_dependency 'topic_list'
require_dependency 'group'
require_dependency 'user_field'
require_dependency 'post_action_type'
# Ensure that Discourse event triggers for web hooks are loaded
require_dependency 'web_hook'
# So open id logs somewhere sane
OpenID::Util.logger = Rails.logger
# Load plugins
Discourse.plugins.each(&:notify_after_initialize)
# we got to clear the pool in case plugins connect
ActiveRecord::Base.connection_handler.clear_active_connections!
# This nasty hack is required for not precompiling QUnit assets
# in test mode. see: https://github.com/rails/sprockets-rails/issues/299#issuecomment-167701012
ActiveSupport.on_load(:action_view) do
default_checker = ActionView::Base.precompiled_asset_checker
ActionView::Base.precompiled_asset_checker = -> logical_path do
default_checker[logical_path] ||
%w{qunit.js qunit.css test_helper.css test_helper.js wizard/test/test_helper.js}.include?(logical_path)
end
end
end
if ENV['RBTRACE'] == "1"
require 'rbtrace'
end
config.generators do |g|
g.test_framework :rspec, fixture: false
end
# we have a monkey_patch we need to require early... prior to connection
# init
require 'freedom_patches/reaper'
end
end
app/model/global_settingg.rb
# frozen_string_literal: true
class GlobalSetting
def self.register(key, default)
define_singleton_method(key) do
provider.lookup(key, default)
end
end
VALID_SECRET_KEY ||= /^[0-9a-f]{128}$/
# this is named SECRET_TOKEN as opposed to SECRET_KEY_BASE
# for legacy reasons
REDIS_SECRET_KEY ||= 'SECRET_TOKEN'
REDIS_VALIDATE_SECONDS ||= 30
# In Rails secret_key_base is used to encrypt the cookie store
# the cookie store contains session data
# Discourse also uses this secret key to digest user auth tokens
# This method will
# - use existing token if already set in ENV or discourse.conf
# - generate a token on the fly if needed and cache in redis
# - enforce rules about token format falling back to redis if needed
def self.safe_secret_key_base
if #safe_secret_key_base && #token_in_redis && (#token_last_validated + REDIS_VALIDATE_SECONDS) < Time.now
#token_last_validated = Time.now
token = $redis.without_namespace.get(REDIS_SECRET_KEY)
if token.nil?
$redis.without_namespace.set(REDIS_SECRET_KEY, #safe_secret_key_base)
end
end
#safe_secret_key_base ||= begin
token = secret_key_base
if token.blank? || token !~ VALID_SECRET_KEY
#token_in_redis = true
#token_last_validated = Time.now
token = $redis.without_namespace.get(REDIS_SECRET_KEY)
unless token && token =~ VALID_SECRET_KEY
token = SecureRandom.hex(64)
$redis.without_namespace.set(REDIS_SECRET_KEY, token)
end
end
if !secret_key_base.blank? && token != secret_key_base
STDERR.puts "WARNING: DISCOURSE_SECRET_KEY_BASE is invalid, it was re-generated"
end
token
end
rescue Redis::CommandError => e
#safe_secret_key_base = SecureRandom.hex(64) if e.message =~ /READONLY/
end
def self.load_defaults
default_provider = FileProvider.from(File.expand_path('../../../config/discourse_defaults.conf', __FILE__))
default_provider.keys.concat(#provider.keys).uniq.each do |key|
default = default_provider.lookup(key, nil)
instance_variable_set("##{key}_cache", nil)
define_singleton_method(key) do
val = instance_variable_get("##{key}_cache")
unless val.nil?
val == :missing ? nil : val
else
val = provider.lookup(key, default)
if val.nil?
val = :missing
end
instance_variable_set("##{key}_cache", val)
val == :missing ? nil : val
end
end
end
end
def self.skip_db=(v)
#skip_db = v
end
def self.skip_db?
#skip_db
end
def self.skip_redis=(v)
#skip_redis = v
end
def self.skip_redis?
#skip_redis
end
def self.use_s3?
(#use_s3 ||=
begin
s3_bucket &&
s3_region && (
s3_use_iam_profile || (s3_access_key_id && s3_secret_access_key)
) ? :true : :false
end) == :true
end
def self.s3_bucket_name
#s3_bucket_name ||= s3_bucket.downcase.split("/")[0]
end
# for testing
def self.reset_s3_cache!
#use_s3 = nil
end
def self.database_config
hash = { "adapter" => "postgresql" }
%w{
pool
connect_timeout
timeout
socket
host
backup_host
port
backup_port
username
password
replica_host
replica_port
}.each do |s|
if val = self.public_send("db_#{s}")
hash[s] = val
end
end
hash["adapter"] = "postgresql_fallback" if hash["replica_host"]
hostnames = [ hostname ]
hostnames << backup_hostname if backup_hostname.present?
hostnames << URI.parse(cdn_url).host if cdn_url.present?
hash["host_names"] = hostnames
hash["database"] = db_name
hash["prepared_statements"] = !!self.db_prepared_statements
{ "production" => hash }
end
# For testing purposes
def self.reset_redis_config!
#config = nil
#message_bus_config = nil
end
def self.redis_config
#config ||=
begin
c = {}
c[:host] = redis_host if redis_host
c[:port] = redis_port if redis_port
if redis_slave_host && redis_slave_port
c[:slave_host] = redis_slave_host
c[:slave_port] = redis_slave_port
c[:connector] = DiscourseRedis::Connector
end
c[:password] = redis_password if redis_password.present?
c[:db] = redis_db if redis_db != 0
c[:db] = 1 if Rails.env == "test"
c[:id] = nil if redis_skip_client_commands
c.freeze
end
end
def self.message_bus_redis_config
return redis_config unless message_bus_redis_enabled
#message_bus_config ||=
begin
c = {}
c[:host] = message_bus_redis_host if message_bus_redis_host
c[:port] = message_bus_redis_port if message_bus_redis_port
if message_bus_redis_slave_host && message_bus_redis_slave_port
c[:slave_host] = message_bus_redis_slave_host
c[:slave_port] = message_bus_redis_slave_port
c[:connector] = DiscourseRedis::Connector
end
c[:password] = message_bus_redis_password if message_bus_redis_password.present?
c[:db] = message_bus_redis_db if message_bus_redis_db != 0
c[:db] = 1 if Rails.env == "test"
c[:id] = nil if message_bus_redis_skip_client_commands
c.freeze
end
end
def self.add_default(name, default)
unless self.respond_to? name
define_singleton_method(name) do
default
end
end
end
class BaseProvider
def self.coerce(setting)
return setting == "true" if setting == "true" || setting == "false"
return $1.to_i if setting.to_s.strip =~ /^([0-9]+)$/
setting
end
def resolve(current, default)
BaseProvider.coerce(
if current.present?
current
else
default.present? ? default : nil
end
)
end
end
class FileProvider < BaseProvider
attr_reader :data
def self.from(file)
if File.exists?(file)
parse(file)
end
end
def initialize(file)
#file = file
#data = {}
end
def read
ERB.new(File.read(#file)).result().split("\n").each do |line|
if line =~ /^\s*([a-z_]+[a-z0-9_]*)\s*=\s*(\"([^\"]*)\"|\'([^\']*)\'|[^#]*)/
#data[$1.strip.to_sym] = ($4 || $3 || $2).strip
end
end
end
def lookup(key, default)
var = #data[key]
resolve(var, var.nil? ? default : "")
end
def keys
#data.keys
end
def self.parse(file)
provider = self.new(file)
provider.read
provider
end
private_class_method :parse
end
class EnvProvider < BaseProvider
def lookup(key, default)
var = ENV["DISCOURSE_" + key.to_s.upcase]
resolve(var , var.nil? ? default : nil)
end
def keys
ENV.keys.select { |k| k =~ /^DISCOURSE_/ }.map { |k| k[10..-1].downcase.to_sym }
end
end
class BlankProvider < BaseProvider
def lookup(key, default)
if key == :redis_port
return ENV["DISCOURSE_REDIS_PORT"] if ENV["DISCOURSE_REDIS_PORT"]
end
default
end
def keys
[]
end
end
class << self
attr_accessor :provider
end
def self.configure!
if Rails.env == "test"
#provider = BlankProvider.new
else
#provider =
FileProvider.from(File.expand_path('../../../config/discourse.conf', __FILE__)) ||
EnvProvider.new
end
end
end
error
Failed to report error: Name or service not known 2 Name or service not known subscribe failed, reconnecting in 1 second. Call stack ["/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/connection/hiredis.rb:19:in `connect'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/connection/hiredis.rb:19:in `connect'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:334:in `establish_connection'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:99:in `block in connect'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:291:in `with_reconnect'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:98:in `connect'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:274:in `with_socket_timeout'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:131:in `call_loop'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/subscribe.rb:43:in `subscription'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/subscribe.rb:12:in `subscribe'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:2824:in `_subscription'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:2192:in `block in subscribe'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:45:in `block in synchronize'",
"/app/vendor/ruby-2.5.5/lib/ruby/2.5.0/monitor.rb:226:in `mon_synchronize'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:45:in `synchronize'",
"/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:2191:in `subscribe'",
"/app/vendor/bundle/ruby/2.5.0/gems/message_bus-2.2.2/lib/message_bus/backends/redis.rb:287:in `global_subscribe'",
"/app/vendor/bundle/ruby/2.5.0/gems/message_bus-2.2.2/lib/message_bus.rb:721:in `global_subscribe_thread'",
"/app/vendor/bundle/ruby/2.5.0/gems/message_bus-2.2.2/lib/message_bus.rb:669:in `block in new_subscriber_thread'"]
fatal: not a git repository (or any parent up to mount point /)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
rake aborted!
Name or service not known
Add your db and redis-host name and port no. in discourse_defaults.conf
Settinggs are available in Hroku_addons. In my case it is as following :
redis_host = ***-***-***.compute-1.amazonaws.com
redis_port = *****
I'm using Rails 5. I have this file, config/environment_variables.yml
development:
COINBASE_KEY: devkey
COINBASE_SECRET: devsecret
test:
COINBASE_KEY: testkey
COINBASE_SECRET: testsecret
production:
COINBASE_KEY: prodkey
COINBASE_SECRET: prodsecret
I load it with the file, config/initializers/environment_variables.rb
module EnvironmentVariables
class Application < Rails::Application
config.before_configuration do
env_file = Rails.root.join("config", 'environment_variables.yml').to_s
if File.exists?(env_file)
YAML.load_file(env_file)[Rails.env].each do |key, value|
ENV[key.to_s] = value
end # end YAML.load_file
end # end if File.exists?
end # end config.before_configuration
end # end class
end # end module
but when I run my test using
rails test test/services/crypto_currency_service_test.rb
The test variables aren't loading -- rather those from the dev environment are loading. Below is my test file
require 'coinbase/wallet'
require 'minitest/mock'
class CryptoCurrencyServiceTest < ActiveSupport::TestCase
test 'sell' do
last_transaction = MyTransaction.new({
:transaction_type => "buy",
:amount_in_usd => "100",
:btc_price_in_usd => "3000"
})
puts "env: #{ENV['COINBASE_KEY']}"
#client = Coinbase::Wallet::Client.new(api_key: ENV['COINBASE_KEY'], api_secret: ENV['COINBASE_SECRET'])
How do I get the test variables to load by default when I run tests?
Edit: Here's the config/environments/test.rb file, which I haven't (consciously) changed ...
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Do not eager load code on boot. This avoids loading your whole application
# just for the purpose of running a single test. If you are using a tool that
# preloads Rails for running tests, you may have to set it to true.
config.eager_load = false
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=3600'
}
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
# Raises error for missing translations
# config.action_view.raise_on_missing_translations = true
end
I would not recommend to write custom code for this. There are existing solutions for setting up environment variables. See dotenv-rails for example. It allows you to put common variables into .env file. Just add gem 'dotenv-rails' to your Gemfile and put common variables into .env file:
# .env
COINBASE_KEY: devkey
COINBASE_SECRET: devsecret
If you need environment-specific variables it allows you to have separate files for this: .env.development, .env.test and .env.production:
#.env.test
COINBASE_KEY: testkey
COINBASE_SECRET: testsecret
#.env.production
COINBASE_KEY: prodkey
COINBASE_SECRET: prodsecret
From the comments in your original post, I suggest checking if config.before_configuration block is not at fault. Might be the case that the rails environment is loaded after that block has run and so you get Rails.env == 'test' when you print that out inside a test, but in the configuration it takes keys from default (development) environment.
Might I suggest moving this part
env_file = Rails.root.join("config", 'environment_variables.yml').to_s
if File.exists?(env_file)
YAML.load_file(env_file)[Rails.env].each do |key, value|
ENV[key.to_s] = value
end # end YAML.load_file
end # end if File.exists?
out in an intializer and then check the environment variables. Might fix the problem. (because initializers surely should respect the environment)
UPDATE: From the documentation it seems that before_configuration block is the VERY first block config part to run, so Rails.env is probably not yet set at that point.
Now I am dealing with dashing from here http://shopify.github.io/dashing/ I created an dashing app using Sinatra and I added some more 3rd party API's everything is working well. Now I want to run the app with rails I tried every thing is working fine but "event" method can't be called by server.Actually it is in dashing.rb file in my lib directory it is like this.
require 'sinatra'
``require 'sprockets'
require 'sinatra/content_for'
require 'rufus/scheduler'
require 'coffee-script'
require 'sass'
require 'json'
require 'pry'
module Dashing
SCHEDULER = Rufus::Scheduler.start_new
class App < Sinatra::Base
if Rails && Rails.root
set :root, Rails.root
set :root_path, '/dashing/'
Rails.application.config.assets.precompile += %w( dashing/application.js dashing/application.css )
set :views, Rails.root.join('app', 'dashing', 'dashboards')
set :widget_path, "#{settings.root}/app/dashing/widgets/"
set :lock, true
set :threaded, true
else
set :root, Dir.pwd
set :root_path, '/'
set :sprockets, Sprockets::Environment.new(settings.root)
set :assets_prefix, '/assets'
set :digest_assets, false
['assets/javascripts', 'assets/stylesheets', 'assets/fonts', 'assets/images', 'widgets', File.expand_path('../../javascripts', __FILE__)]. each do |path|
settings.sprockets.append_path path
end
set server: 'thin'
set :public_folder, File.join(settings.root, 'public')
set :views, File.join(settings.root, 'dashboards')
set :widget_path, File.join(settings.root, 'widgets')
end
set connections: [], history: {}
set :default_dashboard, nil
set :auth_token, nil
helpers Sinatra::ContentFor
helpers do
def protected!
# override with auth logic
end
end
get '/events', provides: 'text/event-stream' do
protected!
stream :keep_open do |out|
settings.connections << out
out << self.latest_events
out.callback { settings.connections.delete(out) }
end
end
get '/' do
begin
redirect settings.root_path + (settings.default_dashboard || self.first_dashboard).to_s
rescue NoMethodError => e
raise Exception.new("There are no dashboards in your dashboard directory.")
end
end
get '/:dashboard' do
protected!
erb params[:dashboard].to_sym
end
get '/views/:widget?.html' do
protected!
widget = params[:widget]
send_file File.join(settings.widget_path, widget, "#{widget}.html")
end
post '/widgets/:id' do
request.body.rewind
body = JSON.parse(request.body.read)
auth_token = body.delete("auth_token")
if !settings.auth_token || settings.auth_token == auth_token
Dashing::Application.send_event(params['id'], body)
204 # response without entity body
else
status 401
"Invalid API key\n"
end
end
class << self
def development?
ENV['RACK_ENV'] == 'development'
end
def production?
ENV['RACK_ENV'] == 'production'
end
def send_event(id, body)
body["id"] = id
body["updatedAt"] = Time.now.to_i
event = format_event(body.to_json)
settings.history[id] = event
settings.connections.each { |out| out << event }
end
def format_event(body)
"data: #{body}\n\n"
end
end
def latest_events
settings.history.inject("") do |str, (id, body)|
str << body
end
end
def first_dashboard
files = Dir[File.join(settings.views, '*.erb')].collect { |f| f.match(/(\w*).erb/)[1] }
files -= ['layout']
files.first
end
Dir[File.join(settings.root, 'lib', '**', '*.rb')].each {|file| require file }
{}.to_json # Forces your json codec to initialize (in the event that it is lazily loaded). Does this before job threads start.
job_path = ENV["JOB_PATH"] || 'jobs'
files = Dir[File.join(settings.root, job_path, '/*.rb')]
files.each { |job| require(job) }
end
end
Rails unable to execute /events root in this.
Can any one suggest me. How to call this /events root in rails.I am using batman.js to call events.
You might want to take a look at Dashing-Rails gem
it only applies on rails 4
Requirements
Ruby >=1.9.3
Rails 4
Redis
Multi Threaded server (puma, rainbows)
I'm fairly new to Ruby on Rails and making my way through Michael Hartl's Rails Tutorial. I've hit a bug I can't seem to fix on Chapter 10 (specifically, 10.1.3 "User/Micropost associations"). The error I run into is when I execute the following rspec command:
$ bundle exec rspec spec/models
It raises the following error:
Failures:
1) Micropost accessible attributes should not allow access to user_id
←[31mFailure/Error:←[0m ←[31mexpect do←[0m
←[31mexpected ActiveModel::MassAssignmentSecurity::Error but nothing was
raised←[0m
←[36m # ./spec/models/micropost_spec.rb:28:in `block (3 levels) in <top (req
uired)>'←[0m
Finished in 5.79 seconds
←[31m27 examples, 1 failure←[0m
Failed examples:
←[31mrspec ./spec/models/micropost_spec.rb:27←[0m ←[36m# Micropost accessible at
tributes should not allow access to user_id←[0m
This is the code for micropost_spec.rb:
require 'spec_helper'
describe Micropost do
let(:user) { FactoryGirl.create(:user) }
before { #micropost = user.microposts.build(content: "Lorem ipsum") }
subject { #micropost }
it { should respond_to(:content) }
it { should respond_to(:user_id) }
it { should respond_to(:user) }
its(:user) { should == user }
it { should be_valid }
describe "when user_id is not present" do
before { #micropost.user_id = nil }
it { should_not be_valid }
end
describe "accessible attributes" do
it "should not allow access to user_id" do
expect do
Micropost.new(user_id: user.id)
end.to raise_error(ActiveModel::MassAssignmentSecurity::Error)
end
end
end
application.rb:
require File.expand_path('../boot', __FILE__)
# Pick the frameworks you want:
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "sprockets/railtie"
# require "rails/test_unit/railtie"
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
module SampleApp
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.active_record.whitelist_attributes = true
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
end
end
micropost.rb...
class Micropost < ActiveRecord::Base
attr_accessible :content
belongs_to :user
validates :user_id, presence: true
end
Thanks in advance for your help!
Thai
So expected ActiveModel::MassAssignmentSecurity::Error but nothing was
raised when Micropost.new(user_id: user.id) is called.
For it to work correctly:
The Rails application should be configured to explicitly whitelist or blacklist accessible parameters; in rails versions before 3.2.3 this was on by default; in previous versions, it has to be done by the following line in config/application.rb as detailed in Listing 10.6 of RailsTutorial book:
config.active_record.whitelist_attributes = true
There shouldn't be a attr_accessible :user_id in the micropost.rb model file.
Try adding
config.active_record.mass_assignment_sanitizer = :strict
To your application.rb file, what I found out is that if not strict, it would just throw a Warning but not an exception.
Like you, I tried all of the solutions above with no luck. I also notice that Hartl's more recent editions of the book for Rails 4 do not contain those tests, so I suspect this approach to testing accessibility does not work in later versions. Perhaps an expert (someone who isn't running through the Rails Tutorial) can chime in.
But.... I noticed this response in another StackOverflow thread recommending the "shoulda-matchers" Gem to test it, and that solved the problem for me (https://stackoverflow.com/a/11876425/3899955). In investigating that Gem, I find it is a nice way to produce readable tests for a number of common ActiveModel, ActiveRecord, and ActionController tests. I am happy to be adding that to my quiver, perhaps you will be too.
I don't take credit for that answer, just wanted to post this so if anyone else is running in to this frustration doing Chapter 10.5, or completing exercise 6 in Chapter 9.
The ActionMailer in my Rails 3.1 project has an odd behavior, the ActionMailer::Base.deliveries is empty in test while I can actually receive the email by running the code in rails console. Anybody can points out what wrong it is?
# spec/mailers/user_mailer_spec.rb
require "spec_helper"
describe UserMailer do
describe ".reminding_email" do
subject { UserMailer.reminding_email(user).deliver }
let(:user) { create :confirmed_user_with_mass_tasks }
it "should be delivered" do
ActionMailer::Base.deliveries.should_not be_empty
end
its(:to) { should == [user.email] }
its(:subject) { should == "Task Reminding" }
end
end
# app/mailers/user_mailer.rb
class UserMailer < ActionMailer::Base
layout "email"
default from: Rails.env.production? ? "<production>#gmail.com" : "<test>#gmail.com"
def reminding_email(user)
#tasks = user.tasks.reminding_required
#current = Time.current
mail(to: user.email, subject: "Task Reminding")
end
end
Failures:
1) UserMailer.reminding_email should be delivered
Failure/Error: ActionMailer::Base.deliveries.should_not be_empty
expected empty? to return false, got true
# ./spec/mailers/user_mailer_spec.rb:8:in `block (3 levels) in '
Finished in 11.81 seconds
42 examples, 1 failure, 2 pending
# config/environments/test.rb
RemindersForMe::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Configure static asset server for tests with Cache-Control for performance
config.serve_static_assets = true
config.static_cache_control = "public, max-age=3600"
# Log error messages when you accidentally call methods on nil
config.whiny_nils = true
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Raise exceptions instead of rendering exception templates
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
# Setup default URL options as devise needed
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
end
Application:
# config/application.rb
require File.expand_path('../boot', __FILE__)
# Pick the frameworks you want:
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "active_resource/railtie"
require "sprockets/railtie"
# require "rails/test_unit/railtie"
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
# Bundler.require(*Rails.groups(:assets => %w(development test)))
Bundler.require *Rails.groups(:assets) if defined?(Bundler)
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
module RemindersForMe
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
# config.i18n.default_locale = :de
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
# Set Rspec generator as default
config.generators do |g|
g.test_framework :rspec
end
# Set Mailer of Devise
config.to_prepare do
Devise::Mailer.layout "email"
end
end
end
Now change the spec as follow:
require "spec_helper"
describe UserMailer do
describe ".reminding_email" do
subject { UserMailer.reminding_email(user) }
let(:user) { create :confirmed_user_with_undue_tasks }
it { expect { subject.deliver }.to change { ActionMailer::Base.deliveries.length }.by(1) }
its(:to) { should == [user.email] }
its(:subject) { should == "Task Reminding" }
end
end
1) UserMailer.reminding_email
Failure/Error: it { expect { subject.deliver }.to change { ActionMailer::Base.deliveries.length }.by(1) }
result should have been changed by 1, but was changed by 2
# ./spec/mailers/user_mailer_spec.rb:7:in `block (3 levels) in '
I had a similar problem and it happened because I was testing Devise emails: Devise uses a separate mailer, so you'll need to access Devise.mailer.deliveries instead of ActionMailer::Base.deliveries.
You should test the separated properties of the mail:
describe UserMailer do
describe ".reminding_email" do
subject { UserMailer.reminding_email(user)}
let(:user) { create :confirmed_user_with_mass_tasks }
it{ expect{subject.deliver}.to change{ActionMailer::Base.deliveries.length}.by(1)}
its(:to) { should == [user.email] }
its(:subject) { should == "Task Reminding" }
end
end
Notice the change in the subject, because your mailer as it should returns the mail method result, which already initialized with to and subject.
By default Action Mailer does not send emails in the test environment. They are just added to the ActionMailer::Base.deliveries array. (See section 6 in http://guides.rubyonrails.org/action_mailer_basics.html)
What "by default" means is that you should not provide effective email_delivery settings for the test environment. If there are effective default email_delivery settings in "config/configuration.yml", you can override it with:
test:
email_delivery:
delivery_method: :test
How are you configuring ActionMailer? Is it within your config/application.rb file or within the specific environments/*.rb files?
Remember, anything you specify in the environments/*.rb files take precedence over the config/application.rb file.
So perhaps your problem is that when running in test mode the ActionMailer is using :smtp and not :test?