diff --git a/Gemfile b/Gemfile index bb142816d..6484c2565 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,9 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '5.0.0.1' +gem 'actioncable', '5.0.0.1' +gem 'redis' + # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets @@ -116,6 +119,8 @@ group :development do # Access an IRB console on exception pages or by using <%= console %> in views gem 'web-console' + + gem 'rack-handlers' end group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index 3d8969e9e..ebf23e02c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -417,6 +417,8 @@ GEM pry (~> 0.10) public_suffix (2.0.4) rack (2.0.1) + rack-handlers (0.7.3) + rack rack-oauth2 (1.4.0) activesupport (>= 2.3) attr_required (>= 0.0.5) @@ -465,6 +467,7 @@ GEM nokogiri (~> 1.5) trollop (~> 2.1) rdoc (4.3.0) + redis (3.3.0) ref (2.0.0) request_store (1.3.1) responders (2.3.0) @@ -624,6 +627,7 @@ PLATFORMS ruby DEPENDENCIES + actioncable (= 5.0.0.1) active_model_serializers apipie-rails as_csv @@ -665,9 +669,11 @@ DEPENDENCIES pg poltergeist pry-byebug + rack-handlers railroady rails (= 5.0.0.1) rails-controller-testing + redis rest-client rgeo-geojson rspec-rails (~> 3.0) diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js new file mode 100644 index 000000000..9139c80fd --- /dev/null +++ b/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the rails generate channel command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 000000000..d56fa30f4 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading. +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 000000000..b4f41389a --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading. +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 000000000..a009ace51 --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 000000000..10a4cba84 --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index cdb69731d..6cfc3ab0a 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -9,6 +9,7 @@ = javascript_include_tag 'application', 'data-turbolinks-track' => true = csrf_meta_tags + = action_cable_meta_tag %body = render partial: 'layouts/support_navigator_banner' #beta{class:(Rails.env == 'production' ? '' : 'beta_staging')} diff --git a/config.ru b/config.ru index bd83b2541..584d0390c 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,8 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) + +# Action Cable requires that all classes are loaded in advance +Rails.application.eager_load! + run Rails.application diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 000000000..1aeb76f7c --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +production: + adapter: redis + url: redis://localhost:6379 + +development: + adapter: redis + url: redis://localhost:6379 + +test: + adapter: async diff --git a/config/environments/development.rb b/config/environments/development.rb index f7174bfa2..4b96a6c33 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -45,5 +45,5 @@ Rails.application.configure do # Raises error for missing translations # config.action_view.raise_on_missing_translations = true - + config.action_cable.url = "ws://localhost:3000/cable" end diff --git a/config/routes.rb b/config/routes.rb index 58d2811dc..aaef99490 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -202,4 +202,6 @@ Rails.application.routes.draw do end apipie + + mount ActionCable.server => '/cable' end diff --git a/config/unicorn.rb b/config/unicorn.rb new file mode 100644 index 000000000..88a5d746a --- /dev/null +++ b/config/unicorn.rb @@ -0,0 +1,109 @@ +# Sample verbose configuration file for Unicorn (not Rack) +# +# This configuration file documents many features of Unicorn +# that may not be needed for some applications. See +# http://unicorn.bogomips.org/examples/unicorn.conf.minimal.rb +# for a much simpler configuration file. +# +# See http://unicorn.bogomips.org/Unicorn/Configurator.html for complete +# documentation. + + + +# Use at least one worker per core if you're on a dedicated server, +# more will usually help for _short_ waits on databases/caches. +worker_processes 2 + +# Since Unicorn is never exposed to outside clients, it does not need to +# run on the standard HTTP port (80), there is no reason to start Unicorn +# as root unless it's from system init scripts. +# If running the master process as root and the workers as an unprivileged +# user, do this to switch euid/egid in the workers (also chowns logs): +# user "unprivileged_user", "unprivileged_group" + +# Help ensure your application will always spawn in the symlinked +# "current" directory that Capistrano sets up. + +# listen on both a Unix domain socket and a TCP port, +# we use a shorter backlog for quicker failover when busy +listen "127.0.0.1:3000", :tcp_nopush => true + +# nuke workers after 30 seconds instead of 60 seconds (the default) +timeout 30 + +# By default, the Unicorn logger will write to stderr. +# Additionally, ome applications/frameworks log to stderr or stdout, +# so prevent them from going to /dev/null when daemonized here: + +# combine Ruby 2.0.0dev or REE with "preload_app true" for memory savings +# http://rubyenterpriseedition.com/faq.html#adapt_apps_for_cow +preload_app true +GC.respond_to?(:copy_on_write_friendly=) and + GC.copy_on_write_friendly = true + +# Enable this flag to have unicorn test client connections by writing the +# beginning of the HTTP headers before calling the application. This +# prevents calling the application for connections that have disconnected +# while queued. This is only guaranteed to detect clients on the same +# host unicorn runs on, and unlikely to detect disconnects even on a +# fast LAN. +check_client_connection false + +# local variable to guard against running a hook multiple times +run_once = true + + +before_fork do |server, worker| + # the following is highly recomended for Rails + "preload_app true" + # as there's no need for the master process to hold a connection + defined?(ActiveRecord::Base) and + ActiveRecord::Base.connection.disconnect! + + # Occasionally, it may be necessary to run non-idempotent code in the + # master before forking. Keep in mind the above disconnect! example + # is idempotent and does not need a guard. + if run_once + # do_something_once_here ... + run_once = false # prevent from firing again + end + + # The following is only recommended for memory/DB-constrained + # installations. It is not needed if your system can house + # twice as many worker_processes as you have configured. + # + # # This allows a new master process to incrementally + # # phase out the old master process with SIGTTOU to avoid a + # # thundering herd (especially in the "preload_app false" case) + # # when doing a transparent upgrade. The last worker spawned + # # will then kill off the old master process with a SIGQUIT. + old_pid = "#{server.config[:pid]}.oldbin" + if old_pid != server.pid + begin + sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU + Process.kill(sig, File.read(old_pid).to_i) + rescue Errno::ENOENT, Errno::ESRCH + end + end + # + # Throttle the master from forking too quickly by sleeping. Due + # to the implementation of standard Unix signal handlers, this + # helps (but does not completely) prevent identical, repeated signals + # from being lost when the receiving process is busy. + sleep 1 +end + +after_fork do |server, worker| + # per-process listener ports for debugging/admin/migrations + # addr = "127.0.0.1:#{9293 + worker.nr}" + # server.listen(addr, :tries => -1, :delay => 5, :tcp_nopush => true) + + # the following is *required* for Rails + "preload_app true", + defined?(ActiveRecord::Base) and + ActiveRecord::Base.establish_connection + + # if preload_app is true, then you may also want to check and + # restart any other shared sockets/descriptors such as Memcached, + # and Redis. TokyoCabinet file handles are safe to reuse + # between any number of forked children (assuming your kernel + # correctly implements pread()/pwrite() system calls) +end