base_rails_app 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +1 -0
- data/README +1 -0
- data/lib/app/controllers/application_controller.rb +55 -0
- data/lib/app/controllers/password_resets_controller.rb +45 -0
- data/lib/app/controllers/user_sessions_controller.rb +25 -0
- data/lib/app/controllers/users_controller.rb +37 -0
- data/lib/app/helpers/application_helper.rb +4 -0
- data/lib/app/helpers/user_sessions_helper.rb +2 -0
- data/lib/app/helpers/users_helper.rb +2 -0
- data/lib/app/models/postman.rb +20 -0
- data/lib/app/models/user.rb +12 -0
- data/lib/app/models/user_session.rb +2 -0
- data/lib/app/views/application/404_not_found.html.erb +8 -0
- data/lib/app/views/layouts/application.html.erb +57 -0
- data/lib/app/views/password_resets/_sidebar.html.erb +0 -0
- data/lib/app/views/password_resets/edit.html.erb +33 -0
- data/lib/app/views/password_resets/new.html.erb +26 -0
- data/lib/app/views/postman/password_reset_instructions.html.erb +3 -0
- data/lib/app/views/postman/welcome_email.html.erb +3 -0
- data/lib/app/views/user_sessions/_form.html.erb +19 -0
- data/lib/app/views/user_sessions/_sidebar.html.erb +13 -0
- data/lib/app/views/user_sessions/new.html.erb +15 -0
- data/lib/app/views/users/_form.html.erb +28 -0
- data/lib/app/views/users/_sidebar.html.erb +6 -0
- data/lib/app/views/users/edit.html.erb +19 -0
- data/lib/app/views/users/new.html.erb +15 -0
- data/lib/app/views/users/show.html.erb +46 -0
- data/lib/base_rails_app.rb +5 -0
- data/lib/base_rails_app/boot.rb +2 -0
- data/lib/base_rails_app/tasks.rb +12 -0
- data/lib/config/configatron/cucumber.rb +0 -0
- data/lib/config/configatron/defaults.rb +4 -0
- data/lib/config/configatron/development.rb +1 -0
- data/lib/config/configatron/production.rb +0 -0
- data/lib/config/configatron/test.rb +0 -0
- data/lib/config/database.yml +25 -0
- data/lib/config/deploy.rb +15 -0
- data/lib/config/environments/cucumber.rb +22 -0
- data/lib/config/environments/development.rb +17 -0
- data/lib/config/environments/production.rb +28 -0
- data/lib/config/environments/test.rb +28 -0
- data/lib/config/gemtronics.rb +36 -0
- data/lib/config/initializers/backtrace_silencers.rb +7 -0
- data/lib/config/initializers/configatron.rb +1 -0
- data/lib/config/initializers/hoptoad.rb +3 -0
- data/lib/config/initializers/inflections.rb +10 -0
- data/lib/config/initializers/mailers.rb +1 -0
- data/lib/config/initializers/mime_types.rb +5 -0
- data/lib/config/initializers/new_rails_defaults.rb +21 -0
- data/lib/config/initializers/session_store.rb +17 -0
- data/lib/config/locales/en.yml +5 -0
- data/lib/config/routes.rb +51 -0
- data/lib/config/schedule.rb +20 -0
- data/lib/db/migrate/20090809175903_create_users.rb +30 -0
- data/lib/db/migrate/20090809204840_acts_as_taggable_on_migration.rb +29 -0
- data/lib/db/migrate/20090912171353_create_delayed_jobs.rb +20 -0
- data/lib/db/migrate/20090912171829_add_delayed_job_extras.rb +11 -0
- data/lib/db/migrate/20090929201455_add_more_time_columns_to_dj.rb +11 -0
- data/lib/db/schema.rb +72 -0
- data/lib/db/seeds.rb +7 -0
- data/lib/lib/tasks/cucumber.rake +36 -0
- data/lib/lib/tasks/rcov.rake +27 -0
- data/lib/lib/tasks/rspec.rake +183 -0
- data/lib/vendor/plugins/delayed_job/generators/delayed_job/delayed_job_generator.rb +22 -0
- data/lib/vendor/plugins/delayed_job/generators/delayed_job/templates/migration.rb +20 -0
- data/lib/vendor/plugins/delayed_job/init.rb +2 -0
- data/lib/vendor/plugins/delayed_job/lib/delayed/command.rb +65 -0
- data/lib/vendor/plugins/delayed_job/lib/delayed/job.rb +271 -0
- data/lib/vendor/plugins/delayed_job/lib/delayed/message_sending.rb +18 -0
- data/lib/vendor/plugins/delayed_job/lib/delayed/performable_method.rb +55 -0
- data/lib/vendor/plugins/delayed_job/lib/delayed/tasks.rb +15 -0
- data/lib/vendor/plugins/delayed_job/lib/delayed/worker.rb +54 -0
- data/lib/vendor/plugins/delayed_job/lib/delayed_job.rb +13 -0
- data/lib/vendor/plugins/delayed_job/recipes/delayed_job.rb +26 -0
- data/lib/vendor/plugins/delayed_job/tasks/jobs.rake +1 -0
- data/lib/vendor/plugins/hoptoad_notifier/install.rb +1 -0
- data/lib/vendor/plugins/hoptoad_notifier/lib/hoptoad_notifier.rb +418 -0
- data/lib/vendor/plugins/hoptoad_notifier/lib/hoptoad_tasks.rb +26 -0
- data/lib/vendor/plugins/hoptoad_notifier/recipes/hoptoad.rb +22 -0
- data/lib/vendor/plugins/hoptoad_notifier/tasks/hoptoad_notifier_tasks.rake +66 -0
- data/lib/vendor/plugins/inherited_resources/README.rdoc +524 -0
- data/lib/vendor/plugins/inherited_resources/inherited_resources.gemspec +71 -0
- data/lib/vendor/plugins/inherited_resources/init.rb +1 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources.rb +23 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/actions.rb +79 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/base.rb +42 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/base_helpers.rb +363 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/belongs_to_helpers.rb +89 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/class_methods.rb +338 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/dsl.rb +26 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/dumb_responder.rb +20 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/has_scope_helpers.rb +83 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/legacy/respond_to.rb +156 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/legacy/responder.rb +200 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/polymorphic_helpers.rb +155 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/singleton_helpers.rb +95 -0
- data/lib/vendor/plugins/inherited_resources/lib/inherited_resources/url_helpers.rb +179 -0
- data/lib/vendor/plugins/inherited_resources/test/aliases_test.rb +139 -0
- data/lib/vendor/plugins/inherited_resources/test/association_chain_test.rb +125 -0
- data/lib/vendor/plugins/inherited_resources/test/base_test.rb +225 -0
- data/lib/vendor/plugins/inherited_resources/test/belongs_to_test.rb +87 -0
- data/lib/vendor/plugins/inherited_resources/test/class_methods_test.rb +138 -0
- data/lib/vendor/plugins/inherited_resources/test/customized_base_test.rb +162 -0
- data/lib/vendor/plugins/inherited_resources/test/customized_belongs_to_test.rb +76 -0
- data/lib/vendor/plugins/inherited_resources/test/defaults_test.rb +70 -0
- data/lib/vendor/plugins/inherited_resources/test/flash_test.rb +88 -0
- data/lib/vendor/plugins/inherited_resources/test/has_scope_test.rb +139 -0
- data/lib/vendor/plugins/inherited_resources/test/locales/en.yml +17 -0
- data/lib/vendor/plugins/inherited_resources/test/nested_belongs_to_test.rb +108 -0
- data/lib/vendor/plugins/inherited_resources/test/optional_belongs_to_test.rb +164 -0
- data/lib/vendor/plugins/inherited_resources/test/polymorphic_test.rb +186 -0
- data/lib/vendor/plugins/inherited_resources/test/redirect_to_test.rb +51 -0
- data/lib/vendor/plugins/inherited_resources/test/respond_to_test.rb +155 -0
- data/lib/vendor/plugins/inherited_resources/test/singleton_test.rb +83 -0
- data/lib/vendor/plugins/inherited_resources/test/test_helper.rb +38 -0
- data/lib/vendor/plugins/inherited_resources/test/url_helpers_test.rb +537 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cars/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cars/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cars/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cars/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cities/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cities/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cities/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/cities/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/comments/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/comments/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/comments/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/comments/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/employees/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/employees/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/employees/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/employees/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/managers/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/managers/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/managers/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/painters/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/painters/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/painters/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/painters/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/pets/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/pets/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/pets/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/pets/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/products/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/products/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/products/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/products/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/professors/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/professors/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/professors/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/professors/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/projects/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/projects/index.json.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/projects/respond_to_skip_default_template.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/projects/respond_with_resource.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/students/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/students/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/trees/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/trees/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/trees/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/trees/show.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/users/edit.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/users/index.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/users/new.html.erb +1 -0
- data/lib/vendor/plugins/inherited_resources/test/views/users/show.html.erb +1 -0
- data/lib/vendor/plugins/web-app-theme/README.md +22 -0
- data/lib/vendor/plugins/web-app-theme/images/avatar.png +0 -0
- data/lib/vendor/plugins/web-app-theme/index.html +473 -0
- data/lib/vendor/plugins/web-app-theme/javascripts/jquery-1.3.min.js +19 -0
- data/lib/vendor/plugins/web-app-theme/javascripts/jquery.localscroll.js +104 -0
- data/lib/vendor/plugins/web-app-theme/javascripts/jquery.scrollTo.js +150 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/theme/templates/view_layout_administration.html.erb +48 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/theme/templates/view_layout_sign.html.erb +15 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/theme/theme_generator.rb +38 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_edit.html.erb +20 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_form.html.erb +10 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_new.html.erb +19 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_show.html.erb +23 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_sidebar.html.erb +13 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_signin.html.erb +39 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_signup.html.erb +56 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/templates/view_tables.html.erb +50 -0
- data/lib/vendor/plugins/web-app-theme/rails_generators/themed/themed_generator.rb +89 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/base.css +336 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/bec-green/style.css +290 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/bec/style.css +301 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/blue/style.css +280 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/default/style.css +267 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/djime-cerulean/style.css +298 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/drastic-dark/style.css +373 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/kathleene/style.css +272 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/orange/style.css +263 -0
- data/lib/vendor/plugins/web-app-theme/stylesheets/themes/reidb-greenish/style.css +301 -0
- metadata +257 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Re-definitions are appended to existing tasks
|
|
2
|
+
task :environment
|
|
3
|
+
task :merb_env
|
|
4
|
+
|
|
5
|
+
namespace :jobs do
|
|
6
|
+
desc "Clear the delayed_job queue."
|
|
7
|
+
task :clear => [:merb_env, :environment] do
|
|
8
|
+
Delayed::Job.delete_all
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
desc "Start a delayed_job worker."
|
|
12
|
+
task :work => [:merb_env, :environment] do
|
|
13
|
+
Delayed::Worker.new(:min_priority => ENV['MIN_PRIORITY'], :max_priority => ENV['MAX_PRIORITY']).start
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Delayed
|
|
2
|
+
class Worker
|
|
3
|
+
SLEEP = 5
|
|
4
|
+
|
|
5
|
+
cattr_accessor :logger
|
|
6
|
+
self.logger = if defined?(Merb::Logger)
|
|
7
|
+
Merb.logger
|
|
8
|
+
elsif defined?(RAILS_DEFAULT_LOGGER)
|
|
9
|
+
RAILS_DEFAULT_LOGGER
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(options={})
|
|
13
|
+
@quiet = options[:quiet]
|
|
14
|
+
Delayed::Job.min_priority = options[:min_priority] if options.has_key?(:min_priority)
|
|
15
|
+
Delayed::Job.max_priority = options[:max_priority] if options.has_key?(:max_priority)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def start
|
|
19
|
+
say "*** Starting job worker #{Delayed::Job.worker_name}"
|
|
20
|
+
|
|
21
|
+
trap('TERM') { say 'Exiting...'; $exit = true }
|
|
22
|
+
trap('INT') { say 'Exiting...'; $exit = true }
|
|
23
|
+
|
|
24
|
+
loop do
|
|
25
|
+
result = nil
|
|
26
|
+
|
|
27
|
+
realtime = Benchmark.realtime do
|
|
28
|
+
result = Delayed::Job.work_off
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
count = result.sum
|
|
32
|
+
|
|
33
|
+
break if $exit
|
|
34
|
+
|
|
35
|
+
if count.zero?
|
|
36
|
+
sleep(SLEEP)
|
|
37
|
+
else
|
|
38
|
+
say "#{count} jobs processed at %.4f j/s, %d failed ..." % [count / realtime, result.last]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
break if $exit
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ensure
|
|
45
|
+
Delayed::Job.clear_locks!
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def say(text)
|
|
49
|
+
puts text unless @quiet
|
|
50
|
+
logger.info text if logger
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
autoload :ActiveRecord, 'activerecord'
|
|
2
|
+
|
|
3
|
+
require File.dirname(__FILE__) + '/delayed/message_sending'
|
|
4
|
+
require File.dirname(__FILE__) + '/delayed/performable_method'
|
|
5
|
+
require File.dirname(__FILE__) + '/delayed/job'
|
|
6
|
+
require File.dirname(__FILE__) + '/delayed/worker'
|
|
7
|
+
|
|
8
|
+
Object.send(:include, Delayed::MessageSending)
|
|
9
|
+
Module.send(:include, Delayed::MessageSending::ClassMethods)
|
|
10
|
+
|
|
11
|
+
if defined?(Merb::Plugins)
|
|
12
|
+
Merb::Plugins.add_rakefiles File.dirname(__FILE__) / 'delayed' / 'tasks'
|
|
13
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Capistrano Recipes for managing delayed_job
|
|
2
|
+
#
|
|
3
|
+
# Add these callbacks to have the delayed_job process restart when the server
|
|
4
|
+
# is restarted:
|
|
5
|
+
#
|
|
6
|
+
# after "deploy:stop", "delayed_job:stop"
|
|
7
|
+
# after "deploy:start", "delayed_job:start"
|
|
8
|
+
# after "deploy:restart", "delayed_job:restart"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
namespace :delayed_job do
|
|
12
|
+
desc "Stop the delayed_job process"
|
|
13
|
+
task :stop, :roles => :app do
|
|
14
|
+
run "cd #{current_path}; script/delayed_job -e #{rails_env} stop"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc "Start the delayed_job process"
|
|
18
|
+
task :start, :roles => :app do
|
|
19
|
+
run "cd #{current_path}; script/delayed_job -e #{rails_env} start"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
desc "Restart the delayed_job process"
|
|
23
|
+
task :restart, :roles => :app do
|
|
24
|
+
run "cd #{current_path}; script/delayed_job -e #{rails_env} restart"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'delayed', 'tasks'))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
puts IO.read(File.join(File.dirname(__FILE__), 'INSTALL'))
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'net/https'
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'active_support'
|
|
5
|
+
|
|
6
|
+
# Plugin for applications to automatically post errors to the Hoptoad of their choice.
|
|
7
|
+
module HoptoadNotifier
|
|
8
|
+
|
|
9
|
+
IGNORE_DEFAULT = ['ActiveRecord::RecordNotFound',
|
|
10
|
+
'ActionController::RoutingError',
|
|
11
|
+
'ActionController::InvalidAuthenticityToken',
|
|
12
|
+
'CGI::Session::CookieStore::TamperedWithCookie',
|
|
13
|
+
'ActionController::UnknownAction']
|
|
14
|
+
|
|
15
|
+
# Some of these don't exist for Rails 1.2.*, so we have to consider that.
|
|
16
|
+
IGNORE_DEFAULT.map!{|e| eval(e) rescue nil }.compact!
|
|
17
|
+
IGNORE_DEFAULT.freeze
|
|
18
|
+
|
|
19
|
+
IGNORE_USER_AGENT_DEFAULT = []
|
|
20
|
+
|
|
21
|
+
VERSION = "1.2.4"
|
|
22
|
+
LOG_PREFIX = "** [Hoptoad] "
|
|
23
|
+
|
|
24
|
+
HEADERS = {
|
|
25
|
+
'Content-type' => 'application/x-yaml',
|
|
26
|
+
'Accept' => 'text/xml, application/xml',
|
|
27
|
+
'X-Hoptoad-Client-Name' => 'Hoptoad Notifier',
|
|
28
|
+
'X-Hoptoad-Client-Version' => VERSION
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class << self
|
|
32
|
+
attr_accessor :host, :port, :secure, :api_key, :http_open_timeout, :http_read_timeout,
|
|
33
|
+
:proxy_host, :proxy_port, :proxy_user, :proxy_pass, :output
|
|
34
|
+
|
|
35
|
+
def backtrace_filters
|
|
36
|
+
@backtrace_filters ||= []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def ignore_by_filters
|
|
40
|
+
@ignore_by_filters ||= []
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Takes a block and adds it to the list of ignore filters. When the filters
|
|
44
|
+
# run, the block will be handed the exception. If the block yields a value
|
|
45
|
+
# equivalent to "true," the exception will be ignored, otherwise it will be
|
|
46
|
+
# processed by hoptoad.
|
|
47
|
+
def ignore_by_filter &block
|
|
48
|
+
self.ignore_by_filters << block
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Takes a block and adds it to the list of backtrace filters. When the filters
|
|
52
|
+
# run, the block will be handed each line of the backtrace and can modify
|
|
53
|
+
# it as necessary. For example, by default a path matching the RAILS_ROOT
|
|
54
|
+
# constant will be transformed into "[RAILS_ROOT]"
|
|
55
|
+
def filter_backtrace &block
|
|
56
|
+
self.backtrace_filters << block
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The port on which your Hoptoad server runs.
|
|
60
|
+
def port
|
|
61
|
+
@port || (secure ? 443 : 80)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The host to connect to.
|
|
65
|
+
def host
|
|
66
|
+
@host ||= 'hoptoadapp.com'
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The HTTP open timeout (defaults to 2 seconds).
|
|
70
|
+
def http_open_timeout
|
|
71
|
+
@http_open_timeout ||= 2
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# The HTTP read timeout (defaults to 5 seconds).
|
|
75
|
+
def http_read_timeout
|
|
76
|
+
@http_read_timeout ||= 5
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Returns the list of errors that are being ignored. The array can be appended to.
|
|
80
|
+
def ignore
|
|
81
|
+
@ignore ||= (HoptoadNotifier::IGNORE_DEFAULT.dup)
|
|
82
|
+
@ignore.flatten!
|
|
83
|
+
@ignore
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Sets the list of ignored errors to only what is passed in here. This method
|
|
87
|
+
# can be passed a single error or a list of errors.
|
|
88
|
+
def ignore_only=(names)
|
|
89
|
+
@ignore = [names].flatten
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns the list of user agents that are being ignored. The array can be appended to.
|
|
93
|
+
def ignore_user_agent
|
|
94
|
+
@ignore_user_agent ||= (HoptoadNotifier::IGNORE_USER_AGENT_DEFAULT.dup)
|
|
95
|
+
@ignore_user_agent.flatten!
|
|
96
|
+
@ignore_user_agent
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Sets the list of ignored user agents to only what is passed in here. This method
|
|
100
|
+
# can be passed a single user agent or a list of user agents.
|
|
101
|
+
def ignore_user_agent_only=(names)
|
|
102
|
+
@ignore_user_agent = [names].flatten
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Returns a list of parameters that should be filtered out of what is sent to Hoptoad.
|
|
106
|
+
# By default, all "password" attributes will have their contents replaced.
|
|
107
|
+
def params_filters
|
|
108
|
+
@params_filters ||= %w(password password_confirmation)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def environment_filters
|
|
112
|
+
@environment_filters ||= %w()
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def report_ready
|
|
116
|
+
write_verbose_log("Notifier #{VERSION} ready to catch errors")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def report_environment_info
|
|
120
|
+
write_verbose_log("Environment Info: #{environment_info}")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def report_response_body(response)
|
|
124
|
+
write_verbose_log("Response from Hoptoad: \n#{response}")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def environment_info
|
|
128
|
+
info = "[Ruby: #{RUBY_VERSION}]"
|
|
129
|
+
info << " [Rails: #{::Rails::VERSION::STRING}] [RailsEnv: #{RAILS_ENV}]" if defined?(Rails)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def write_verbose_log(message)
|
|
133
|
+
logger.info LOG_PREFIX + message if logger
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Checking for the logger in hopes we can get rid of the ugly syntax someday
|
|
137
|
+
def logger
|
|
138
|
+
if defined?(Rails.logger)
|
|
139
|
+
Rails.logger
|
|
140
|
+
elsif defined?(RAILS_DEFAULT_LOGGER)
|
|
141
|
+
RAILS_DEFAULT_LOGGER
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Call this method to modify defaults in your initializers.
|
|
146
|
+
#
|
|
147
|
+
# HoptoadNotifier.configure do |config|
|
|
148
|
+
# config.api_key = '1234567890abcdef'
|
|
149
|
+
# config.secure = false
|
|
150
|
+
# end
|
|
151
|
+
#
|
|
152
|
+
# NOTE: secure connections are not yet supported.
|
|
153
|
+
def configure
|
|
154
|
+
add_default_filters
|
|
155
|
+
yield self
|
|
156
|
+
if defined?(ActionController::Base) && !ActionController::Base.include?(HoptoadNotifier::Catcher)
|
|
157
|
+
ActionController::Base.send(:include, HoptoadNotifier::Catcher)
|
|
158
|
+
end
|
|
159
|
+
report_ready
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def protocol #:nodoc:
|
|
163
|
+
secure ? "https" : "http"
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def url #:nodoc:
|
|
167
|
+
URI.parse("#{protocol}://#{host}:#{port}/notices/")
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def default_notice_options #:nodoc:
|
|
171
|
+
{
|
|
172
|
+
:api_key => HoptoadNotifier.api_key,
|
|
173
|
+
:error_message => 'Notification',
|
|
174
|
+
:backtrace => caller,
|
|
175
|
+
:request => {},
|
|
176
|
+
:session => {},
|
|
177
|
+
:environment => ENV.to_hash
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# You can send an exception manually using this method, even when you are not in a
|
|
182
|
+
# controller. You can pass an exception or a hash that contains the attributes that
|
|
183
|
+
# would be sent to Hoptoad:
|
|
184
|
+
# * api_key: The API key for this project. The API key is a unique identifier that Hoptoad
|
|
185
|
+
# uses for identification.
|
|
186
|
+
# * error_message: The error returned by the exception (or the message you want to log).
|
|
187
|
+
# * backtrace: A backtrace, usually obtained with +caller+.
|
|
188
|
+
# * request: The controller's request object.
|
|
189
|
+
# * session: The contents of the user's session.
|
|
190
|
+
# * environment: ENV merged with the contents of the request's environment.
|
|
191
|
+
def notify notice = {}
|
|
192
|
+
Sender.new.notify_hoptoad( notice )
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def add_default_filters
|
|
196
|
+
self.backtrace_filters.clear
|
|
197
|
+
|
|
198
|
+
filter_backtrace do |line|
|
|
199
|
+
line.gsub(/#{RAILS_ROOT}/, "[RAILS_ROOT]")
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
filter_backtrace do |line|
|
|
203
|
+
line.gsub(/^\.\//, "")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
filter_backtrace do |line|
|
|
207
|
+
if defined?(Gem)
|
|
208
|
+
Gem.path.inject(line) do |line, path|
|
|
209
|
+
line.gsub(/#{path}/, "[GEM_ROOT]")
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
filter_backtrace do |line|
|
|
215
|
+
line if line !~ /lib\/#{File.basename(__FILE__)}/
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Include this module in Controllers in which you want to be notified of errors.
|
|
221
|
+
module Catcher
|
|
222
|
+
|
|
223
|
+
def self.included(base) #:nodoc:
|
|
224
|
+
if base.instance_methods.map(&:to_s).include? 'rescue_action_in_public' and !base.instance_methods.map(&:to_s).include? 'rescue_action_in_public_without_hoptoad'
|
|
225
|
+
base.send(:alias_method, :rescue_action_in_public_without_hoptoad, :rescue_action_in_public)
|
|
226
|
+
base.send(:alias_method, :rescue_action_in_public, :rescue_action_in_public_with_hoptoad)
|
|
227
|
+
base.hide_action(:notify_hoptoad, :inform_hoptoad) if base.respond_to?(:hide_action)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Overrides the rescue_action method in ActionController::Base, but does not inhibit
|
|
232
|
+
# any custom processing that is defined with Rails 2's exception helpers.
|
|
233
|
+
def rescue_action_in_public_with_hoptoad exception
|
|
234
|
+
notify_hoptoad(exception) unless ignore?(exception) || ignore_user_agent?
|
|
235
|
+
rescue_action_in_public_without_hoptoad(exception)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# This method should be used for sending manual notifications while you are still
|
|
239
|
+
# inside the controller. Otherwise it works like HoptoadNotifier.notify.
|
|
240
|
+
def notify_hoptoad hash_or_exception
|
|
241
|
+
if public_environment?
|
|
242
|
+
notice = normalize_notice(hash_or_exception)
|
|
243
|
+
notice = clean_notice(notice)
|
|
244
|
+
send_to_hoptoad(:notice => notice)
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Returns the default logger or a logger that prints to STDOUT. Necessary for manual
|
|
249
|
+
# notifications outside of controllers.
|
|
250
|
+
def logger
|
|
251
|
+
ActiveRecord::Base.logger
|
|
252
|
+
rescue
|
|
253
|
+
@logger ||= Logger.new(STDERR)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
private
|
|
257
|
+
|
|
258
|
+
def public_environment? #nodoc:
|
|
259
|
+
defined?(RAILS_ENV) and !['development', 'test'].include?(RAILS_ENV)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def ignore?(exception) #:nodoc:
|
|
263
|
+
ignore_these = HoptoadNotifier.ignore.flatten
|
|
264
|
+
ignore_these.include?(exception.class) || ignore_these.include?(exception.class.name) || HoptoadNotifier.ignore_by_filters.find {|filter| filter.call(exception_to_data(exception))}
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def ignore_user_agent? #:nodoc:
|
|
268
|
+
# Rails 1.2.6 doesn't have request.user_agent, so check for it here
|
|
269
|
+
user_agent = request.respond_to?(:user_agent) ? request.user_agent : request.env["HTTP_USER_AGENT"]
|
|
270
|
+
HoptoadNotifier.ignore_user_agent.flatten.any? { |ua| ua === user_agent }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def exception_to_data exception #:nodoc:
|
|
274
|
+
data = {
|
|
275
|
+
:api_key => HoptoadNotifier.api_key,
|
|
276
|
+
:error_class => exception.class.name,
|
|
277
|
+
:error_message => "#{exception.class.name}: #{exception.message}",
|
|
278
|
+
:backtrace => exception.backtrace,
|
|
279
|
+
:environment => ENV.to_hash
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if self.respond_to? :request
|
|
283
|
+
data[:request] = {
|
|
284
|
+
:params => request.parameters.to_hash,
|
|
285
|
+
:rails_root => File.expand_path(RAILS_ROOT),
|
|
286
|
+
:url => "#{request.protocol}#{request.host}#{request.request_uri}"
|
|
287
|
+
}
|
|
288
|
+
data[:environment].merge!(request.env.to_hash)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
if self.respond_to? :session
|
|
292
|
+
data[:session] = {
|
|
293
|
+
:key => session.instance_variable_get("@session_id"),
|
|
294
|
+
:data => session.respond_to?(:to_hash) ?
|
|
295
|
+
session.to_hash :
|
|
296
|
+
session.instance_variable_get("@data")
|
|
297
|
+
}
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
data
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def normalize_notice(notice) #:nodoc:
|
|
304
|
+
case notice
|
|
305
|
+
when Hash
|
|
306
|
+
HoptoadNotifier.default_notice_options.merge(notice)
|
|
307
|
+
when Exception
|
|
308
|
+
HoptoadNotifier.default_notice_options.merge(exception_to_data(notice))
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def clean_notice(notice) #:nodoc:
|
|
313
|
+
notice[:backtrace] = clean_hoptoad_backtrace(notice[:backtrace])
|
|
314
|
+
if notice[:request].is_a?(Hash) && notice[:request][:params].is_a?(Hash)
|
|
315
|
+
notice[:request][:params] = filter_parameters(notice[:request][:params]) if respond_to?(:filter_parameters)
|
|
316
|
+
notice[:request][:params] = clean_hoptoad_params(notice[:request][:params])
|
|
317
|
+
end
|
|
318
|
+
if notice[:environment].is_a?(Hash)
|
|
319
|
+
notice[:environment] = filter_parameters(notice[:environment]) if respond_to?(:filter_parameters)
|
|
320
|
+
notice[:environment] = clean_hoptoad_environment(notice[:environment])
|
|
321
|
+
end
|
|
322
|
+
clean_non_serializable_data(notice)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def log(level, message, response = nil)
|
|
326
|
+
logger.send level, LOG_PREFIX + message if logger
|
|
327
|
+
HoptoadNotifier.report_environment_info
|
|
328
|
+
HoptoadNotifier.report_response_body(response.body) if response && response.respond_to?(:body)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def send_to_hoptoad data #:nodoc:
|
|
332
|
+
url = HoptoadNotifier.url
|
|
333
|
+
http = Net::HTTP::Proxy(HoptoadNotifier.proxy_host,
|
|
334
|
+
HoptoadNotifier.proxy_port,
|
|
335
|
+
HoptoadNotifier.proxy_user,
|
|
336
|
+
HoptoadNotifier.proxy_pass).new(url.host, url.port)
|
|
337
|
+
|
|
338
|
+
http.use_ssl = true
|
|
339
|
+
http.read_timeout = HoptoadNotifier.http_read_timeout
|
|
340
|
+
http.open_timeout = HoptoadNotifier.http_open_timeout
|
|
341
|
+
http.use_ssl = !!HoptoadNotifier.secure
|
|
342
|
+
|
|
343
|
+
response = begin
|
|
344
|
+
http.post(url.path, stringify_keys(data).to_yaml, HEADERS)
|
|
345
|
+
rescue TimeoutError => e
|
|
346
|
+
log :error, "Timeout while contacting the Hoptoad server."
|
|
347
|
+
nil
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
case response
|
|
351
|
+
when Net::HTTPSuccess then
|
|
352
|
+
log :info, "Success: #{response.class}", response
|
|
353
|
+
else
|
|
354
|
+
log :error, "Failure: #{response.class}", response
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def clean_hoptoad_backtrace backtrace #:nodoc:
|
|
359
|
+
if backtrace.to_a.size == 1
|
|
360
|
+
backtrace = backtrace.to_a.first.split(/\n\s*/)
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
filtered = backtrace.to_a.map do |line|
|
|
364
|
+
HoptoadNotifier.backtrace_filters.inject(line) do |line, proc|
|
|
365
|
+
proc.call(line)
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
filtered.compact
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def clean_hoptoad_params params #:nodoc:
|
|
373
|
+
params.each do |k, v|
|
|
374
|
+
params[k] = "[FILTERED]" if HoptoadNotifier.params_filters.any? do |filter|
|
|
375
|
+
k.to_s.match(/#{filter}/)
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def clean_hoptoad_environment env #:nodoc:
|
|
381
|
+
env.each do |k, v|
|
|
382
|
+
env[k] = "[FILTERED]" if HoptoadNotifier.environment_filters.any? do |filter|
|
|
383
|
+
k.to_s.match(/#{filter}/)
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def clean_non_serializable_data(data) #:nodoc:
|
|
389
|
+
case data
|
|
390
|
+
when Hash
|
|
391
|
+
data.inject({}) do |result, (key, value)|
|
|
392
|
+
result.update(key => clean_non_serializable_data(value))
|
|
393
|
+
end
|
|
394
|
+
when Fixnum, Array, String, Bignum
|
|
395
|
+
data
|
|
396
|
+
else
|
|
397
|
+
data.to_s
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def stringify_keys(hash) #:nodoc:
|
|
402
|
+
hash.inject({}) do |h, pair|
|
|
403
|
+
h[pair.first.to_s] = pair.last.is_a?(Hash) ? stringify_keys(pair.last) : pair.last
|
|
404
|
+
h
|
|
405
|
+
end
|
|
406
|
+
end
|
|
407
|
+
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# A dummy class for sending notifications manually outside of a controller.
|
|
411
|
+
class Sender
|
|
412
|
+
def rescue_action_in_public(exception)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
include HoptoadNotifier::Catcher
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|