Skip to content
Browse files

update for newer gems

  • Loading branch information...
1 parent ab6a4f3 commit 3ca4fe2eed07087387e98110dfbc1f250b6e657c @fortuity committed Apr 19, 2011
View
16 .gitignore
@@ -1,5 +1,11 @@
#----------------------------------------------------------------------------
# Ignore these files when commiting to a git repository
+#
+# The original version of this file is found here:
+# https://github.com/fortuity/rails3-gitignore/raw/master/gitignore.txt
+#
+# Corrections? Improvements? Create a GitHub issue:
+# https://github.com/fortuity/rails3-gitignore/issues
#----------------------------------------------------------------------------
# bundler state
@@ -27,12 +33,10 @@ tmp/*
/doc/app/
/doc/features.html
/doc/specs.html
-/log/*
/public/cache
/public/stylesheets/compiled
/public/system
/spec/tmp/*
-/tmp/*
/cache
/capybara*
/capybara-*.html
@@ -46,14 +50,14 @@ tmp/*
# scm revert files
**.orig
-# mac finder poop
+# Mac finder artifacts
.DS_Store
-# netbeans project directory
+# Netbeans project directory
/nbproject/
-# textmate project files
+# Textmate project files
/*.tmpproj
-# vim poop
+# vim artifacts
**.swp
View
22 Gemfile
@@ -1,12 +1,12 @@
source 'http://rubygems.org'
-gem 'rails', '>= 3.0.5'
-gem 'mongoid', '>= 2.0.0.rc.8'
-gem "bson_ext", ">= 1.2.4"
-gem "rspec-rails", ">= 2.5", :group => [:development, :test]
-gem 'database_cleaner', '>= 0.6.6', :group => :test
-gem 'cucumber-rails', ">= 0.4.0", :group => :test
-gem 'capybara', ">= 0.4.1.2", :group => :test
-gem "devise", ">= 1.2.0"
-gem 'mongoid-rspec', ">= 1.4.1", :group => :test
-gem 'factory_girl_rails', ">= 1.1.beta1", :group => :test
-gem 'relish', ">= 0.2.2", :group => :development
+gem 'rails', '3.0.6'
+gem "rspec-rails", ">= 2.5.0", :group => [:development, :test]
+gem "database_cleaner", ">= 0.6.6", :group => :test
+gem "mongoid-rspec", ">= 1.4.1", :group => :test
+gem "factory_girl_rails", ">= 1.1.beta1", :group => :test
+gem "cucumber-rails", ">= 0.4.1", :group => :test
+gem "capybara", ">= 0.4.1.2", :group => :test
+gem "launchy", ">= 0.4.0", :group => :test
+gem "bson_ext", ">= 1.3.0"
+gem "mongoid", ">= 2.0.1"
+gem "devise", ">= 1.3.0"
View
2 config/cucumber.yml
@@ -1,7 +1,7 @@
<%
rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
-std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} --strict --tags ~@wip"
+std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip"
%>
default: <%= std_opts %> features
wip: --tags @wip:3 --wip features
View
41 config/initializers/devise.rb
@@ -3,7 +3,7 @@
Devise.setup do |config|
# ==> Mailer Configuration
# Configure the e-mail address which will be shown in DeviseMailer.
- config.mailer_sender = "please-change-me@config-initializers-devise.com"
+ config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"
# Configure the class responsible to send e-mails.
# config.mailer = "Devise::Mailer"
@@ -34,7 +34,7 @@
# Configure which authentication keys should be case-insensitive.
# These keys will be downcased upon creating or modifying a user and when used
# to authenticate or find a user. Default is :email.
- # config.case_insensitive_keys = [ :email ]
+ config.case_insensitive_keys = [ :email ]
# Tell if authentication through request.params is enabled. True by default.
# config.params_authenticatable = true
@@ -53,6 +53,9 @@
# using other encryptors, it sets how many times you want the password re-encrypted.
config.stretches = 10
+ # Setup a pepper to generate the encrypted password.
+ # config.pepper = "ea6d4816b271609531c57e1996b9f6f3c91bc3ed272ebad3f842d8bf860534ddc23ae524d199316e8bf96dc15e11cbb42a6e3a275c9011638093dc78cce87565"
+
# ==> Configuration for :confirmable
# The time you want to give your user to confirm his account. During this time
# he will be able to access your application without confirming. Default is 0.days
@@ -62,6 +65,9 @@
# (ie 2 days).
# config.confirm_within = 2.days
+ # Defines which key will be used when confirming an account
+ # config.confirmation_keys = [ :email ]
+
# ==> Configuration for :rememberable
# The time the user will be remembered without asking for credentials again.
# config.remember_for = 2.weeks
@@ -76,12 +82,16 @@
# to false if you are not using database authenticatable.
config.use_salt_as_remember_token = true
+ # Options to be passed to the created cookie. For instance, you can set
+ # :secure => true in order to force SSL only cookies.
+ # config.cookie_options = {}
+
# ==> Configuration for :validatable
- # Range for password length. Default is 6..20.
- # config.password_length = 6..20
+ # Range for password length. Default is 6..128.
+ # config.password_length = 6..128
# Regex to use to validate the email address
- # config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
+ # config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i
# ==> Configuration for :timeoutable
# The time you want to timeout the user session without activity. After this
@@ -94,6 +104,9 @@
# :none = No lock strategy. You should handle locking by yourself.
# config.lock_strategy = :failed_attempts
+ # Defines which key will be used when locking and unlocking an account
+ # config.unlock_keys = [ :email ]
+
# Defines which strategy will be used to unlock an account.
# :email = Sends an unlock link to the user email
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
@@ -108,6 +121,16 @@
# Time interval to unlock the account if :time is enabled as unlock_strategy.
# config.unlock_in = 1.hour
+ # ==> Configuration for :recoverable
+ #
+ # Defines which key will be used when recovering the password for an account
+ # config.reset_password_keys = [ :email ]
+
+ # Time interval you can reset your password with a reset password key.
+ # Don't put a too small interval or your users won't have the time to
+ # change their passwords.
+ config.reset_password_within = 2.hours
+
# ==> Configuration for :encryptable
# Allow you to use another encryption algorithm besides bcrypt (default). You can use
# :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
@@ -116,9 +139,6 @@
# REST_AUTH_SITE_KEY to pepper)
# config.encryptor = :sha512
- # Setup a pepper to generate the encrypted password.
- # config.pepper = "38981e01b70a2edd48a67dd520a79472b792b2e790ca30f4243224c7eb9050c1d02e0d9e15d4df7d1f752ee5653b93bde423bc2e6c0bfdf7023ac84700baa656"
-
# ==> Configuration for :token_authenticatable
# Defines name of the authentication token params key
# config.token_authentication_key = :auth_token
@@ -150,8 +170,9 @@
# If you have any extra navigational formats, like :iphone or :mobile, you
# should add them to the navigational formats lists.
#
- # The :"*/*" format below is required to match Internet Explorer requests.
- # config.navigational_formats = [:"*/*", :html]
+ # The :"*/*" and "*/*" formats below is required to match Internet
+ # Explorer requests.
+ # config.navigational_formats = [:"*/*", "*/*", :html]
# The default HTTP method used to sign out a resource. Default is :get.
# config.sign_out_via = :get
View
3 config/locales/devise.en.yml
@@ -1,3 +1,5 @@
+# Additional translations at http://github.com/plataformatec/devise/wiki/I18n
+
en:
errors:
messages:
@@ -10,6 +12,7 @@ en:
devise:
failure:
+ already_authenticated: 'You are already signed in.'
unauthenticated: 'You need to sign in or sign up before continuing.'
unconfirmed: 'You have to confirm your account before continuing.'
locked: 'Your account is locked.'
View
2 doc/README_FOR_APP
@@ -1,2 +0,0 @@
-Use this README file to introduce your application and point to useful places in the API for learning more.
-Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
View
172 features/step_definitions/web_steps.rb
@@ -1,21 +1,46 @@
-# IMPORTANT: This file is generated by cucumber-rails - edit at your own peril.
-# It is recommended to regenerate this file in the future when you upgrade to a
-# newer version of cucumber-rails. Consider adding your own code to a new file
-# instead of editing this one. Cucumber will automatically load all features/**/*.rb
-# files.
+# TL;DR: YOU SHOULD DELETE THIS FILE
+#
+# This file was generated by Cucumber-Rails and is only here to get you a head start
+# These step definitions are thin wrappers around the Capybara/Webrat API that lets you
+# visit pages, interact with widgets and make assertions about page content.
+#
+# If you use these step definitions as basis for your features you will quickly end up
+# with features that are:
+#
+# * Hard to maintain
+# * Verbose to read
+#
+# A much better approach is to write your own higher level step definitions, following
+# the advice in the following blog posts:
+#
+# * http://benmabey.com/2008/05/19/imperative-vs-declarative-scenarios-in-user-stories.html
+# * http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/
+# * http://elabs.se/blog/15-you-re-cuking-it-wrong
+#
require 'uri'
require 'cgi'
require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths"))
+require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "selectors"))
module WithinHelpers
def with_scope(locator)
- locator ? within(locator) { yield } : yield
+ locator ? within(*selector_for(locator)) { yield } : yield
end
end
World(WithinHelpers)
+# Single-line step scoper
+When /^(.*) within ([^:]+)$/ do |step, parent|
+ with_scope(parent) { When step }
+end
+
+# Multi-line step scoper
+When /^(.*) within ([^:]+):$/ do |step, parent, table_or_string|
+ with_scope(parent) { When "#{step}:", table_or_string }
+end
+
Given /^(?:|I )am on (.+)$/ do |page_name|
visit path_to(page_name)
end
@@ -24,28 +49,20 @@ def with_scope(locator)
visit path_to(page_name)
end
-When /^(?:|I )press "([^"]*)"(?: within "([^"]*)")?$/ do |button, selector|
- with_scope(selector) do
- click_button(button)
- end
+When /^(?:|I )press "([^"]*)"$/ do |button|
+ click_button(button)
end
-When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector|
- with_scope(selector) do
- click_link(link)
- end
+When /^(?:|I )follow "([^"]*)"$/ do |link|
+ click_link(link)
end
-When /^(?:|I )fill in "([^"]*)" with "([^"]*)"(?: within "([^"]*)")?$/ do |field, value, selector|
- with_scope(selector) do
- fill_in(field, :with => value)
- end
+When /^(?:|I )fill in "([^"]*)" with "([^"]*)"$/ do |field, value|
+ fill_in(field, :with => value)
end
-When /^(?:|I )fill in "([^"]*)" for "([^"]*)"(?: within "([^"]*)")?$/ do |value, field, selector|
- with_scope(selector) do
- fill_in(field, :with => value)
- end
+When /^(?:|I )fill in "([^"]*)" for "([^"]*)"$/ do |value, field|
+ fill_in(field, :with => value)
end
# Use this to fill in an entire form with data from a table. Example:
@@ -59,95 +76,70 @@ def with_scope(locator)
# TODO: Add support for checkbox, select og option
# based on naming conventions.
#
-When /^(?:|I )fill in the following(?: within "([^"]*)")?:$/ do |selector, fields|
- with_scope(selector) do
- fields.rows_hash.each do |name, value|
- When %{I fill in "#{name}" with "#{value}"}
- end
- end
-end
-
-When /^(?:|I )select "([^"]*)" from "([^"]*)"(?: within "([^"]*)")?$/ do |value, field, selector|
- with_scope(selector) do
- select(value, :from => field)
+When /^(?:|I )fill in the following:$/ do |fields|
+ fields.rows_hash.each do |name, value|
+ When %{I fill in "#{name}" with "#{value}"}
end
end
-When /^(?:|I )check "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector|
- with_scope(selector) do
- check(field)
- end
+When /^(?:|I )select "([^"]*)" from "([^"]*)"$/ do |value, field|
+ select(value, :from => field)
end
-When /^(?:|I )uncheck "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector|
- with_scope(selector) do
- uncheck(field)
- end
+When /^(?:|I )check "([^"]*)"$/ do |field|
+ check(field)
end
-When /^(?:|I )choose "([^"]*)"(?: within "([^"]*)")?$/ do |field, selector|
- with_scope(selector) do
- choose(field)
- end
+When /^(?:|I )uncheck "([^"]*)"$/ do |field|
+ uncheck(field)
end
-When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"(?: within "([^"]*)")?$/ do |path, field, selector|
- with_scope(selector) do
- attach_file(field, path)
- end
+When /^(?:|I )choose "([^"]*)"$/ do |field|
+ choose(field)
end
-Then /^(?:|I )should see JSON:$/ do |expected_json|
- require 'json'
- expected = JSON.pretty_generate(JSON.parse(expected_json))
- actual = JSON.pretty_generate(JSON.parse(response.body))
- expected.should == actual
+When /^(?:|I )attach the file "([^"]*)" to "([^"]*)"$/ do |path, field|
+ attach_file(field, File.expand_path(path))
end
-Then /^(?:|I )should see "([^"]*)"(?: within "([^"]*)")?$/ do |text, selector|
- with_scope(selector) do
- if page.respond_to? :should
- page.should have_content(text)
- else
- assert page.has_content?(text)
- end
+Then /^(?:|I )should see "([^"]*)"$/ do |text|
+ if page.respond_to? :should
+ page.should have_content(text)
+ else
+ assert page.has_content?(text)
end
end
-Then /^(?:|I )should see \/([^\/]*)\/(?: within "([^"]*)")?$/ do |regexp, selector|
+Then /^(?:|I )should see \/([^\/]*)\/$/ do |regexp|
regexp = Regexp.new(regexp)
- with_scope(selector) do
- if page.respond_to? :should
- page.should have_xpath('//*', :text => regexp)
- else
- assert page.has_xpath?('//*', :text => regexp)
- end
+
+ if page.respond_to? :should
+ page.should have_xpath('//*', :text => regexp)
+ else
+ assert page.has_xpath?('//*', :text => regexp)
end
end
-Then /^(?:|I )should not see "([^"]*)"(?: within "([^"]*)")?$/ do |text, selector|
- with_scope(selector) do
- if page.respond_to? :should
- page.should have_no_content(text)
- else
- assert page.has_no_content?(text)
- end
+Then /^(?:|I )should not see "([^"]*)"$/ do |text|
+ if page.respond_to? :should
+ page.should have_no_content(text)
+ else
+ assert page.has_no_content?(text)
end
end
-Then /^(?:|I )should not see \/([^\/]*)\/(?: within "([^"]*)")?$/ do |regexp, selector|
+Then /^(?:|I )should not see \/([^\/]*)\/$/ do |regexp|
regexp = Regexp.new(regexp)
- with_scope(selector) do
- if page.respond_to? :should
- page.should have_no_xpath('//*', :text => regexp)
- else
- assert page.has_no_xpath?('//*', :text => regexp)
- end
+
+ if page.respond_to? :should
+ page.should have_no_xpath('//*', :text => regexp)
+ else
+ assert page.has_no_xpath?('//*', :text => regexp)
end
end
-Then /^the "([^"]*)" field(?: within "([^"]*)")? should contain "([^"]*)"$/ do |field, selector, value|
- with_scope(selector) do
+Then /^the "([^"]*)" field(?: within (.*))? should contain "([^"]*)"$/ do |field, parent, value|
+ with_scope(parent) do
field = find_field(field)
field_value = (field.tag_name == 'textarea') ? field.text : field.value
if field_value.respond_to? :should
@@ -158,8 +150,8 @@ def with_scope(locator)
end
end
-Then /^the "([^"]*)" field(?: within "([^"]*)")? should not contain "([^"]*)"$/ do |field, selector, value|
- with_scope(selector) do
+Then /^the "([^"]*)" field(?: within (.*))? should not contain "([^"]*)"$/ do |field, parent, value|
+ with_scope(parent) do
field = find_field(field)
field_value = (field.tag_name == 'textarea') ? field.text : field.value
if field_value.respond_to? :should_not
@@ -170,8 +162,8 @@ def with_scope(locator)
end
end
-Then /^the "([^"]*)" checkbox(?: within "([^"]*)")? should be checked$/ do |label, selector|
- with_scope(selector) do
+Then /^the "([^"]*)" checkbox(?: within (.*))? should be checked$/ do |label, parent|
+ with_scope(parent) do
field_checked = find_field(label)['checked']
if field_checked.respond_to? :should
field_checked.should be_true
@@ -181,8 +173,8 @@ def with_scope(locator)
end
end
-Then /^the "([^"]*)" checkbox(?: within "([^"]*)")? should not be checked$/ do |label, selector|
- with_scope(selector) do
+Then /^the "([^"]*)" checkbox(?: within (.*))? should not be checked$/ do |label, parent|
+ with_scope(parent) do
field_checked = find_field(label)['checked']
if field_checked.respond_to? :should
field_checked.should be_false
View
51 features/support/env.rb
@@ -4,42 +4,37 @@
# instead of editing this one. Cucumber will automatically load all features/**/*.rb
# files.
-ENV["RAILS_ENV"] ||= "test"
-require File.expand_path(File.dirname(__FILE__) + '/../../config/environment')
+require 'cucumber/rails'
-require 'cucumber/formatter/unicode' # Remove this line if you don't want Cucumber Unicode support
-require 'cucumber/rails/rspec'
-require 'cucumber/rails/world'
-require 'cucumber/web/tableish'
-
-require 'capybara/rails'
-require 'capybara/cucumber'
-require 'capybara/session'
-# see https://github.com/aslakhellesoy/cucumber-rails/issues/closed/#issue/77 re capybara_javascript_emulation
-# require 'cucumber/rails/capybara_javascript_emulation' # Lets you click links with onclick javascript handlers without using @culerity or @javascript
# Capybara defaults to XPath selectors rather than Webrat's default of CSS3. In
# order to ease the transition to Capybara we set the default here. If you'd
# prefer to use XPath just remove this line and adjust any selectors in your
# steps to use the XPath syntax.
Capybara.default_selector = :css
-# If you set this to false, any error raised from within your app will bubble
-# up to your step definition and out to cucumber unless you catch it somewhere
-# on the way. You can make Rails rescue errors and render error pages on a
-# per-scenario basis by tagging a scenario or feature with the @allow-rescue tag.
+# By default, any exception happening in your Rails application will bubble up
+# to Cucumber so that your scenario will fail. This is a different from how
+# your application behaves in the production environment, where an error page will
+# be rendered instead.
+#
+# Sometimes we want to override this default behaviour and allow Rails to rescue
+# exceptions and display an error page (just like when the app is running in production).
+# Typical scenarios where you want to do this is when you test your error pages.
+# There are two ways to allow Rails to rescue exceptions:
+#
+# 1) Tag your scenario (or feature) with @allow-rescue
+#
+# 2) Set the value below to true. Beware that doing this globally is not
+# recommended as it will mask a lot of errors for you!
#
-# If you set this to true, Rails will rescue all errors and render error
-# pages, more or less in the same way your application would behave in the
-# default production environment. It's not recommended to do this for all
-# of your scenarios, as this makes it hard to discover errors in your application.
ActionController::Base.allow_rescue = false
-# How to clean your database when transactions are turned off. See
-# http://github.com/bmabey/database_cleaner for more info.
-if defined?(ActiveRecord::Base)
- begin
- require 'database_cleaner'
- DatabaseCleaner.strategy = :truncation
- rescue LoadError => ignore_if_database_cleaner_not_present
- end
+# Remove/comment out the lines below if your app doesn't have a database.
+# For some databases (like MongoDB and CouchDB) you may need to use :truncation instead.
+begin
+ DatabaseCleaner.orm = 'mongoid'
+ DatabaseCleaner.strategy = :truncation
+rescue NameError
+ raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end
+
View
4 features/support/local_env.rb
@@ -1,4 +0,0 @@
-require 'database_cleaner'
-DatabaseCleaner.strategy = :truncation
-DatabaseCleaner.orm = "mongoid"
-Before { DatabaseCleaner.clean }
View
39 features/support/selectors.rb
@@ -0,0 +1,39 @@
+module HtmlSelectorsHelpers
+ # Maps a name to a selector. Used primarily by the
+ #
+ # When /^(.+) within (.+)$/ do |step, scope|
+ #
+ # step definitions in web_steps.rb
+ #
+ def selector_for(locator)
+ case locator
+
+ when /the page/
+ "html > body"
+
+ # Add more mappings here.
+ # Here is an example that pulls values out of the Regexp:
+ #
+ # when /the (notice|error|info) flash/
+ # ".flash.#{$1}"
+
+ # You can also return an array to use a different selector
+ # type, like:
+ #
+ # when /the header/
+ # [:xpath, "//header"]
+
+ # This allows you to provide a quoted selector as the scope
+ # for "within" steps as was previously the default for the
+ # web steps:
+ when /"(.+)"/
+ $1
+
+ else
+ raise "Can't find mapping from \"#{locator}\" to a selector.\n" +
+ "Now, go and add a mapping in #{__FILE__}"
+ end
+ end
+end
+
+World(HtmlSelectorsHelpers)
View
6 public/javascripts/jquery.js
3 additions, 3 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
319 public/javascripts/rails.js
@@ -3,155 +3,256 @@
*
* Requires jQuery 1.4.3 or later.
* https://github.com/rails/jquery-ujs
+
+ * Uploading file using rails.js
+ *
+ * By default, browsers do not allow files to be uploaded via AJAX. As a result, if there are any non-blank file fields
+ * in the remote form, this adapter aborts the AJAX submission and submits the form through standard means.
+ *
+ * When AJAX submission is aborted then event `ajax:aborted:file` is fired and this allows you to bind your own
+ * handler to process the form submission the way you want.
+ *
+ * For example if you want remote form submission to be cancelled and you do not want to submit the form through
+ * standard means then you can write following handler.
+ *
+ * Ex:
+ * $('form').live('ajax:aborted:file', function(){
+ * // Implement own remote file-transfer handler here.
+ * return false;
+ * });
+ *
+ * The `ajax:aborted:file` event is fired when a form is submitted and both conditions are met:
+ * a) file-type input field is detected, and
+ * b) the value of the input:file field is not blank.
+ *
+ * Third-party tools can use this hook to detect when an AJAX file upload is attempted, and then use
+ * techniques like the iframe method to upload the file instead.
+ *
+ * Similarly, rails.js aborts AJAX form submissions if any non-blank input[required] fields are detected,
+ * providing the `ajax:aborted:required` hook.
+ * Unlike file uploads, however, blank required input fields cancel the whole form submission by default.
+ *
+ * The default behavior of aborting the remote form submission when required inputs are missing, may be
+ * changed (thereby submitting the form via AJAX anyway) by binding a handler function that returns
+ * false to the `ajax:aborted:required` hook.
+ *
+ * Ex:
+ * $('form').live('ajax:aborted:required', function(){
+ * return ! confirm("Would you like to submit the form with missing info?");
+ * });
*/
(function($) {
- // Make sure that every Ajax request sends the CSRF token
- function CSRFProtection(xhr) {
- var token = $('meta[name="csrf-token"]').attr('content');
- if (token) xhr.setRequestHeader('X-CSRF-Token', token);
- }
- if ('ajaxPrefilter' in $) $.ajaxPrefilter(function(options, originalOptions, xhr){ CSRFProtection(xhr) });
- else $(document).ajaxSend(function(e, xhr){ CSRFProtection(xhr) });
-
- // Triggers an event on an element and returns the event result
- function fire(obj, name, data) {
- var event = new $.Event(name);
- obj.trigger(event, data);
- return event.result !== false;
- }
- // Submits "remote" forms and links with ajax
- function handleRemote(element) {
- var method, url, data,
- dataType = element.attr('data-type') || ($.ajaxSettings && $.ajaxSettings.dataType);
-
- if (element.is('form')) {
- method = element.attr('method');
- url = element.attr('action');
- data = element.serializeArray();
- // memoized value from clicked submit button
- var button = element.data('ujs:submit-button');
- if (button) {
- data.push(button);
- element.data('ujs:submit-button', null);
- }
- } else {
- method = element.attr('data-method');
- url = element.attr('href');
- data = null;
- }
+ // Shorthand to make it a little easier to call public rails functions from within rails.js
+ var rails;
+
+ $.rails = rails = {
+
+ // Make sure that every Ajax request sends the CSRF token
+ CSRFProtection: function(xhr) {
+ var token = $('meta[name="csrf-token"]').attr('content');
+ if (token) xhr.setRequestHeader('X-CSRF-Token', token);
+ },
+
+ // Triggers an event on an element and returns false if the event result is false
+ fire: function(obj, name, data) {
+ var event = $.Event(name);
+ obj.trigger(event, data);
+ return event.result !== false;
+ },
- $.ajax({
- url: url, type: method || 'GET', data: data, dataType: dataType,
- // stopping the "ajax:beforeSend" event will cancel the ajax request
- beforeSend: function(xhr, settings) {
- if (settings.dataType === undefined) {
- xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
+ // Submits "remote" forms and links with ajax
+ handleRemote: function(element) {
+ var method, url, data,
+ dataType = element.data('type') || ($.ajaxSettings && $.ajaxSettings.dataType);
+
+ if (rails.fire(element, 'ajax:before')) {
+
+ if (element.is('form')) {
+ method = element.attr('method');
+ url = element.attr('action');
+ data = element.serializeArray();
+ // memoized value from clicked submit button
+ var button = element.data('ujs:submit-button');
+ if (button) {
+ data.push(button);
+ element.data('ujs:submit-button', null);
+ }
+ } else {
+ method = element.data('method');
+ url = element.attr('href');
+ data = null;
}
- return fire(element, 'ajax:beforeSend', [xhr, settings]);
- },
- success: function(data, status, xhr) {
- element.trigger('ajax:success', [data, status, xhr]);
- },
- complete: function(xhr, status) {
- element.trigger('ajax:complete', [xhr, status]);
- },
- error: function(xhr, status, error) {
- element.trigger('ajax:error', [xhr, status, error]);
+
+ $.ajax({
+ url: url, type: method || 'GET', data: data, dataType: dataType,
+ // stopping the "ajax:beforeSend" event will cancel the ajax request
+ beforeSend: function(xhr, settings) {
+ if (settings.dataType === undefined) {
+ xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
+ }
+ return rails.fire(element, 'ajax:beforeSend', [xhr, settings]);
+ },
+ success: function(data, status, xhr) {
+ element.trigger('ajax:success', [data, status, xhr]);
+ },
+ complete: function(xhr, status) {
+ element.trigger('ajax:complete', [xhr, status]);
+ },
+ error: function(xhr, status, error) {
+ element.trigger('ajax:error', [xhr, status, error]);
+ }
+ });
}
- });
- }
+ },
- // Handles "data-method" on links such as:
- // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
- function handleMethod(link) {
- var href = link.attr('href'),
- method = link.attr('data-method'),
- csrf_token = $('meta[name=csrf-token]').attr('content'),
- csrf_param = $('meta[name=csrf-param]').attr('content'),
- form = $('<form method="post" action="' + href + '"></form>'),
- metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';
-
- if (csrf_param !== undefined && csrf_token !== undefined) {
- metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
- }
+ // Handles "data-method" on links such as:
+ // <a href="/users/5" data-method="delete" rel="nofollow" data-confirm="Are you sure?">Delete</a>
+ handleMethod: function(link) {
+ var href = link.attr('href'),
+ method = link.data('method'),
+ csrf_token = $('meta[name=csrf-token]').attr('content'),
+ csrf_param = $('meta[name=csrf-param]').attr('content'),
+ form = $('<form method="post" action="' + href + '"></form>'),
+ metadata_input = '<input name="_method" value="' + method + '" type="hidden" />';
- form.hide().append(metadata_input).appendTo('body');
- form.submit();
- }
+ if (csrf_param !== undefined && csrf_token !== undefined) {
+ metadata_input += '<input name="' + csrf_param + '" value="' + csrf_token + '" type="hidden" />';
+ }
- function disableFormElements(form) {
- form.find('input[data-disable-with]').each(function() {
- var input = $(this);
- input.data('ujs:enable-with', input.val())
- .val(input.attr('data-disable-with'))
- .attr('disabled', 'disabled');
- });
- }
+ form.hide().append(metadata_input).appendTo('body');
+ form.submit();
+ },
- function enableFormElements(form) {
- form.find('input[data-disable-with]').each(function() {
- var input = $(this);
- input.val(input.data('ujs:enable-with')).removeAttr('disabled');
- });
- }
+ disableFormElements: function(form) {
+ form.find('input[data-disable-with], button[data-disable-with]').each(function() {
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
+ element.data('ujs:enable-with', element[method]());
+ element[method](element.data('disable-with'));
+ element.attr('disabled', 'disabled');
+ });
+ },
- function allowAction(element) {
- var message = element.attr('data-confirm');
- return !message || (fire(element, 'confirm') && confirm(message));
- }
+ enableFormElements: function(form) {
+ form.find('input[data-disable-with]:disabled, button[data-disable-with]:disabled').each(function() {
+ var element = $(this), method = element.is('button') ? 'html' : 'val';
+ if (element.data('ujs:enable-with')) element[method](element.data('ujs:enable-with'));
+ element.removeAttr('disabled');
+ });
+ },
+
+ allowAction: function(element) {
+ var message = element.data('confirm');
+ return !message || (rails.fire(element, 'confirm') && confirm(message));
+ },
+
+ blankInputs: function(form, specifiedSelector) {
+ var blankExists = false,
+ selector = specifiedSelector || 'input';
+ form.find(selector).each(function() {
+ if (!$(this).val()) {
+ blankExists = true;
+ return false; //this terminates the each loop
+ }
+ });
+ return blankExists;
+ },
+
+ nonBlankInputs: function(form, specifiedSelector) {
+ var nonBlankExists = false,
+ selector = specifiedSelector || 'input';
+ form.find(selector).each(function() {
+ if ($(this).val()) {
+ nonBlankExists = true;
+ return false; //this terminates the each loop
+ }
+ });
+ return nonBlankExists;
+ },
- function requiredValuesMissing(form) {
- var missing = false;
- form.find('input[name][required]').each(function() {
- if (!$(this).val()) missing = true;
- });
- return missing;
+ stopEverything: function(e) {
+ e.stopImmediatePropagation();
+ return false;
+ },
+
+ // find all the submit events directly bound to the form and
+ // manually invoke them. If anyone returns false then stop the loop
+ callFormSubmitBindings: function(form) {
+ var events = form.data('events'), continuePropagation = true;
+ if (events !== undefined && events['submit'] !== undefined) {
+ $.each(events['submit'], function(i, obj){
+ if (typeof obj.handler === 'function') return continuePropagation = obj.handler(obj.data);
+ });
+ }
+ return continuePropagation;
+ }
+ };
+
+ // ajaxPrefilter is a jQuery 1.5 feature
+ if ('ajaxPrefilter' in $) {
+ $.ajaxPrefilter(function(options, originalOptions, xhr){ rails.CSRFProtection(xhr); });
+ } else {
+ $(document).ajaxSend(function(e, xhr){ rails.CSRFProtection(xhr); });
}
$('a[data-confirm], a[data-method], a[data-remote]').live('click.rails', function(e) {
var link = $(this);
- if (!allowAction(link)) return false;
+ if (!rails.allowAction(link)) return rails.stopEverything(e);
- if (link.attr('data-remote') != undefined) {
- handleRemote(link);
+ if (link.data('remote') !== undefined) {
+ rails.handleRemote(link);
return false;
- } else if (link.attr('data-method')) {
- handleMethod(link);
+ } else if (link.data('method')) {
+ rails.handleMethod(link);
return false;
}
});
$('form').live('submit.rails', function(e) {
- var form = $(this), remote = form.attr('data-remote') != undefined;
- if (!allowAction(form)) return false;
+ var form = $(this), remote = form.data('remote') !== undefined;
+ if (!rails.allowAction(form)) return rails.stopEverything(e);
+
+ // skip other logic when required values are missing or file upload is present
+ if (rails.blankInputs(form, 'input[name][required]') && rails.fire(form, 'ajax:aborted:required')) {
+ return !remote;
+ }
+
+ if (rails.nonBlankInputs(form, 'input:file')) {
+ return rails.fire(form, 'ajax:aborted:file');
+ }
- // skip other logic when required values are missing
- if (requiredValuesMissing(form)) return !remote;
+ // If browser does not support submit bubbling, then this live-binding will be called before direct
+ // bindings. Therefore, we should directly call any direct bindings before remotely submitting form.
+ if (!$.support.submitBubbles && rails.callFormSubmitBindings(form) === false) return rails.stopEverything(e);
if (remote) {
- handleRemote(form);
+ rails.handleRemote(form);
return false;
} else {
// slight timeout so that the submit button gets properly serialized
- setTimeout(function(){ disableFormElements(form) }, 13);
+ setTimeout(function(){ rails.disableFormElements(form); }, 13);
}
});
- $('form input[type=submit], form button[type=submit], form button:not([type])').live('click.rails', function() {
+ $('form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])').live('click.rails', function() {
var button = $(this);
- if (!allowAction(button)) return false;
+
+ if (!rails.allowAction(button)) return rails.stopEverything(e);
+
// register the pressed submit button
- var name = button.attr('name'), data = name ? {name:name, value:button.val()} : null;
+ var name = button.attr('name'),
+ data = name ? {name:name, value:button.val()} : null;
+
button.closest('form').data('ujs:submit-button', data);
});
-
+
$('form').live('ajax:beforeSend.rails', function(event) {
- if (this == event.target) disableFormElements($(this));
+ if (this == event.target) rails.disableFormElements($(this));
});
$('form').live('ajax:complete.rails', function(event) {
- if (this == event.target) enableFormElements($(this));
+ if (this == event.target) rails.enableFormElements($(this));
});
+
})( jQuery );
View
2 spec/support/devise.rb
@@ -1,3 +1,3 @@
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
-end
+end
View
2 spec/support/mongoid.rb
@@ -1,3 +1,3 @@
RSpec.configure do |config|
config.include Mongoid::Matchers
-end
+end

0 comments on commit 3ca4fe2

Please sign in to comment.
Something went wrong with that request. Please try again.