diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..e85bc9f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,35 @@
+language: ruby
+
+before_install:
+  # https://github.com/danmayer/coverband/issues/162#issuecomment-452173268
+  - rm /home/travis/.rvm/gems/*/specifications/bundler-2.*.gemspec || true
+  - gem install bundler -v '<2'
+
+bundler_args: --without development --jobs=3 --retry=3 --path=../vendor/bundle
+
+cache: bundler
+
+env:
+  matrix:
+    - JQUERY_VERSION=
+
+rvm:
+  - 2.5.5
+
+gemfile:
+  - gemfiles/rails_3.2.gemfile
+  - gemfiles/rails_4.2.gemfile
+  - gemfiles/rails_5.2.gemfile
+  - gemfiles/rails_6.0.gemfile
+
+dist: trusty
+
+sudo: false
+
+matrix:
+  include:
+    - env: JQUERY_VERSION=2
+      gemfile: gemfiles/rails_6.0.gemfile
+    - env: JQUERY_VERSION=3
+      gemfile: gemfiles/rails_6.0.gemfile
+  fast_finish: true
diff --git a/Appraisals b/Appraisals
new file mode 100644
index 0000000..d0354cb
--- /dev/null
+++ b/Appraisals
@@ -0,0 +1,25 @@
+appraise "rails-3.2" do
+  gem 'rails', '~> 3.2.0'
+  gem 'test-unit', '~> 3.0'
+  gem "strong_parameters"
+
+  group :development, :test do
+    gem 'sqlite3', '~> 1.3.5'
+  end
+end
+
+appraise "rails-4.2" do
+  gem 'rails', '~> 4.2.0'
+
+  group :development, :test do
+    gem 'sqlite3', '~> 1.3.6'
+  end
+end
+
+appraise "rails-5.2" do
+  gem 'rails', '~> 5.2.0'
+end
+
+appraise "rails-6.0" do
+  gem 'rails', '~> 6.0.0.rc1'
+end
diff --git a/Gemfile b/Gemfile
index 61fcdac..66d453f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,9 +2,22 @@ source 'https://rubygems.org'
 
 group :development do
   gem 'rake'
-  gem 'jeweler'
+  gem 'jeweler', github: 'technicalpickles/jeweler'
   # This conflicts with jeweler gemspec generation,
   # causes dependencies to be added to gemspec recursively
   #gemspec
 end
 
+group :development, :test do
+  gem 'appraisal'
+  gem 'jquery-rails'
+  gem 'sqlite3'
+  gem 'paperclip'
+  gem 'remotipart', path: '.'
+end
+
+group :test do
+  gem 'database_cleaner'
+  gem 'poltergeist'
+  gem 'rspec-rails'
+end
diff --git a/Gemfile.lock b/Gemfile.lock
deleted file mode 100644
index 5c22cbd..0000000
--- a/Gemfile.lock
+++ /dev/null
@@ -1,20 +0,0 @@
-GEM
-  remote: https://rubygems.org/
-  specs:
-    git (1.2.5)
-    jeweler (1.8.4)
-      bundler (~> 1.0)
-      git (>= 1.2.5)
-      rake
-      rdoc
-    json (1.7.6)
-    rake (10.0.3)
-    rdoc (3.12)
-      json (~> 1.4)
-
-PLATFORMS
-  ruby
-
-DEPENDENCIES
-  jeweler
-  rake
diff --git a/History.rdoc b/History.rdoc
index a12c3af..136b79c 100644
--- a/History.rdoc
+++ b/History.rdoc
@@ -1,5 +1,39 @@
 = History
 
+=== 1.4.4 / 2019-12-29
+
+* Fixed Rails 6 autoloading deprecation.
+* Fixed ActiveScaffold incompatibility.
+
+=== 1.4.3 / 2019-05-23
+
+* Fixed xhr.responseText not being populated.
+* Security: fixed cross-site scripting vulnerability when server renders user input.
+
+=== 1.4.2 / 2018-04-25
+
+* Fixed ActionView::Template::Error in web-console.
+
+=== 1.4.0 / 2018-04-09
+
+* Added jQuery 3 compatibility.
+* Changed to use ActiveSupport lazy load hooks on initialization.
+* Changed jQuery iframe-transport to v1.0.1.
+* Fixed to preserve original return value of render call for non-remotipart requests.
+* Fixed remote javascript with &quot; not being executed.
+* Fixed method signature of render_with_remotipart, making RJS templates not usable.
+
+=== 1.3.1 / 2016-10-06
+
+* Fixed remote form submit not working with Firefox 49.
+
+=== 1.3.0 / 2016-09-14
+
+* Added Rails 5 support.
+* Added an event `ajax:remotipartComplete`, which will be fired when the ajax upload completes.
+* Changed to preserve original input files upon submit.
+* Fixed TypeError when POST body is empty with Rails 3.
+
 === 1.2.1 / 2013-07-07
 
 * Added automatic authenticity_token detection and appending to iframe submission.
diff --git a/LICENSE b/LICENSE
index ac758b8..86b9f50 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,7 @@
+============================================
+Remotipart is licensed under the MIT License
+============================================
+
 Copyright (c) 2009 Greg Leppert
 
 Permission is hereby granted, free of charge, to any person obtaining
diff --git a/README.rdoc b/README.rdoc
index 73b775d..b8f22f3 100644
--- a/README.rdoc
+++ b/README.rdoc
@@ -1,4 +1,8 @@
-= Remotipart: Rails jQuery File Upload
+= Remotipart: Rails jQuery File Uploads
+
+{<img src="https://badge.fury.io/rb/remotipart.svg" alt="Gem Version" />}[https://badge.fury.io/rb/remotipart]
+{<img src="https://travis-ci.com/JangoSteve/remotipart.svg?branch=master" alt="Build Status" />}[https://travis-ci.com/JangoSteve/remotipart]
+{<img src="https://codeclimate.com/github/JangoSteve/remotipart/badges/gpa.svg" />}[https://codeclimate.com/github/JangoSteve/remotipart]
 
 Remotipart is a Ruby on Rails gem enabling AJAX file uploads with jQuery in Rails 3 and Rails 4 remote forms.
 This gem augments the native Rails jQuery remote form functionality enabling asynchronous file uploads with little to no modification to your application.
@@ -9,7 +13,9 @@ This gem augments the native Rails jQuery remote form functionality enabling asy
 == Dependencies
 
 * {Rails 3 or Rails 4}[http://github.com/rails/rails]
-* {The jquery-rails gem}[http://rubygems.org/gems/jquery-rails] (included in Rails 3 and Rails 4 by default), which installs {jQuery}[http://jquery.com] and the {Rails jQuery driver (jquery-ujs)}[https://github.com/rails/jquery-ujs]
+* {The jquery-rails gem}[http://rubygems.org/gems/jquery-rails]
+
+<em>The jquery-rails gem is included in Rails 3 and Rails 4 by default, and installs {jQuery}[http://jquery.com] and the {Rails jQuery UJS driver (jquery-ujs)}[https://github.com/rails/jquery-ujs]</em>
 
 == Installation
 
@@ -29,7 +35,7 @@ make sure you have a supported jquery-ujs (rails.js or jquery_ujs.js) version fr
 
    bundle install
 
-=== Rails 3.1
+=== Rails 3.1 and Rails 4
 
 [2.]
   The necessary js files will automatically be added to the asset pipeline, so add the following to app/assets/javascripts/application.js (right after <tt>//= require jquery_ujs</tt>):
@@ -53,7 +59,7 @@ make sure you have a supported jquery-ujs (rails.js or jquery_ujs.js) version fr
 * For multipart / forms with file inputs, set your form_for to remote as you would for a normal ajax form:
    :remote => true
 * When Javascript is enabled in the user's browser, the form, including the file, will be submitted asynchronously to your controller with:
-   :format == 'js'
+   :format => 'js'
 * If you need to determine if a particular request was made via a remotipart-enabled form...
   * from your Rails controller or view:
 
@@ -63,10 +69,16 @@ make sure you have a supported jquery-ujs (rails.js or jquery_ujs.js) version fr
       $(form).bind("ajax:success", function(){
         if ( $(this).data('remotipartSubmitted') )
       });
+* If you want to be notified when the upload is complete (which can be either success or error)
+  * from your javascript:
 
+      $(form).on("ajax:remotipartComplete", function(e, data){
+        console.log(e, data)
+      });
+      
 === Example
 
-sample_layout.html.erb
+<tt>sample_layout.html.erb</tt>
   <%= form_for @sample, :html => { :multipart => true }, :remote => true do |f| %>
     <div class="field">
       <%= f.label :file %>
@@ -77,7 +89,7 @@ sample_layout.html.erb
     </div>
   <% end %>
 
-sample_controller.rb
+<tt>sample_controller.rb</tt>
   def create
     respond_to do |format|
       if @sample.save
@@ -86,7 +98,7 @@ sample_controller.rb
     end
   end
 
-create.js.erb
+<tt>create.js.erb</tt>
   // Display a Javascript alert
   alert('success!');
   <% if remotipart_submitted? %>
@@ -95,6 +107,21 @@ create.js.erb
     alert('submitted via native jquery-ujs')
   <% end %>
 
+The content type requested from the application can be overridden via the <tt>data-type</tt> HTML5 attribute:
+
+<tt>sample_layout2.html.erb</tt>
+  <%= form_for @sample, :html => { :multipart => true }, :remote => true, :data => { :type => :html } do |f| %>
+    <div class="field">
+      <%= f.label :file %>
+      <%= f.file_field :file %>
+    </div>
+    <div class="actions">
+      <%= f.submit %>
+    </div>
+  <% end %>
+
+In this case, the application should serve HTML using a <tt>create.html.erb</tt> template instead of JavaScript.
+
 == Note on Patches/Pull Requests
 
 <b>If you have a general improvement, optimization, or refactoring, please {read this first}[https://github.com/formasfunction/remotipart/wiki/Refactoring-and-Improving-Remotipart].</b>
@@ -114,7 +141,7 @@ to test the file upload functionality of remotipart (since the browsers running
 upload input using javascript). So, instead we created a demo Rails app using remotipart with all remotipart functionality tested using RSpec and Capybara.
 
 * {Demo Rails App with Tests}[https://github.com/JangoSteve/Rails-jQuery-Demo/tree/remotipart]
-  * {Tests}[https://github.com/JangoSteve/Rails-jQuery-Demo/blob/remotipart/spec/integration/comments_spec.rb]
+  * {Tests}[https://github.com/JangoSteve/Rails-jQuery-Demo/blob/master/spec/features/comments_spec.rb]
 
 To run tests:
 
diff --git a/Rakefile b/Rakefile
index 3dc0c10..7e9449c 100644
--- a/Rakefile
+++ b/Rakefile
@@ -21,13 +21,6 @@ rescue LoadError
   puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
 end
 
-require 'rake/testtask'
-Rake::TestTask.new(:test) do |test|
-  test.libs << 'lib' << 'test'
-  test.pattern = 'test/**/test_*.rb'
-  test.verbose = true
-end
-
 begin
   require 'rcov/rcovtask'
   Rcov::RcovTask.new do |test|
@@ -51,3 +44,8 @@ Rake::RDocTask.new do |rdoc|
   rdoc.rdoc_files.include('README*')
   rdoc.rdoc_files.include('lib/**/*.rb')
 end
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec)
+
+task default: :spec
diff --git a/debian/changelog b/debian/changelog
index 48d4ec2..914c362 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-ruby-remotipart (1.2.1-3) UNRELEASED; urgency=medium
+ruby-remotipart (1.4.4-1) UNRELEASED; urgency=medium
 
   [ Cédric Boutillier ]
   * Bump debhelper compatibility level to 9
@@ -19,8 +19,9 @@ ruby-remotipart (1.2.1-3) UNRELEASED; urgency=medium
   * Use canonical URL in Vcs-Git.
   * Update watch file format version to 4.
   * Bump debhelper from old 12 to 13.
+  * New upstream release.
 
- -- Utkarsh Gupta <guptautkarsh2102@gmail.com>  Tue, 13 Aug 2019 07:09:59 +0530
+ -- Utkarsh Gupta <guptautkarsh2102@gmail.com>  Sun, 15 May 2022 15:03:43 -0000
 
 ruby-remotipart (1.2.1-2) unstable; urgency=medium
 
diff --git a/debian/patches/engine-root.patch b/debian/patches/engine-root.patch
index 81c96e4..230ab7d 100644
--- a/debian/patches/engine-root.patch
+++ b/debian/patches/engine-root.patch
@@ -8,5 +8,5 @@ Index: ruby-remotipart/lib/remotipart/rails/engine.rb
      class Engine < ::Rails::Engine
 +      config.root = '/usr/share/ruby-remotipart'
        initializer "remotipart.view_helper" do
-         ActionView::Base.send :include, RequestHelper
-         ActionView::Base.send :include, ViewHelper
+         ActiveSupport.on_load :action_view do
+           include RequestHelper
diff --git a/gemfiles/rails_3.2.gemfile b/gemfiles/rails_3.2.gemfile
new file mode 100644
index 0000000..791332c
--- /dev/null
+++ b/gemfiles/rails_3.2.gemfile
@@ -0,0 +1,26 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rails", "~> 3.2.0"
+gem "test-unit", "~> 3.0"
+gem "strong_parameters"
+
+group :development do
+  gem "rake"
+  gem "jeweler"
+end
+
+group :development, :test do
+  gem "appraisal"
+  gem "jquery-rails"
+  gem "sqlite3", "~> 1.3.5"
+  gem "paperclip"
+  gem "remotipart", path: "../"
+end
+
+group :test do
+  gem "database_cleaner"
+  gem "poltergeist"
+  gem "rspec-rails"
+end
diff --git a/gemfiles/rails_4.2.gemfile b/gemfiles/rails_4.2.gemfile
new file mode 100644
index 0000000..4b7d147
--- /dev/null
+++ b/gemfiles/rails_4.2.gemfile
@@ -0,0 +1,24 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rails", "~> 4.2.0"
+
+group :development do
+  gem "rake"
+  gem "jeweler"
+end
+
+group :development, :test do
+  gem "appraisal"
+  gem "jquery-rails"
+  gem "sqlite3", "~> 1.3.6"
+  gem "paperclip"
+  gem "remotipart", path: "../"
+end
+
+group :test do
+  gem "database_cleaner"
+  gem "poltergeist"
+  gem "rspec-rails"
+end
diff --git a/gemfiles/rails_5.2.gemfile b/gemfiles/rails_5.2.gemfile
new file mode 100644
index 0000000..e0cc32a
--- /dev/null
+++ b/gemfiles/rails_5.2.gemfile
@@ -0,0 +1,24 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rails", "~> 5.2.0"
+
+group :development do
+  gem "rake"
+  gem "jeweler"
+end
+
+group :development, :test do
+  gem "appraisal"
+  gem "jquery-rails"
+  gem "sqlite3"
+  gem "paperclip"
+  gem "remotipart", path: "../"
+end
+
+group :test do
+  gem "database_cleaner"
+  gem "poltergeist"
+  gem "rspec-rails"
+end
diff --git a/gemfiles/rails_6.0.gemfile b/gemfiles/rails_6.0.gemfile
new file mode 100644
index 0000000..36d8d37
--- /dev/null
+++ b/gemfiles/rails_6.0.gemfile
@@ -0,0 +1,24 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rails", "~> 6.0.0.rc1"
+
+group :development do
+  gem "rake"
+  gem "jeweler"
+end
+
+group :development, :test do
+  gem "appraisal"
+  gem "jquery-rails"
+  gem "sqlite3"
+  gem "paperclip"
+  gem "remotipart", path: "../"
+end
+
+group :test do
+  gem "database_cleaner"
+  gem "poltergeist"
+  gem "rspec-rails"
+end
diff --git a/lib/remotipart/middleware.rb b/lib/remotipart/middleware.rb
index 41f00f4..50baf39 100644
--- a/lib/remotipart/middleware.rb
+++ b/lib/remotipart/middleware.rb
@@ -1,6 +1,6 @@
 module Remotipart
 
-  # A middleware to look for our form parameters and 
+  # A middleware to look for our form parameters and
   # encourage Rails to respond with the requested format
   class Middleware
     def initialize app
@@ -9,7 +9,12 @@ module Remotipart
 
     def call env
       # Get request params
-      params = Rack::Request.new(env).params
+      begin
+        params = Rack::Request.new(env).params
+      rescue TypeError => e
+        ::Rails.logger.warn e.message
+        ::Rails.logger.warn e.backtrace.join("\n")
+      end
 
       if params
         # This was using an iframe transport, and is therefore an XHR
@@ -19,8 +24,8 @@ module Remotipart
         end
 
         # Override the accepted format, because it isn't what we really want
-        if params['X-Http-Accept']
-          env['HTTP_ACCEPT'] = params['X-Http-Accept']
+        if params['X-HTTP-Accept']
+          env['HTTP_ACCEPT'] = params['X-HTTP-Accept']
         end
       end
 
diff --git a/lib/remotipart/rails/engine.rb b/lib/remotipart/rails/engine.rb
index 30518db..e38ce70 100644
--- a/lib/remotipart/rails/engine.rb
+++ b/lib/remotipart/rails/engine.rb
@@ -4,17 +4,27 @@ module Remotipart
 
     class Engine < ::Rails::Engine
       initializer "remotipart.view_helper" do
-        ActionView::Base.send :include, RequestHelper
-        ActionView::Base.send :include, ViewHelper
+        ActiveSupport.on_load :action_view do
+          include RequestHelper
+          include ViewHelper
+        end
       end
 
       initializer "remotipart.controller_helper" do
-        ActionController::Base.send :include, RequestHelper
-        ActionController::Base.send :include, RenderOverrides
+        ActiveSupport.on_load :action_controller do
+          include RequestHelper
+          include RenderOverrides
+        end
       end
 
       initializer "remotipart.include_middelware" do
-        config.app_middleware.insert_after ActionDispatch::ParamsParser, Middleware
+        if ::Rails.version >= '5'
+          # Rails 5 no longer instantiates ActionDispatch::ParamsParser
+          # https://github.com/rails/rails/commit/a1ced8b52ce60d0634e65aa36cb89f015f9f543d
+          config.app_middleware.use Middleware
+        else
+          config.app_middleware.insert_after ActionDispatch::ParamsParser, Middleware
+        end
       end
     end
 
diff --git a/lib/remotipart/rails/railtie.rb b/lib/remotipart/rails/railtie.rb
index be4db2c..db1e9ee 100644
--- a/lib/remotipart/rails/railtie.rb
+++ b/lib/remotipart/rails/railtie.rb
@@ -23,13 +23,17 @@ module Remotipart
       end
 
       initializer "remotipart.view_helper" do
-        ActionView::Base.send :include, RequestHelper
-        ActionView::Base.send :include, ViewHelper
+        ActiveSupport.on_load(:action_view) do
+          include RequestHelper
+          include ViewHelper
+        end
       end
 
       initializer "remotipart.controller_helper" do
-        ActionController::Base.send :include, RequestHelper
-        ActionController::Base.send :include, RenderOverrides
+        ActiveSupport.on_load(:action_controller) do
+          include RequestHelper
+          include RenderOverrides
+        end
       end
 
       initializer "remotipart.include_middelware" do
diff --git a/lib/remotipart/rails/version.rb b/lib/remotipart/rails/version.rb
index 114b363..f26afc3 100644
--- a/lib/remotipart/rails/version.rb
+++ b/lib/remotipart/rails/version.rb
@@ -1,6 +1,6 @@
 module Remotipart
   module Rails
-    VERSION = "1.2.1"
-    IFRAMETRANSPORT_VERSION = "02.06.2013"
+    VERSION = "1.4.4"
+    IFRAMETRANSPORT_VERSION = "1.0.1.remotipart"
   end
 end
diff --git a/lib/remotipart/render_overrides.rb b/lib/remotipart/render_overrides.rb
index f91f491..10e38ca 100644
--- a/lib/remotipart/render_overrides.rb
+++ b/lib/remotipart/render_overrides.rb
@@ -3,21 +3,43 @@ module Remotipart
   # as expected by iframe-transport.
   module RenderOverrides
     include ERB::Util
+    include ActionView::Helpers::JavaScriptHelper
 
     def self.included(base)
       base.class_eval do
-        alias_method_chain :render, :remotipart
+        if respond_to? :prepend
+          base.prepend Prependable
+        else
+          base.include Includable
+          # Do not use alias_method_chain for compatibility
+          alias render_without_remotipart render
+          alias render render_with_remotipart
+        end
       end
     end
 
-    def render_with_remotipart *args
-      render_without_remotipart *args
+    module Prependable
+      def render(*args, &block)
+        treat_render_for_remotipart super(*args, &block)
+      end
+    end
+
+    module Includable
+      def render_with_remotipart(*args, &block)
+        treat_render_for_remotipart render_without_remotipart(*args, &block)
+      end
+    end
+
+    private
+
+    def treat_render_for_remotipart(render_return_value)
       if remotipart_submitted?
-        textarea_body = response.content_type == 'text/html' ? html_escape(response.body) : response.body
-        response.body = %{<textarea data-type=\"#{response.content_type}\" data-status=\"#{response.response_code}\" data-statusText=\"#{response.message}\">#{textarea_body}</textarea>}
-        response.content_type = Mime::HTML
+        response.body = %{<script type="text/javascript">try{window.parent.document;}catch(err){document.domain=document.domain;}</script><textarea data-type="#{response.content_type}" data-status="#{response.response_code}" data-statusText="#{response.message}"></textarea><script type="text/javascript">document.querySelector("textarea").value="#{escape_javascript(response.body)}";</script>}
+        response.content_type = ::Rails.version >= '5' ? Mime[:html] : Mime::HTML
+        response_body
+      else
+        render_return_value
       end
-      response_body
     end
   end
 end
diff --git a/lib/remotipart/request_helper.rb b/lib/remotipart/request_helper.rb
index b8a5ed3..52e0efe 100644
--- a/lib/remotipart/request_helper.rb
+++ b/lib/remotipart/request_helper.rb
@@ -2,6 +2,8 @@ module Remotipart
   module RequestHelper
     def remotipart_submitted?
       params[:remotipart_submitted] ? true : false
+    rescue
+      false
     end
     
     alias :remotipart_requested? :remotipart_submitted?
diff --git a/lib/remotipart/view_helper.rb b/lib/remotipart/view_helper.rb
index 0330388..531f379 100644
--- a/lib/remotipart/view_helper.rb
+++ b/lib/remotipart/view_helper.rb
@@ -1,9 +1,11 @@
 module Remotipart
   module ViewHelper
+
     #No longer used
     #Retrained to prevent issues while updating
     def remotipart_response(options = {}, &block)
       with_output_buffer(&block)
     end
+
   end
 end
diff --git a/metadata.yml b/metadata.yml
deleted file mode 100644
index 5635a12..0000000
--- a/metadata.yml
+++ /dev/null
@@ -1,100 +0,0 @@
---- !ruby/object:Gem::Specification
-name: remotipart
-version: !ruby/object:Gem::Version
-  version: 1.2.1
-  prerelease: 
-platform: ruby
-authors:
-- Greg Leppert
-- Steve Schwartz
-autorequire: 
-bindir: bin
-cert_chain: []
-date: 2013-07-08 00:00:00.000000000Z
-dependencies:
-- !ruby/object:Gem::Dependency
-  name: rake
-  requirement: &70170920954340 !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ! '>='
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: *70170920954340
-- !ruby/object:Gem::Dependency
-  name: jeweler
-  requirement: &70170920953080 !ruby/object:Gem::Requirement
-    none: false
-    requirements:
-    - - ! '>='
-      - !ruby/object:Gem::Version
-        version: '0'
-  type: :development
-  prerelease: false
-  version_requirements: *70170920953080
-description: ! "Remotipart is a Ruby on Rails gem enabling remote multipart forms
-  (AJAX style file uploads) with jquery-rails.\n    This gem augments the native Rails
-  3 jQuery-UJS remote form function enabling asynchronous file uploads with little
-  to no modification to your application.\n    "
-email:
-- greg@formasfunction.com
-- steve@alfajango.com
-executables: []
-extensions: []
-extra_rdoc_files:
-- LICENSE
-- README.rdoc
-files:
-- .document
-- CONTRIBUTING.md
-- Gemfile
-- Gemfile.lock
-- History.rdoc
-- LICENSE
-- README.rdoc
-- Rakefile
-- VERSION_COMPATIBILITY.rdoc
-- lib/generators/remotipart/install/install_generator.rb
-- lib/remotipart.rb
-- lib/remotipart/middleware.rb
-- lib/remotipart/rails.rb
-- lib/remotipart/rails/engine.rb
-- lib/remotipart/rails/railtie.rb
-- lib/remotipart/rails/version.rb
-- lib/remotipart/render_overrides.rb
-- lib/remotipart/request_helper.rb
-- lib/remotipart/view_helper.rb
-- remotipart.gemspec
-- vendor/assets/javascripts/jquery.iframe-transport.js
-- vendor/assets/javascripts/jquery.remotipart.js
-homepage: http://opensource.alfajango.com/remotipart/
-licenses: []
-post_install_message: 
-rdoc_options: []
-require_paths:
-- lib
-required_ruby_version: !ruby/object:Gem::Requirement
-  none: false
-  requirements:
-  - - ! '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-      segments:
-      - 0
-      hash: -3061483236240277448
-required_rubygems_version: !ruby/object:Gem::Requirement
-  none: false
-  requirements:
-  - - ! '>='
-    - !ruby/object:Gem::Version
-      version: '0'
-requirements: []
-rubyforge_project: 
-rubygems_version: 1.8.15
-signing_key: 
-specification_version: 3
-summary: Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style
-  file uploads) with jquery-rails.
-test_files: []
diff --git a/remotipart.gemspec b/remotipart.gemspec
index c215e0b..ddd013f 100644
--- a/remotipart.gemspec
+++ b/remotipart.gemspec
@@ -2,30 +2,37 @@
 # DO NOT EDIT THIS FILE DIRECTLY
 # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
 # -*- encoding: utf-8 -*-
+# stub: remotipart 1.4.4 ruby lib
 
 Gem::Specification.new do |s|
-  s.name = "remotipart"
-  s.version = "1.2.1"
+  s.name = "remotipart".freeze
+  s.version = "1.4.4"
 
-  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
-  s.authors = ["Greg Leppert", "Steve Schwartz"]
-  s.date = "2013-07-08"
-  s.description = "Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails.\n    This gem augments the native Rails 3 jQuery-UJS remote form function enabling asynchronous file uploads with little to no modification to your application.\n    "
-  s.email = ["greg@formasfunction.com", "steve@alfajango.com"]
+  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
+  s.require_paths = ["lib".freeze]
+  s.authors = ["Greg Leppert".freeze, "Steve Schwartz".freeze]
+  s.date = "2019-12-29"
+  s.description = "Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails.\n    This gem augments the native Rails 3 jQuery-UJS remote form function enabling asynchronous file uploads with little to no modification to your application.\n    ".freeze
+  s.email = ["greg@formasfunction.com".freeze, "steve@alfajango.com".freeze]
   s.extra_rdoc_files = [
     "LICENSE",
     "README.rdoc"
   ]
   s.files = [
     ".document",
+    ".travis.yml",
+    "Appraisals",
     "CONTRIBUTING.md",
     "Gemfile",
-    "Gemfile.lock",
     "History.rdoc",
     "LICENSE",
     "README.rdoc",
     "Rakefile",
     "VERSION_COMPATIBILITY.rdoc",
+    "gemfiles/rails_3.2.gemfile",
+    "gemfiles/rails_4.2.gemfile",
+    "gemfiles/rails_5.2.gemfile",
+    "gemfiles/rails_6.0.gemfile",
     "lib/generators/remotipart/install/install_generator.rb",
     "lib/remotipart.rb",
     "lib/remotipart/middleware.rb",
@@ -37,27 +44,96 @@ Gem::Specification.new do |s|
     "lib/remotipart/request_helper.rb",
     "lib/remotipart/view_helper.rb",
     "remotipart.gemspec",
+    "spec/dummy_app/.gitignore",
+    "spec/dummy_app/Rakefile",
+    "spec/dummy_app/app/assets/config/manifest.js",
+    "spec/dummy_app/app/assets/images/rails.png",
+    "spec/dummy_app/app/assets/javascripts/application.js.erb",
+    "spec/dummy_app/app/assets/javascripts/comments.js",
+    "spec/dummy_app/app/assets/stylesheets/application.css",
+    "spec/dummy_app/app/assets/stylesheets/scaffold.css",
+    "spec/dummy_app/app/controllers/application_controller.rb",
+    "spec/dummy_app/app/controllers/comments_controller.rb",
+    "spec/dummy_app/app/controllers/prepended_controller.rb",
+    "spec/dummy_app/app/helpers/application_helper.rb",
+    "spec/dummy_app/app/helpers/comments_helper.rb",
+    "spec/dummy_app/app/models/comment.rb",
+    "spec/dummy_app/app/views/comments/_comment.html.erb",
+    "spec/dummy_app/app/views/comments/_form.html.erb",
+    "spec/dummy_app/app/views/comments/_new_comment_links.html.erb",
+    "spec/dummy_app/app/views/comments/create.html.erb",
+    "spec/dummy_app/app/views/comments/create.js.erb",
+    "spec/dummy_app/app/views/comments/destroy.js.erb",
+    "spec/dummy_app/app/views/comments/edit.html.erb",
+    "spec/dummy_app/app/views/comments/escape_test.html.erb",
+    "spec/dummy_app/app/views/comments/index.html.erb",
+    "spec/dummy_app/app/views/comments/new.html.erb",
+    "spec/dummy_app/app/views/comments/show.html.erb",
+    "spec/dummy_app/app/views/layouts/application.html.erb",
+    "spec/dummy_app/app/views/prepended/show.html.erb",
+    "spec/dummy_app/bin/bundle",
+    "spec/dummy_app/bin/rails",
+    "spec/dummy_app/bin/rake",
+    "spec/dummy_app/bin/setup",
+    "spec/dummy_app/bin/update",
+    "spec/dummy_app/config.ru",
+    "spec/dummy_app/config/application.rb",
+    "spec/dummy_app/config/boot.rb",
+    "spec/dummy_app/config/database.yml",
+    "spec/dummy_app/config/environment.rb",
+    "spec/dummy_app/config/environments/development.rb",
+    "spec/dummy_app/config/environments/test.rb",
+    "spec/dummy_app/config/initializers/secret_token.rb",
+    "spec/dummy_app/config/routes.rb",
+    "spec/dummy_app/config/secrets.yml",
+    "spec/dummy_app/db/migrate/20110209210252_create_comments.rb",
+    "spec/dummy_app/db/migrate/20110209210315_add_attachment_to_comment.rb",
+    "spec/dummy_app/db/migrate/20110714205346_add_other_attachment_to_comment.rb",
+    "spec/dummy_app/db/schema.rb",
+    "spec/dummy_app/db/seeds.rb",
+    "spec/features/comments_spec.rb",
+    "spec/features/prepended_spec.rb",
+    "spec/fixtures/hi.txt",
+    "spec/fixtures/qr.jpg",
+    "spec/spec_helper.rb",
+    "spec/support/arel_helper.rb",
+    "spec/support/connection_helper.rb",
+    "spec/support/integration_helper.rb",
     "vendor/assets/javascripts/jquery.iframe-transport.js",
     "vendor/assets/javascripts/jquery.remotipart.js"
   ]
-  s.homepage = "http://opensource.alfajango.com/remotipart/"
-  s.require_paths = ["lib"]
-  s.rubygems_version = "1.8.15"
-  s.summary = "Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails."
+  s.homepage = "http://opensource.alfajango.com/remotipart/".freeze
+  s.rubygems_version = "3.0.3".freeze
+  s.summary = "Remotipart is a Ruby on Rails gem enabling remote multipart forms (AJAX style file uploads) with jquery-rails.".freeze
 
   if s.respond_to? :specification_version then
-    s.specification_version = 3
+    s.specification_version = 4
 
     if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
-      s.add_development_dependency(%q<rake>, [">= 0"])
-      s.add_development_dependency(%q<jeweler>, [">= 0"])
+      s.add_development_dependency(%q<rake>.freeze, [">= 0"])
+      s.add_development_dependency(%q<jeweler>.freeze, [">= 0"])
+      s.add_development_dependency(%q<appraisal>.freeze, [">= 0"])
+      s.add_development_dependency(%q<jquery-rails>.freeze, [">= 0"])
+      s.add_development_dependency(%q<sqlite3>.freeze, [">= 0"])
+      s.add_development_dependency(%q<paperclip>.freeze, [">= 0"])
+      s.add_development_dependency(%q<remotipart>.freeze, [">= 0"])
     else
-      s.add_dependency(%q<rake>, [">= 0"])
-      s.add_dependency(%q<jeweler>, [">= 0"])
+      s.add_dependency(%q<rake>.freeze, [">= 0"])
+      s.add_dependency(%q<jeweler>.freeze, [">= 0"])
+      s.add_dependency(%q<appraisal>.freeze, [">= 0"])
+      s.add_dependency(%q<jquery-rails>.freeze, [">= 0"])
+      s.add_dependency(%q<sqlite3>.freeze, [">= 0"])
+      s.add_dependency(%q<paperclip>.freeze, [">= 0"])
+      s.add_dependency(%q<remotipart>.freeze, [">= 0"])
     end
   else
-    s.add_dependency(%q<rake>, [">= 0"])
-    s.add_dependency(%q<jeweler>, [">= 0"])
+    s.add_dependency(%q<rake>.freeze, [">= 0"])
+    s.add_dependency(%q<jeweler>.freeze, [">= 0"])
+    s.add_dependency(%q<appraisal>.freeze, [">= 0"])
+    s.add_dependency(%q<jquery-rails>.freeze, [">= 0"])
+    s.add_dependency(%q<sqlite3>.freeze, [">= 0"])
+    s.add_dependency(%q<paperclip>.freeze, [">= 0"])
+    s.add_dependency(%q<remotipart>.freeze, [">= 0"])
   end
 end
 
diff --git a/spec/dummy_app/.gitignore b/spec/dummy_app/.gitignore
new file mode 100644
index 0000000..dd71abb
--- /dev/null
+++ b/spec/dummy_app/.gitignore
@@ -0,0 +1,17 @@
+# See http://help.github.com/ignore-files/ for more about ignoring files.
+#
+# If you find yourself ignoring temporary files generated by your text editor
+# or operating system, you probably want to add a global ignore instead:
+#   git config --global core.excludesfile ~/.gitignore_global
+
+# Ignore bundler config
+/.bundle
+
+# Ignore the default SQLite database.
+/db/*.sqlite3
+
+# Ignore all logfiles and tempfiles.
+/log/*.log
+/tmp
+
+/public/system
diff --git a/spec/dummy_app/Rakefile b/spec/dummy_app/Rakefile
new file mode 100644
index 0000000..1187394
--- /dev/null
+++ b/spec/dummy_app/Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require File.expand_path('../config/application', __FILE__)
+
+DummyApp::Application.load_tasks
diff --git a/spec/dummy_app/app/assets/config/manifest.js b/spec/dummy_app/app/assets/config/manifest.js
new file mode 100644
index 0000000..c8e290c
--- /dev/null
+++ b/spec/dummy_app/app/assets/config/manifest.js
@@ -0,0 +1,4 @@
+
+//= link_tree ../images
+//= link_directory ../javascripts .js
+//= link_directory ../stylesheets .css
diff --git a/spec/dummy_app/app/assets/images/rails.png b/spec/dummy_app/app/assets/images/rails.png
new file mode 100644
index 0000000..d5edc04
Binary files /dev/null and b/spec/dummy_app/app/assets/images/rails.png differ
diff --git a/spec/dummy_app/app/assets/javascripts/application.js.erb b/spec/dummy_app/app/assets/javascripts/application.js.erb
new file mode 100644
index 0000000..c16f8e3
--- /dev/null
+++ b/spec/dummy_app/app/assets/javascripts/application.js.erb
@@ -0,0 +1,8 @@
+// FIXME: Tell people that this is a manifest file, real code should go into discrete files
+// FIXME: Tell people how Sprockets and CoffeeScript works
+//
+<% require_asset "jquery#{ENV['JQUERY_VERSION']}" %>
+<% require_asset "jquery_ujs" %>
+<% require_asset "jquery.remotipart" %>
+<% require_asset "comments" %>
+
diff --git a/spec/dummy_app/app/assets/javascripts/comments.js b/spec/dummy_app/app/assets/javascripts/comments.js
new file mode 100644
index 0000000..e605660
--- /dev/null
+++ b/spec/dummy_app/app/assets/javascripts/comments.js
@@ -0,0 +1,28 @@
+$(document)
+  .delegate('#new-comment-link, #new-comment-attachment-link', 'ajax:success', function(e, data, status, xhr){
+    var $this = $(this),
+        $container = $('#new-comment-links'),
+        $responseText = $(xhr.responseText),
+        $cancelButton = $responseText.find('#cancel-button');
+    $container.replaceWith($responseText)
+    $cancelButton.click(function(e){
+      $cancelButton.parent().replaceWith($container);
+      e.preventDefault();
+    });
+  })
+  .delegate('form[data-remote]', 'ajax:aborted:required', function(){
+    var $form = $(this),
+        errorDivId = 'ajax-validation-errors',
+        $errorDiv = $form.find('#' + errorDivId);
+    if ( ! $errorDiv.length ) {
+      $errorDiv = $('<div>', { id: errorDivId});
+      $form.prepend($errorDiv)
+    }
+    $errorDiv.html($('<h2>', {
+      text: 'You must fill in all required fields!'
+    }));
+  })
+  .delegate('form[data-remote]', 'ajax:error', function(e, xhr, status, statusText) {
+    $('#comments').after('Error status code: ' + xhr.status + ', Error status message: ' + statusText);
+  });
+
diff --git a/spec/dummy_app/app/assets/stylesheets/application.css b/spec/dummy_app/app/assets/stylesheets/application.css
new file mode 100644
index 0000000..a208a1a
--- /dev/null
+++ b/spec/dummy_app/app/assets/stylesheets/application.css
@@ -0,0 +1,6 @@
+/*
+ * FIXME: Introduce SCSS & Sprockets
+ *= require 'scaffold'
+ *= require_self
+ *= require_tree .
+*/
diff --git a/spec/dummy_app/app/assets/stylesheets/scaffold.css b/spec/dummy_app/app/assets/stylesheets/scaffold.css
new file mode 100644
index 0000000..5793755
--- /dev/null
+++ b/spec/dummy_app/app/assets/stylesheets/scaffold.css
@@ -0,0 +1,65 @@
+body { background-color: #fff; color: #333; }
+
+body, p, ol, ul, td {
+  font-family: verdana, arial, helvetica, sans-serif;
+  font-size:   13px;
+  line-height: 18px;
+}
+
+pre {
+  background-color: #eee;
+  padding: 10px;
+  font-size: 11px;
+}
+
+a { color: #000; }
+a:visited { color: #666; }
+a:hover { color: #fff; background-color:#000; }
+
+div.field, div.actions {
+  margin-bottom: 10px;
+}
+
+#notice {
+  color: green;
+}
+
+legend.required:before {
+  content: "*";
+  color: red;
+}
+label.required:after {
+  content: "*";
+  color: red;
+}
+
+.field_with_errors {
+  padding: 2px;
+  background-color: red;
+  display: table;
+}
+
+#error_explanation, #ajax-validation-errors {
+  width: 450px;
+  border: 2px solid red;
+  padding: 7px;
+  padding-bottom: 0;
+  margin-bottom: 20px;
+  background-color: #f0f0f0;
+}
+
+#error_explanation h2, #ajax-validation-errors h2{
+  text-align: left;
+  font-weight: bold;
+  padding: 5px 5px 5px 15px;
+  font-size: 12px;
+  margin: -7px;
+  margin-bottom: 0px;
+  background-color: #c00;
+  color: #fff;
+}
+
+#error_explanation ul li {
+  font-size: 12px;
+  list-style: square;
+}
diff --git a/spec/dummy_app/app/controllers/application_controller.rb b/spec/dummy_app/app/controllers/application_controller.rb
new file mode 100644
index 0000000..e8065d9
--- /dev/null
+++ b/spec/dummy_app/app/controllers/application_controller.rb
@@ -0,0 +1,3 @@
+class ApplicationController < ActionController::Base
+  protect_from_forgery
+end
diff --git a/spec/dummy_app/app/controllers/comments_controller.rb b/spec/dummy_app/app/controllers/comments_controller.rb
new file mode 100644
index 0000000..b9836f1
--- /dev/null
+++ b/spec/dummy_app/app/controllers/comments_controller.rb
@@ -0,0 +1,72 @@
+class CommentsController < ApplicationController
+  def index
+    @comments = Comment.all
+    respond_to do |format|
+      format.html
+      format.json { render json: @comments }
+    end
+  end
+
+  def show
+    @comment = Comment.find(params[:id])
+    respond_to do |format|
+      format.html
+      format.json { render json: @comment }
+    end
+  end
+
+  def new
+    @comment = Comment.new
+    respond_to do |format|
+      format.html { render :layout => ! request.xhr? }
+    end
+  end
+
+  def edit
+    @comment = Comment.find(params[:id])
+    respond_to do |format|
+      format.html
+      format.json { render json: @comment }
+    end
+  end
+
+  def create
+    @comment = Comment.create(comment_params)
+    if request.xhr? || remotipart_submitted?
+      sleep 1 if params[:pause]
+      respond_to do |format|
+        format.html { render (params[:template] == 'escape' ? 'comments/escape_test' : 'comments/create'), layout: false }
+        format.js { render 'comments/create', layout: false, status:(@comment.errors.any? ? :unprocessable_entity : :ok) }
+        format.json { render json: @comment }
+      end
+    else
+      redirect_to comments_path
+    end
+  end
+
+  def update
+    @comment = Comment.find(params[:id])
+    respond_to do |format|
+      format.html { redirect_to @comment }
+      format.js { render json: @comment }
+    end
+  end
+
+  def destroy
+    @comment = Comment.destroy(params[:id])
+  end
+
+  def say
+    if Rails.version < '4'
+      render text: params[:message], content_type: 'text/plain'
+    else
+      render plain: params[:message]
+    end
+  end
+
+  private
+
+  def comment_params
+    params.require(:comment).permit(:subject, :body, :attachment, :other_attachment)
+  end
+end
diff --git a/spec/dummy_app/app/controllers/prepended_controller.rb b/spec/dummy_app/app/controllers/prepended_controller.rb
new file mode 100644
index 0000000..a938f20
--- /dev/null
+++ b/spec/dummy_app/app/controllers/prepended_controller.rb
@@ -0,0 +1,9 @@
+class PrependedController < ApplicationController
+  # order matters, only prepend then include causes the issue
+  prepend Module.new
+  include Remotipart::RenderOverrides
+
+  def show
+    render
+  end
+end
\ No newline at end of file
diff --git a/spec/dummy_app/app/helpers/application_helper.rb b/spec/dummy_app/app/helpers/application_helper.rb
new file mode 100644
index 0000000..de6be79
--- /dev/null
+++ b/spec/dummy_app/app/helpers/application_helper.rb
@@ -0,0 +1,2 @@
+module ApplicationHelper
+end
diff --git a/spec/dummy_app/app/helpers/comments_helper.rb b/spec/dummy_app/app/helpers/comments_helper.rb
new file mode 100644
index 0000000..0ec9ca5
--- /dev/null
+++ b/spec/dummy_app/app/helpers/comments_helper.rb
@@ -0,0 +1,2 @@
+module CommentsHelper
+end
diff --git a/spec/dummy_app/app/models/comment.rb b/spec/dummy_app/app/models/comment.rb
new file mode 100644
index 0000000..25e6b06
--- /dev/null
+++ b/spec/dummy_app/app/models/comment.rb
@@ -0,0 +1,7 @@
+class Comment < ActiveRecord::Base
+  has_attached_file :attachment
+  has_attached_file :other_attachment
+  validates :subject, :body, :presence => true
+  validates_attachment :attachment, content_type: { content_type: /\Aimage\/.*\Z/ }
+  validates_attachment :other_attachment, content_type: { content_type: 'text/plain' }
+end
diff --git a/spec/dummy_app/app/views/comments/_comment.html.erb b/spec/dummy_app/app/views/comments/_comment.html.erb
new file mode 100644
index 0000000..81c3d45
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/_comment.html.erb
@@ -0,0 +1,9 @@
+<tr class='comment' id='comment-<%= comment.id %>'>
+  <td><%= comment.subject %></td>
+  <td><%= comment.body %></td>
+  <td><%= link_to comment.attachment_file_name, comment.attachment.url if comment.attachment? %></td>
+  <td><%= link_to comment.other_attachment_file_name, comment.other_attachment.url if comment.other_attachment? %></td>
+  <td><%= link_to 'Show', comment %></td>
+  <td><%= link_to 'Edit', edit_comment_path(comment) %></td>
+  <td><%= link_to 'Destroy', comment, :data => {:confirm => 'Are you sure?'}, :method => :delete, :remote => true %></td>
+</tr>
diff --git a/spec/dummy_app/app/views/comments/_form.html.erb b/spec/dummy_app/app/views/comments/_form.html.erb
new file mode 100644
index 0000000..d808c5f
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/_form.html.erb
@@ -0,0 +1,40 @@
+<%= form_for(@comment, :remote => (params[:action] == 'new' ? true : false)) do |f| %>
+  <% if @comment.errors.any? %>
+    <div id="error_explanation">
+      <h2><%= pluralize(@comment.errors.count, "error") %> prohibited this comment from being saved:</h2>
+
+      <ul>
+      <% @comment.errors.full_messages.each do |msg| %>
+        <li><%= msg %></li>
+      <% end %>
+      </ul>
+    </div>
+  <% end %>
+
+  <fieldset>
+    <legend class='required'>
+      Required fields
+    </legend>
+    <div class="field">
+      <%= f.label :subject, :class => 'required' %><br />
+      <%= f.text_field :subject, :required => true %>
+    </div>
+    <div class="field">
+      <%= f.label :body, :class => 'required' %><br />
+      <%= f.text_area :body, :required => true %>
+    </div>
+    <% if params[:attachment] %>
+      <div class="field">
+        <%= f.label :attachment %><br />
+        <%= f.file_field :attachment %>
+      </div>
+      <div class="field">
+        <%= f.label :other_attachment %><br />
+        <%= f.file_field :other_attachment %>
+      </div>
+    <% end %>
+    </fieldset>
+  <div class="actions">
+    <%= f.submit :data => {disable_with: "Submitting..."} %>
+  </div>
+<% end %>
diff --git a/spec/dummy_app/app/views/comments/_new_comment_links.html.erb b/spec/dummy_app/app/views/comments/_new_comment_links.html.erb
new file mode 100644
index 0000000..9654a7d
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/_new_comment_links.html.erb
@@ -0,0 +1,5 @@
+<div id='new-comment-links'>
+  <%= link_to 'New Comment', new_comment_path, :remote => true, :'data-type' => 'html', :id => 'new-comment-link' %>
+  <br />
+  <%= link_to 'New Comment with Attachment', new_comment_path(:attachment => true), :remote => true, :'data-type' => 'html', :id => 'new-comment-attachment-link' %>
+</div>
diff --git a/spec/dummy_app/app/views/comments/create.html.erb b/spec/dummy_app/app/views/comments/create.html.erb
new file mode 100644
index 0000000..01a1789
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/create.html.erb
@@ -0,0 +1,7 @@
+<span>
+HTML response:
+</span>
+
+<table>
+<%= render @comment %>
+</table>
diff --git a/spec/dummy_app/app/views/comments/create.js.erb b/spec/dummy_app/app/views/comments/create.js.erb
new file mode 100644
index 0000000..bb65046
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/create.js.erb
@@ -0,0 +1,20 @@
+<%= remotipart_response do %>
+  <% unless @comment.errors.any? %>
+    $('#comments').append( '<%= escape_javascript(
+      render @comment
+    ) %>' );
+    $('#new-comment-form-container').find('input:not(:submit),select,textarea').val('');
+    <% if request.put? %>
+        $('#comments').after('PUT request!');
+    <% end %>
+  <% else %>
+    var $form = $('#new_comment'),
+        $errorDiv = $('<div id="error_explanation">'),
+        $errorList = $('<ul>');
+    <% @comment.errors.full_messages.each do |msg| %>
+      $errorList.append('<li><%= escape_javascript msg %></li>');
+    <% end %>
+    $form.find('#error_explanation').remove();
+    $form.prepend($errorDiv.append($errorList));
+  <% end %>
+<% end %>
diff --git a/spec/dummy_app/app/views/comments/destroy.js.erb b/spec/dummy_app/app/views/comments/destroy.js.erb
new file mode 100644
index 0000000..347af22
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/destroy.js.erb
@@ -0,0 +1 @@
+$('#comment-<%= @comment.id %>').remove();
diff --git a/spec/dummy_app/app/views/comments/edit.html.erb b/spec/dummy_app/app/views/comments/edit.html.erb
new file mode 100644
index 0000000..12ea7f9
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/edit.html.erb
@@ -0,0 +1,6 @@
+<h1>Editing comment</h1>
+
+<%= render 'form' %>
+
+<%= link_to 'Show', @comment %> |
+<%= link_to 'Back', comments_path %>
diff --git a/spec/dummy_app/app/views/comments/escape_test.html.erb b/spec/dummy_app/app/views/comments/escape_test.html.erb
new file mode 100644
index 0000000..2895479
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/escape_test.html.erb
@@ -0,0 +1 @@
+<%= text_field_tag :quote, '"' %>
diff --git a/spec/dummy_app/app/views/comments/index.html.erb b/spec/dummy_app/app/views/comments/index.html.erb
new file mode 100644
index 0000000..478add8
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/index.html.erb
@@ -0,0 +1,19 @@
+<h1>Listing comments</h1>
+
+<table id='comments'>
+  <tr>
+    <th>Subject</th>
+    <th>Body</th>
+    <th>Attachment</td>
+    <th>Other Attachment</td>
+    <th></th>
+    <th></th>
+    <th></th>
+  </tr>
+
+  <%= render @comments %>
+</table>
+
+<br />
+
+<%= render 'new_comment_links' %>
diff --git a/spec/dummy_app/app/views/comments/new.html.erb b/spec/dummy_app/app/views/comments/new.html.erb
new file mode 100644
index 0000000..2fcbec3
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/new.html.erb
@@ -0,0 +1,7 @@
+<div id='new-comment-form-container'>
+  <h1>New comment</h1>
+  
+  <%= render 'form' %>
+  
+  <%= link_to 'Cancel', comments_path, :id => 'cancel-button' %>
+</div>
diff --git a/spec/dummy_app/app/views/comments/show.html.erb b/spec/dummy_app/app/views/comments/show.html.erb
new file mode 100644
index 0000000..172d81d
--- /dev/null
+++ b/spec/dummy_app/app/views/comments/show.html.erb
@@ -0,0 +1,15 @@
+<table>
+  <tr>
+    <th>Subject</th>
+    <th>Body</th>
+    <th>Attachment</th>
+    <th></th>
+    <th></th>
+    <th></th>
+  </tr>
+  <%= render @comment %>
+</table>
+
+<br />
+
+<%= link_to 'Back', comments_path %>
diff --git a/spec/dummy_app/app/views/layouts/application.html.erb b/spec/dummy_app/app/views/layouts/application.html.erb
new file mode 100644
index 0000000..5e9ef70
--- /dev/null
+++ b/spec/dummy_app/app/views/layouts/application.html.erb
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>JqueryRails</title>
+  <%= stylesheet_link_tag "application" %>
+  <%= javascript_include_tag "application" %>
+  <%= csrf_meta_tag %>
+</head>
+<body>
+
+<%= yield %>
+
+</body>
+</html>
diff --git a/spec/dummy_app/app/views/prepended/show.html.erb b/spec/dummy_app/app/views/prepended/show.html.erb
new file mode 100644
index 0000000..65e7e58
--- /dev/null
+++ b/spec/dummy_app/app/views/prepended/show.html.erb
@@ -0,0 +1 @@
+<p>prepended</p>
\ No newline at end of file
diff --git a/spec/dummy_app/bin/bundle b/spec/dummy_app/bin/bundle
new file mode 100755
index 0000000..66e9889
--- /dev/null
+++ b/spec/dummy_app/bin/bundle
@@ -0,0 +1,3 @@
+#!/usr/bin/env ruby
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+load Gem.bin_path('bundler', 'bundle')
diff --git a/spec/dummy_app/bin/rails b/spec/dummy_app/bin/rails
new file mode 100755
index 0000000..5191e69
--- /dev/null
+++ b/spec/dummy_app/bin/rails
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+APP_PATH = File.expand_path('../../config/application', __FILE__)
+require_relative '../config/boot'
+require 'rails/commands'
diff --git a/spec/dummy_app/bin/rake b/spec/dummy_app/bin/rake
new file mode 100755
index 0000000..1724048
--- /dev/null
+++ b/spec/dummy_app/bin/rake
@@ -0,0 +1,4 @@
+#!/usr/bin/env ruby
+require_relative '../config/boot'
+require 'rake'
+Rake.application.run
diff --git a/spec/dummy_app/bin/setup b/spec/dummy_app/bin/setup
new file mode 100755
index 0000000..589bee8
--- /dev/null
+++ b/spec/dummy_app/bin/setup
@@ -0,0 +1,34 @@
+#!/usr/bin/env ruby
+require 'pathname'
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
+
+def system!(*args)
+  system(*args) || abort("\n== Command #{args} failed ==")
+end
+
+chdir APP_ROOT do
+  # This script is a starting point to setup your application.
+  # Add necessary setup steps to this file.
+
+  puts '== Installing dependencies =='
+  system! 'gem install bundler --conservative'
+  system('bundle check') or system!('bundle install')
+
+  # puts "\n== Copying sample files =="
+  # unless File.exist?('config/database.yml')
+  #   cp 'config/database.yml.sample', 'config/database.yml'
+  # end
+
+  puts "\n== Preparing database =="
+  system! 'bin/rails db:setup'
+
+  puts "\n== Removing old logs and tempfiles =="
+  system! 'bin/rails log:clear tmp:clear'
+
+  puts "\n== Restarting application server =="
+  system! 'bin/rails restart'
+end
diff --git a/spec/dummy_app/bin/update b/spec/dummy_app/bin/update
new file mode 100755
index 0000000..9851923
--- /dev/null
+++ b/spec/dummy_app/bin/update
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+require 'pathname'
+require 'fileutils'
+include FileUtils
+
+# path to your application root.
+APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
+
+def system!(*args)
+  system(*args) || abort("\n== Command #{args} failed ==")
+end
+
+chdir APP_ROOT do
+  # This script is a way to update your development environment automatically.
+  # Add necessary update steps to this file.
+
+  puts '== Installing dependencies =='
+  system! 'gem install bundler --conservative'
+  system 'bundle check' or system! 'bundle install'
+
+  puts "\n== Updating database =="
+  system! 'bin/rails db:migrate'
+
+  puts "\n== Removing old logs and tempfiles =="
+  system! 'bin/rails log:clear tmp:clear'
+
+  puts "\n== Restarting application server =="
+  system! 'bin/rails restart'
+end
diff --git a/spec/dummy_app/config.ru b/spec/dummy_app/config.ru
new file mode 100644
index 0000000..7ae1c84
--- /dev/null
+++ b/spec/dummy_app/config.ru
@@ -0,0 +1,4 @@
+# This file is used by Rack-based servers to start the application.
+
+require ::File.expand_path('../config/environment', __FILE__)
+run DummyApp::Application
diff --git a/spec/dummy_app/config/application.rb b/spec/dummy_app/config/application.rb
new file mode 100644
index 0000000..f8d7941
--- /dev/null
+++ b/spec/dummy_app/config/application.rb
@@ -0,0 +1,18 @@
+require File.expand_path('../boot', __FILE__)
+
+require 'rails/all'
+
+# Require the gems listed in Gemfile, including any gems
+# you've limited to :test, :development, or :production.
+Bundler.require(*Rails.groups)
+
+module DummyApp
+  class Application < Rails::Application
+    # Settings in config/environments/* take precedence over those specified here.
+    # Application configuration should go into files in config/initializers
+    config.assets.paths << Rails.root.join("..", "..", "vendor", "assets", "javascripts")
+    config.active_record.raise_in_transactional_callbacks = true if Rails::VERSION::MAJOR == 4 && Rails::VERSION::MINOR == 2
+    config.active_record.time_zone_aware_types = [:datetime, :time] if Rails::VERSION::MAJOR >= 5
+    config.active_record.sqlite3.represent_boolean_as_integer = true if config.active_record.sqlite3.respond_to?(:represent_boolean_as_integer=) && Rails::VERSION::MAJOR == 5 && Rails::VERSION::MINOR == 2
+  end
+end
diff --git a/spec/dummy_app/config/boot.rb b/spec/dummy_app/config/boot.rb
new file mode 100644
index 0000000..6ab0815
--- /dev/null
+++ b/spec/dummy_app/config/boot.rb
@@ -0,0 +1,3 @@
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../gemfiles/rails_5.2.gemfile', __FILE__)
+
+require 'bundler/setup' # Set up gems listed in the Gemfile.
diff --git a/spec/dummy_app/config/database.yml b/spec/dummy_app/config/database.yml
new file mode 100644
index 0000000..963ad5d
--- /dev/null
+++ b/spec/dummy_app/config/database.yml
@@ -0,0 +1,7 @@
+development:
+  adapter: sqlite3
+  database: db/development.sqlite3
+
+test:
+  adapter: sqlite3
+  database: ":memory:"
diff --git a/spec/dummy_app/config/environment.rb b/spec/dummy_app/config/environment.rb
new file mode 100644
index 0000000..e82229a
--- /dev/null
+++ b/spec/dummy_app/config/environment.rb
@@ -0,0 +1,5 @@
+# Load the Rails application.
+require File.expand_path('../application', __FILE__)
+
+# Initialize the Rails application.
+DummyApp::Application.initialize!
diff --git a/spec/dummy_app/config/environments/development.rb b/spec/dummy_app/config/environments/development.rb
new file mode 100644
index 0000000..417a284
--- /dev/null
+++ b/spec/dummy_app/config/environments/development.rb
@@ -0,0 +1,54 @@
+DummyApp::Application.configure do
+  # Settings specified here will take precedence over those in config/application.rb.
+
+  # In the development environment your application's code is reloaded on
+  # every request. This slows down response time but is perfect for development
+  # since you don't have to restart the web server when you make code changes.
+  config.cache_classes = false
+
+  # Do not eager load code on boot.
+  config.eager_load = false
+
+  # Show full error reports.
+  config.consider_all_requests_local = true
+
+  # Enable/disable caching. By default caching is disabled.
+  if Rails.root.join('tmp/caching-dev.txt').exist?
+    config.action_controller.perform_caching = true
+    config.cache_store = :memory_store
+    config.public_file_server.headers = {'Cache-Control' => 'public, max-age=172800'}
+  else
+    config.action_controller.perform_caching = false
+    config.cache_store = :null_store
+  end
+
+  # Don't care if the mailer can't send.
+  config.action_mailer.raise_delivery_errors = false
+
+  # Print deprecation notices to the Rails logger.
+  config.active_support.deprecation = :log
+
+  # Raise an error on page load if there are pending migrations.
+  config.active_record.migration_error = :page_load
+
+  # Debug mode disables concatenation and preprocessing of assets.
+  # This option may cause significant delays in view rendering with a large
+  # number of complex assets.
+  config.assets.debug = true
+
+  # Asset digests allow you to set far-future HTTP expiration dates on all assets,
+  # yet still be able to expire them through the digest params.
+  config.assets.digest = true
+
+  # Adds additional error checking when serving assets at runtime.
+  # Checks for improperly declared sprockets dependencies.
+  # Raises helpful error messages.
+  config.assets.raise_runtime_errors = true
+
+  # Raises error for missing translations
+  # config.action_view.raise_on_missing_translations = true
+
+  # Use an evented file watcher to asynchronously detect changes in source code,
+  # routes, locales, etc. This feature depends on the listen gem.
+  # config.file_watcher = ActiveSupport::EventedFileUpdateChecker
+end
diff --git a/spec/dummy_app/config/environments/test.rb b/spec/dummy_app/config/environments/test.rb
new file mode 100644
index 0000000..2dbee76
--- /dev/null
+++ b/spec/dummy_app/config/environments/test.rb
@@ -0,0 +1,53 @@
+DummyApp::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.
+  if config.respond_to?(:public_file_server)
+    config.public_file_server.enabled = true
+    config.public_file_server.headers = {'Cache-Control' => 'public, max-age=3600'}
+  else
+    if Rails::VERSION::MAJOR < 4
+      config.assets.enabled = true
+      config.assets.debug = true
+      config.serve_static_assets = true
+    else
+      config.serve_static_files   = true
+    end
+    config.static_cache_control = 'public, max-age=3600'
+  end
+
+  # 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
+
+  # Randomize the order test cases are executed.
+  config.active_support.test_order = :random
+
+  # 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
diff --git a/spec/dummy_app/config/initializers/secret_token.rb b/spec/dummy_app/config/initializers/secret_token.rb
new file mode 100644
index 0000000..21f5a32
--- /dev/null
+++ b/spec/dummy_app/config/initializers/secret_token.rb
@@ -0,0 +1,3 @@
+if Rails::VERSION::MAJOR < 4
+  DummyApp::Application.config.secret_token = 'f2338e8b8018053b0b322cd6469d8c0ed06ab0aaf43dd30a1c33a4c55d9c0d6a1c1ad4140049019f85388db3ce1ddbeff597cf07c49c5b22242cecd146f2bd66'
+end
diff --git a/spec/dummy_app/config/routes.rb b/spec/dummy_app/config/routes.rb
new file mode 100644
index 0000000..077cad9
--- /dev/null
+++ b/spec/dummy_app/config/routes.rb
@@ -0,0 +1,7 @@
+DummyApp::Application.routes.draw do
+  match 'comments' => 'comments#create', :via => [:put]
+  match 'say' => 'comments#say', :via => [:get]
+  resources :comments
+  match 'prepended' => 'prepended#show', :via => [:get]
+  root :to => "comments#index"
+end
diff --git a/spec/dummy_app/config/secrets.yml b/spec/dummy_app/config/secrets.yml
new file mode 100644
index 0000000..f340993
--- /dev/null
+++ b/spec/dummy_app/config/secrets.yml
@@ -0,0 +1,5 @@
+development:
+  secret_key_base: d059ae03480564f4e9dcb7c96b901e5803037b0e09fd53e96343dff0d18dc54390a2f07b99c231eacb1d0cc6b74b90676fec4786afaf0f2e7f69b971ab2f9600
+
+test:
+  secret_key_base: e5e0e4811c8cfc047799cf3e82d1626adbf02fa7a3530b4bdd39cc17e1098d328f4da6ada090ec01449b5c92662bcec92cfb13b4c3c4c4bb3fac5a303e91c356
diff --git a/spec/dummy_app/db/migrate/20110209210252_create_comments.rb b/spec/dummy_app/db/migrate/20110209210252_create_comments.rb
new file mode 100644
index 0000000..f71a017
--- /dev/null
+++ b/spec/dummy_app/db/migrate/20110209210252_create_comments.rb
@@ -0,0 +1,14 @@
+class CreateComments < ActiveRecord::Migration
+  def self.up
+    create_table :comments do |t|
+      t.string :subject
+      t.text :body
+
+      t.timestamps
+    end
+  end
+
+  def self.down
+    drop_table :comments
+  end
+end
diff --git a/spec/dummy_app/db/migrate/20110209210315_add_attachment_to_comment.rb b/spec/dummy_app/db/migrate/20110209210315_add_attachment_to_comment.rb
new file mode 100644
index 0000000..0c906f5
--- /dev/null
+++ b/spec/dummy_app/db/migrate/20110209210315_add_attachment_to_comment.rb
@@ -0,0 +1,15 @@
+class AddAttachmentToComment < ActiveRecord::Migration
+  def self.up
+    add_column :comments, :attachment_file_name,    :string
+    add_column :comments, :attachment_content_type, :string
+    add_column :comments, :attachment_file_size,    :integer
+    add_column :comments, :attachment_updated_at,   :datetime
+  end
+
+  def self.down
+    remove_column :comments, :attachment_file_name
+    remove_column :comments, :attachment_content_type
+    remove_column :comments, :attachment_file_size
+    remove_column :comments, :attachment_updated_at
+  end
+end
diff --git a/spec/dummy_app/db/migrate/20110714205346_add_other_attachment_to_comment.rb b/spec/dummy_app/db/migrate/20110714205346_add_other_attachment_to_comment.rb
new file mode 100644
index 0000000..26a5550
--- /dev/null
+++ b/spec/dummy_app/db/migrate/20110714205346_add_other_attachment_to_comment.rb
@@ -0,0 +1,8 @@
+class AddOtherAttachmentToComment < ActiveRecord::Migration
+  def change
+    add_column :comments, :other_attachment_file_name,    :string
+    add_column :comments, :other_attachment_content_type, :string
+    add_column :comments, :other_attachment_file_size,    :integer
+    add_column :comments, :other_attachment_updated_at,   :datetime
+  end
+end
diff --git a/spec/dummy_app/db/schema.rb b/spec/dummy_app/db/schema.rb
new file mode 100644
index 0000000..a4585a5
--- /dev/null
+++ b/spec/dummy_app/db/schema.rb
@@ -0,0 +1,31 @@
+# encoding: UTF-8
+# This file is auto-generated from the current state of the database. Instead
+# of editing this file, please use the migrations feature of Active Record to
+# incrementally modify your database, and then regenerate this schema definition.
+#
+# Note that this schema.rb definition is the authoritative source for your
+# database schema. If you need to create the application database on another
+# system, you should be using db:schema:load, not running all the migrations
+# from scratch. The latter is a flawed and unsustainable approach (the more migrations
+# you'll amass, the slower it'll run and the greater likelihood for issues).
+#
+# It's strongly recommended to check this file into your version control system.
+
+ActiveRecord::Schema.define(:version => 20110714205346) do
+
+  create_table "comments", :force => true do |t|
+    t.string   "subject"
+    t.text     "body"
+    t.datetime "created_at"
+    t.datetime "updated_at"
+    t.string   "attachment_file_name"
+    t.string   "attachment_content_type"
+    t.integer  "attachment_file_size"
+    t.datetime "attachment_updated_at"
+    t.string   "other_attachment_file_name"
+    t.string   "other_attachment_content_type"
+    t.integer  "other_attachment_file_size"
+    t.datetime "other_attachment_updated_at"
+  end
+
+end
diff --git a/spec/dummy_app/db/seeds.rb b/spec/dummy_app/db/seeds.rb
new file mode 100644
index 0000000..664d8c7
--- /dev/null
+++ b/spec/dummy_app/db/seeds.rb
@@ -0,0 +1,7 @@
+# This file should contain all the record creation needed to seed the database with its default values.
+# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
+#
+# Examples:
+#
+#   cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }])
+#   Mayor.create(:name => 'Daley', :city => cities.first)
diff --git a/spec/features/comments_spec.rb b/spec/features/comments_spec.rb
new file mode 100644
index 0000000..5ae5169
--- /dev/null
+++ b/spec/features/comments_spec.rb
@@ -0,0 +1,414 @@
+require 'spec_helper'
+
+describe 'comments', type: :feature do
+  it 'creates a new comment', js: true do
+    visit root_path
+    click_link 'New Comment'
+
+    # New Comment link should disappear
+    expect(page).to have_no_link('New Comment')
+    # Comment form should appear
+    expect(page).to have_field('comment_subject')
+    expect(page).to have_field('comment_body')
+    expect(page).to have_no_field('comment_file')
+
+    # Filling in form and submitting
+    comment_subject = 'A new comment!'
+    comment_body = 'Woo, this is my comment, dude.'
+    fill_in 'comment_subject', with: comment_subject
+    fill_in 'comment_body', with: comment_body
+    click_button 'Create Comment'
+
+    # Comment should appear in the comments table
+    within '#comments' do
+      expect(page).to have_content(comment_subject)
+      expect(page).to have_content(comment_body)
+    end
+    # Form should clear
+    expect(page).to have_field('comment_subject', with: '')
+    expect(page).to have_field('comment_body', with: '')
+    # ...and be replaced by link again
+    expect(page).to have_link('Cancel')
+  end
+
+  it "cancels creating a comment", js: true do
+    visit root_path
+    click_link 'New Comment'
+
+    expect(page).to have_field('comment_subject')
+    expect(page).to have_link('Cancel')
+    click_link 'Cancel'
+
+    # Form should disappear
+    expect(page).to have_no_field('comment_subject')
+    expect(page).to have_link('New Comment')
+  end
+
+  it "deletes a comment", js: true do
+    Comment.create(subject: 'The Great Yogurt', body: 'The Schwarz is strong with this one.')
+    visit root_path
+
+    within '#comments' do
+      expect(page).to have_content('The Great Yogurt')
+      accept_js_confirm do
+        click_link 'Destroy'
+      end
+
+      expect(page).to have_no_content('The Great Yogurt')
+    end
+  end
+
+  it "uploads a file", js: true do
+    visit root_path
+    click_link 'New Comment with Attachment'
+
+    expect(page).to have_field('comment_subject')
+    expect(page).to have_field('comment_body')
+    expect(page).to have_field('comment_attachment')
+    expect(page).to have_field('comment_other_attachment')
+
+    comment_subject = 'Newby'
+    comment_body = 'Woot, a file!'
+    fill_in 'comment_subject', with: comment_subject
+    fill_in 'comment_body', with: comment_body
+
+    # Attach file
+    file_path = File.join(fixture_path, 'qr.jpg')
+    other_file_path = File.join(fixture_path, 'hi.txt')
+    attach_file 'comment_attachment', file_path
+    attach_file 'comment_other_attachment', other_file_path
+
+    page_should_not_redirect do
+      click_button 'Create Comment'
+    end
+
+    within '#comments' do
+      expect(page).to have_selector("td", text: comment_subject)
+      expect(page).to have_selector("td", text: comment_body)
+      expect(page).to have_selector("a", text: File.basename(file_path))
+      expect(page).to have_selector("a", text: File.basename(other_file_path))
+    end
+  end
+
+  it "Disables submit button while submitting", js: true do
+    visit root_path
+
+    click_link 'New Comment'
+    # Needed to make test wait for above to finish
+    form = find('form')
+
+    button = find_button('Create Comment')
+    page.execute_script(%q{$('form').append('<input name="pause" type="hidden" value=1 />');})
+
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    click_button 'Create Comment'
+
+    expect(button[:disabled]).to be true
+    expect(button.value).to eq "Submitting..."
+
+    sleep 1.5
+
+    expect(button[:disabled]).to be false
+    expect(button.value).to eq "Create Comment"
+  end
+
+  it "triggers ajax:remotipartSubmit event hook", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:remotipartSubmit', function() { $('#comments').after('remotipart!'); });")
+
+    click_link 'New Comment with Attachment'
+
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', File.join(fixture_path, 'qr.jpg')
+    click_button 'Create Comment'
+
+    expect(page).to have_content('remotipart!')
+  end
+
+  it "allows remotipart submission to be cancelable via event hook", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:remotipartSubmit', function() { $('#comments').after('remotipart!'); return false; });")
+
+    click_link 'New Comment with Attachment'
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content('remotipart!')
+
+    within '#comments' do
+      expect(page).to have_no_content('Hi')
+      expect(page).to have_no_content('there')
+      expect(page).to have_no_content(File.basename(file_path))
+    end
+  end
+
+  it "allows custom data-type on form", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:success', function(evt, data, status, xhr) { $('#comments').after(xhr.responseText); });")
+
+    click_link 'New Comment with Attachment'
+
+    # Needed to make test wait for above to finish
+    form = find('form')
+    page.execute_script("$('form').attr('data-type', 'html');")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content('HTML response')
+  end
+
+  it "allows users to use ajax response data safely", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:success', function(evt, data, status, xhr) { $('#comments').after(data); });")
+
+    click_link 'New Comment with Attachment'
+
+    # Needed to make test wait for above to finish
+    form = find('form')
+    page.execute_script("$('form').attr('data-type', 'html');")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content('HTML response')
+  end
+
+  it "escapes html response content properly", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:success', function(evt, data, status, xhr) { $('#comments').after(xhr.responseText); });")
+
+    click_link 'New Comment with Attachment'
+
+    # Needed to make test wait for above to finish
+    form = find('form')
+    page.execute_script("$('form').attr('data-type', 'html');")
+    page.execute_script("$('form').append('<input type=\"hidden\" name=\"template\" value=\"escape\" />');")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(find('input[name="quote"]').value).to eq '"'
+  end
+
+  it "returns the correct response status", js: true do
+    visit root_path
+
+    click_link 'New Comment with Attachment'
+    # Needed to make test wait for above to finish
+    input = find('#comment_subject')
+    page.execute_script("$('#comment_subject').removeAttr('required');")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    #within '#error_explanation' do
+    #  expect(page).to have_content "Subject can't be blank"
+    #end
+    expect(page).to have_content "Error status code: 422"
+    expect(page).to have_content "Error status message: Unprocessable Entity"
+  end
+
+  it "passes the method as _method parameter (rails convention)", js: true do
+    visit root_path
+
+    click_link 'New Comment with Attachment'
+    sleep 0.5
+    page.execute_script(%q{$('form').append('<input name="_method" type="hidden" value="put" />');})
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content 'PUT request!'
+  end
+
+  it "does not submit via remotipart unless file is present", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:remotipartSubmit', function() { $('#comments').after('remotipart!'); });")
+
+    click_link 'New Comment with Attachment'
+
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    click_button 'Create Comment'
+
+    expect(page).to have_no_content('remotipart!')
+  end
+
+  it "fires all the ajax callbacks on the form", js: true do
+    visit root_path
+    click_link 'New Comment with Attachment'
+
+    # Needed to make test wait for above to finish
+    form = find('form')
+
+    page.execute_script("$('form').bind('ajax:beforeSend', function() { $('#comments').after('thebefore'); });")
+    page.execute_script("$(document).delegate('form', 'ajax:success', function() { $('#comments').after('success'); });")
+    page.execute_script("$(document).delegate('form', 'ajax:complete', function() { $('#comments').after('complete'); });")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content('before')
+    expect(page).to have_content('success')
+    expect(page).to have_content('complete')
+  end
+
+  it "fires the ajax callbacks for json data-type with remotipart", js: true do
+    visit root_path
+    click_link 'New Comment with Attachment'
+
+    # Needed to make test wait for above to finish
+    form = find('form')
+
+    page.execute_script("$('form').data('type', 'json');")
+
+    page.execute_script("$('form').bind('ajax:beforeSend', function() { $('#comments').after('thebefore'); });")
+    page.execute_script("$(document).delegate('form', 'ajax:success', function() { $('#comments').after('success'); });")
+    page.execute_script("$(document).delegate('form', 'ajax:complete', function() { $('#comments').after('complete'); });")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content('before')
+    expect(page).to have_content('success')
+    expect(page).to have_content('complete')
+  end
+
+  it "only fires the beforeSend hook once", js: true do
+    visit root_path
+    click_link 'New Comment with Attachment'
+
+    # Needed to make test wait for above to finish
+    form = find('form')
+
+    page.execute_script("$('form').bind('ajax:beforeSend', function() { $('#comments').after('<div class=\"ajax\">ajax!</div>'); });")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_css("div.ajax", :count => 1)
+  end
+
+  it "cleans up after itself when uploading files", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:remotipartSubmit', function(evt, xhr, data) { if ($(this).data('remotipartSubmitted')) { $('#comments').after('remotipart before!'); } });")
+
+    click_link 'New Comment with Attachment'
+    page.execute_script("$('form').attr('data-type', 'html');")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content('remotipart before!')
+
+    page.execute_script("if (!$('form').data('remotipartSubmitted')) { $('#comments').after('no remotipart after!'); } ")
+    expect(page).to have_content('no remotipart after!')
+  end
+
+  it "submits via remotipart when a file upload is present", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:remotipartSubmit', function(evt, xhr, data) { $('#comments').after('<div class=\"remotipart\">remotipart!</div>'); });")
+
+    click_link 'New Comment with Attachment'
+    page.execute_script("$('form').attr('data-type', 'html');")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_css("div.remotipart")
+  end
+
+  it "does not submit via remotipart when a file upload is not present", js: true do
+    visit root_path
+    page.execute_script("$(document).delegate('form', 'ajax:remotipartSubmit', function(evt, xhr, data) { $('#comments').after('<div class=\"remotipart\">remotipart!</div>'); });")
+
+    click_link 'New Comment with Attachment'
+    page.execute_script("$('form').attr('data-type', 'html');")
+
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    click_button 'Create Comment'
+
+    expect(page).not_to have_css("div.remotipart")
+  end
+
+  it "Disables submit button while submitting with remotipart", js: true do
+    visit root_path
+
+    click_link 'New Comment with Attachment'
+
+    button = find_button('Create Comment')
+    # clicking 'Create Comment' button causes capybara evaluation freeze until request ends, so perform check by JavaScript
+    page.execute_script("$('form').bind('ajax:remotipartComplete', function(data) { window.commitButtonDisabled = $('input[name=\"commit\"]').is(':disabled'); window.commitButtonValue = $('input[name=\"commit\"]').val(); });")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page.evaluate_script("window.commitButtonDisabled")).to be true
+    expect(page.evaluate_script("window.commitButtonValue")).to eq "Submitting..."
+
+    expect(button[:disabled]).to be false
+    expect(button.value).to eq "Create Comment"
+  end
+
+  it "submits the clicked button with the form like non-file remote form", js: true do
+    visit root_path
+    click_link 'New Comment with Attachment'
+
+    form = find('form')
+    page.execute_script("$('form').bind('ajax:remotipartSubmit', function(e, xhr, settings) { $('#comments').after('<div class=\"params\">' + $.param(settings.data) + '</div>'); });")
+
+    file_path = File.join(fixture_path, 'qr.jpg')
+    fill_in 'comment_subject', with: 'Hi'
+    fill_in 'comment_body', with: 'there'
+    attach_file 'comment_attachment', file_path
+    click_button 'Create Comment'
+
+    expect(page).to have_content('commit=')
+  end
+
+  it "doesn't allow XSS via script injection for text responses", js: true do
+    visit "/say?message=%3C/textarea%3E%3Csvg/onload=alert(domain)%3E&remotipart_submitted=x"
+    expect(page).to have_selector("textarea")
+    expect(find("textarea").value).to eq('</textarea><svg/onload=alert(domain)>')
+  end
+end
diff --git a/spec/features/prepended_spec.rb b/spec/features/prepended_spec.rb
new file mode 100644
index 0000000..4b04107
--- /dev/null
+++ b/spec/features/prepended_spec.rb
@@ -0,0 +1,9 @@
+require 'spec_helper'
+
+describe 'prepended', type: :feature do
+  context "when another library overrides #render using prepend" do
+    it "does not break" do
+      expect { visit prepended_path }.not_to raise_error
+    end
+  end
+end
\ No newline at end of file
diff --git a/spec/fixtures/hi.txt b/spec/fixtures/hi.txt
new file mode 100644
index 0000000..444e00e
--- /dev/null
+++ b/spec/fixtures/hi.txt
@@ -0,0 +1 @@
+Smile, you're on candid camera!
diff --git a/spec/fixtures/qr.jpg b/spec/fixtures/qr.jpg
new file mode 100644
index 0000000..7078899
Binary files /dev/null and b/spec/fixtures/qr.jpg differ
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
new file mode 100644
index 0000000..cb165b8
--- /dev/null
+++ b/spec/spec_helper.rb
@@ -0,0 +1,40 @@
+# Configure Rails Envinronment
+ENV['RAILS_ENV'] = 'test'
+require File.expand_path('../dummy_app/config/environment', __FILE__)
+
+require 'rspec/rails'
+require 'capybara/rspec'
+require 'capybara/poltergeist'
+require 'database_cleaner'
+
+Capybara.javascript_driver = :poltergeist
+Capybara.server = :webrick
+Capybara.default_max_wait_time = 5
+
+# Requires supporting ruby files with custom matchers and macros, etc,
+# in spec/support/ and its subdirectories.
+Dir[File.expand_path('../support/**/*.rb', __FILE__)].each {|f| require f }
+
+RSpec.configure do |config|
+  load "#{Rails.root.to_s}/db/schema.rb" # use db agnostic schema by default
+
+  config.mock_with :rspec
+  config.expect_with :rspec do |c|
+    c.syntax = :expect
+  end
+  config.fixture_path = File.expand_path('../fixtures', __FILE__)
+
+  config.include Rails.application.routes.url_helpers
+  config.include RSpec::Matchers
+  config.include Capybara::DSL, type: :feature
+  config.include IntegrationHelper, type: :feature
+
+  config.before do |example|
+    DatabaseCleaner.strategy = :truncation
+    DatabaseCleaner.start
+  end
+
+  config.after(:each) do
+    DatabaseCleaner.clean
+  end
+end
diff --git a/spec/support/arel_helper.rb b/spec/support/arel_helper.rb
new file mode 100644
index 0000000..a36f006
--- /dev/null
+++ b/spec/support/arel_helper.rb
@@ -0,0 +1,15 @@
+module Arel
+  module Visitors
+    class DepthFirst < Arel::Visitors::Visitor
+      alias :visit_Integer :terminal
+    end
+
+    class Dot < Arel::Visitors::Visitor
+      alias :visit_Integer :visit_String
+    end
+
+    class ToSql < Arel::Visitors::Visitor
+      alias :visit_Integer :literal
+    end
+  end
+end if Rails::VERSION::MAJOR == 3
diff --git a/spec/support/connection_helper.rb b/spec/support/connection_helper.rb
new file mode 100644
index 0000000..032520c
--- /dev/null
+++ b/spec/support/connection_helper.rb
@@ -0,0 +1,12 @@
+class ActiveRecord::Base
+  mattr_accessor :shared_connection
+  @@shared_connection = nil
+
+  def self.connection
+    @@shared_connection || retrieve_connection
+  end
+end
+
+# Forces all threads to share the same connection. This works on
+# Capybara because it starts the web server in a thread.
+ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
diff --git a/spec/support/integration_helper.rb b/spec/support/integration_helper.rb
new file mode 100644
index 0000000..d3e0119
--- /dev/null
+++ b/spec/support/integration_helper.rb
@@ -0,0 +1,28 @@
+module IntegrationHelper
+  # If you do something that triggers a confirm, do it inside an accept_js_confirm or reject_js_confirm block
+  def accept_js_confirm
+    page.evaluate_script 'window.original_confirm_function = window.confirm;'
+    page.evaluate_script 'window.confirm = function(msg) { return true; }'
+    yield
+    page.evaluate_script 'window.confirm = window.original_confirm_function;'
+  end
+
+  # If you do something that triggers a confirm, do it inside an accept_js_confirm or reject_js_confirm block
+  def reject_js_confirm
+    page.evaluate_script 'window.original_confirm_function = window.confirm;'
+    page.evaluate_script 'window.confirm = function(msg) { return false; }'
+    yield
+    page.evaluate_script 'window.confirm = window.original_confirm_function;'
+  end
+
+  # Test that page doesn't redirect (there is probably a much better, built-in way to
+  # test this, I just don't know it.
+  def page_should_not_redirect
+    path = current_path
+    text = "bleep bloop"
+    page.execute_script "var txt = document.createTextNode('#{text}');document.body.appendChild(txt);"
+    yield
+    expect(current_path).to eq path
+    expect(page).to have_content(text)
+  end
+end
diff --git a/vendor/assets/javascripts/jquery.iframe-transport.js b/vendor/assets/javascripts/jquery.iframe-transport.js
index 3e9af1d..2b5bdb5 100644
--- a/vendor/assets/javascripts/jquery.iframe-transport.js
+++ b/vendor/assets/javascripts/jquery.iframe-transport.js
@@ -1,12 +1,12 @@
-// This [jQuery](http://jquery.com/) plugin implements an `<iframe>`
-// [transport](http://api.jquery.com/extending-ajax/#Transports) so that
+// This [jQuery](https://jquery.com/) plugin implements an `<iframe>`
+// [transport](https://api.jquery.com/jQuery.ajax/#extending-ajax) so that
 // `$.ajax()` calls support the uploading of files using standard HTML file
 // input fields. This is done by switching the exchange from `XMLHttpRequest`
 // to a hidden `iframe` element containing a form that is submitted.
 
-// The [source for the plugin](http://github.com/cmlenz/jquery-iframe-transport)
-// is available on [Github](http://github.com/) and dual licensed under the MIT
-// or GPL Version 2 licenses.
+// The [source for the plugin](https://github.com/cmlenz/jquery-iframe-transport)
+// is available on [Github](https://github.com/) and licensed under the [MIT
+// license](https://github.com/cmlenz/jquery-iframe-transport/blob/master/LICENSE).
 
 // ## Usage
 
@@ -70,9 +70,9 @@
 // impossible for the javascript code to determine the HTTP status code of the
 // servers response. Effectively, all of the calls you make will look like they
 // are getting successful responses, and thus invoke the `done()` or
-// `complete()` callbacks. You can only determine communicate problems using
-// the content of the response payload. For example, consider using a JSON
-// response such as the following to indicate a problem with an uploaded file:
+// `complete()` callbacks. You can only communicate problems using the content
+// of the response payload. For example, consider using a JSON response such as
+// the following to indicate a problem with an uploaded file:
 
 //     <textarea data-type="application/json">
 //       {"ok": false, "message": "Please only upload reasonably sized files."}
@@ -96,6 +96,7 @@
   // switches to the "iframe" data type if it is `true`.
   $.ajaxPrefilter(function(options, origOptions, jqXHR) {
     if (options.iframe) {
+      options.originalURL = options.url;
       return "iframe";
     }
   });
@@ -109,16 +110,19 @@
         name = "iframe-" + $.now(),
         files = $(options.files).filter(":file:enabled"),
         markers = null,
-        accepts;
+        accepts = null;
 
     // This function gets called after a successful submission or an abortion
     // and should revert all changes made to the page to enable the
     // submission via this transport.
     function cleanUp() {
-      markers.prop('disabled', false);
+      files.each(function(i, file) {
+        var $file = $(file);
+        $file.data("clone").replaceWith($file);
+      });
       form.remove();
-      iframe.bind("load", function() { iframe.remove(); });
-      iframe.attr("src", "javascript:false;");
+      iframe.one("load", function() { iframe.remove(); });
+      iframe.attr("src", "about:blank");
     }
 
     // Remove "iframe" from the data types list so that further processing is
@@ -126,9 +130,14 @@
     // (unsupported) conversion from "iframe" to the actual type.
     options.dataTypes.shift();
 
+    // Use the data from the original AJAX options, as it doesn't seem to be 
+    // copied over since jQuery 1.7.
+    // See https://github.com/cmlenz/jquery-iframe-transport/issues/6
+    options.data = origOptions.data;
+
     if (files.length) {
       form = $("<form enctype='multipart/form-data' method='post'></form>").
-        hide().attr({action: options.url, target: name});
+        hide().attr({action: options.originalURL, target: name});
 
       // If there is any additional data specified via the `data` option,
       // we add it as hidden fields to the form. This (currently) requires
@@ -152,21 +161,27 @@
       $("<input type='hidden' value='IFrame' name='X-Requested-With' />").
         appendTo(form);
 
-      // Borrowed straight from the JQuery source
-      // Provides a way of specifying the accepted data type similar to HTTP_ACCEPTS
-      accepts = options.dataTypes[ 0 ] && options.accepts[ options.dataTypes[0] ] ?
-        options.accepts[ options.dataTypes[0] ] + ( options.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
-        options.accepts[ "*" ]
-
-      $("<input type='hidden' name='X-Http-Accept'>")
-        .attr("value", accepts).appendTo(form);
+      // Borrowed straight from the JQuery source.
+      // Provides a way of specifying the accepted data type similar to the
+      // HTTP "Accept" header
+      if (options.dataTypes[0] && options.accepts[options.dataTypes[0]]) {
+        accepts = options.accepts[options.dataTypes[0]] +
+                  (options.dataTypes[0] !== "*" ? ", */*; q=0.01" : "");
+      } else {
+        accepts = options.accepts["*"];
+      }
+      $("<input type='hidden' name='X-HTTP-Accept'>").
+        attr("value", accepts).appendTo(form);
 
       // Move the file fields into the hidden form, but first remember their
       // original locations in the document by replacing them with disabled
       // clones. This should also avoid introducing unwanted changes to the
       // page layout during submission.
       markers = files.after(function(idx) {
-        return $(this).clone().prop("disabled", true);
+        var $this = $(this),
+            $clone = $this.clone().prop("disabled", true);
+        $this.data("clone", $clone);
+        return $clone;
       }).next();
       files.appendTo(form);
 
@@ -175,18 +190,18 @@
         // The `send` function is called by jQuery when the request should be
         // sent.
         send: function(headers, completeCallback) {
-          iframe = $("<iframe src='javascript:false;' name='" + name +
+          iframe = $("<iframe src='about:blank' name='" + name +
             "' id='" + name + "' style='display:none'></iframe>");
 
           // The first load event gets fired after the iframe has been injected
           // into the DOM, and is used to prepare the actual submission.
-          iframe.bind("load", function() {
+          iframe.one("load", function() {
 
             // The second load event gets fired when the response to the form
             // submission is received. The implementation detects whether the
             // actual payload is embedded in a `<textarea>` element, and
             // prepares the required conversions to be made in that case.
-            iframe.unbind("load").bind("load", function() {
+            iframe.one("load", function() {
               var doc = this.contentWindow ? this.contentWindow.document :
                 (this.contentDocument ? this.contentDocument : this.document),
                 root = doc.documentElement ? doc.documentElement : doc.body,
@@ -195,7 +210,6 @@
                 status = textarea && textarea.getAttribute("data-status") || 200,
                 statusText = textarea && textarea.getAttribute("data-statusText") || "OK",
                 content = {
-                  html: root.innerHTML,
                   text: type ?
                     textarea.value :
                     root ? (root.textContent || root.innerText) : null
@@ -223,7 +237,7 @@
         // aborted.
         abort: function() {
           if (iframe !== null) {
-            iframe.unbind("load").attr("src", "javascript:false;");
+            iframe.unbind("load").attr("src", "about:blank");
             cleanUp();
           }
         }
diff --git a/vendor/assets/javascripts/jquery.remotipart.js b/vendor/assets/javascripts/jquery.remotipart.js
index 61dcedf..e6cf51c 100644
--- a/vendor/assets/javascripts/jquery.remotipart.js
+++ b/vendor/assets/javascripts/jquery.remotipart.js
@@ -51,7 +51,9 @@
           // Allow remotipartSubmit to be cancelled if needed
           if ($.rails.fire(form, 'ajax:remotipartSubmit', [xhr, settings])) {
             // Second verse, same as the first
-            $.rails.ajax(settings);
+            $.rails.ajax(settings).always(function(data){
+              $.rails.fire(form, 'ajax:remotipartComplete', [data]);
+            });
             setTimeout(function(){ $.rails.disableFormElements(form); }, 20);
           }