aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile3
-rw-r--r--actionpack/CHANGELOG40
-rw-r--r--actionpack/actionpack.gemspec22
-rw-r--r--actionpack/lib/abstract_controller/asset_paths.rb3
-rw-r--r--actionpack/lib/abstract_controller/rendering.rb4
-rw-r--r--actionpack/lib/action_controller/test_case.rb20
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb1
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb10
-rw-r--r--actionpack/lib/action_dispatch/routing/url_for.rb5
-rw-r--r--actionpack/lib/action_dispatch/testing/test_process.rb7
-rw-r--r--actionpack/lib/action_view/asset_paths.rb21
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb20
-rw-r--r--actionpack/lib/sprockets/assets.rake109
-rw-r--r--actionpack/lib/sprockets/helpers.rb3
-rw-r--r--actionpack/lib/sprockets/helpers/isolated_helper.rb13
-rw-r--r--actionpack/lib/sprockets/helpers/rails_helper.rb13
-rw-r--r--actionpack/lib/sprockets/railtie.rb8
-rw-r--r--actionpack/lib/sprockets/static_compiler.rb49
-rw-r--r--actionpack/test/controller/test_test.rb36
-rw-r--r--actionpack/test/controller/url_for_test.rb14
-rw-r--r--actionpack/test/dispatch/request_test.rb1
-rw-r--r--actionpack/test/template/sprockets_helper_test.rb41
-rw-r--r--actionpack/test/template/url_helper_test.rb4
-rw-r--r--activemodel/lib/active_model/serialization.rb25
-rw-r--r--activemodel/test/cases/serialization_test.rb6
-rw-r--r--activemodel/test/cases/serializers/json_serialization_test.rb10
-rw-r--r--activerecord/CHANGELOG26
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb7
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb6
-rw-r--r--activerecord/lib/active_record/attribute_methods/write.rb2
-rw-r--r--activerecord/lib/active_record/base.rb9
-rw-r--r--activerecord/lib/active_record/errors.rb14
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/persistence.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake2
-rw-r--r--activerecord/lib/active_record/reflection.rb4
-rw-r--r--activerecord/lib/active_record/relation.rb6
-rw-r--r--activerecord/lib/active_record/transactions.rb2
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb2
-rw-r--r--activerecord/test/cases/attribute_methods/read_test.rb4
-rw-r--r--activerecord/test/cases/base_test.rb4
-rw-r--r--activerecord/test/cases/primary_keys_test.rb14
-rw-r--r--activerecord/test/cases/reflection_test.rb1
-rw-r--r--activerecord/test/config.example.yml2
-rw-r--r--activeresource/lib/active_resource/base.rb4
-rw-r--r--activeresource/lib/active_resource/connection.rb5
-rw-r--r--activeresource/test/cases/authorization_test.rb6
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/range/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb24
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb2
-rw-r--r--activesupport/lib/active_support/json/encoding.rb4
-rw-r--r--activesupport/test/caching_test.rb8
-rw-r--r--activesupport/test/core_ext/time_ext_test.rb3
-rw-r--r--activesupport/test/rescuable_test.rb2
-rw-r--r--railties/CHANGELOG7
-rw-r--r--railties/guides/source/asset_pipeline.textile67
-rw-r--r--railties/lib/rails/application.rb2
-rw-r--r--railties/lib/rails/application/configuration.rb27
-rw-r--r--railties/lib/rails/commands/application.rb8
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/actions.rb4
-rw-r--r--railties/lib/rails/generators/rails/app/USAGE6
-rw-r--r--railties/lib/rails/initializable.rb5
-rw-r--r--railties/lib/rails/test_help.rb2
-rw-r--r--railties/test/application/assets_test.rb75
-rw-r--r--railties/test/application/configuration_test.rb8
-rw-r--r--railties/test/application/middleware/cache_test.rb14
-rw-r--r--railties/test/generators/actions_test.rb16
-rw-r--r--railties/test/initializable_test.rb4
71 files changed, 669 insertions, 238 deletions
diff --git a/Gemfile b/Gemfile
index a1585e279c..f63260a260 100644
--- a/Gemfile
+++ b/Gemfile
@@ -99,3 +99,6 @@ if ENV['ORACLE_ENHANCED_PATH'] || ENV['ORACLE_ENHANCED']
gem "activerecord-oracle_enhanced-adapter", :git => "git://github.com/rsim/oracle-enhanced.git"
end
end
+
+# A gem necessary for ActiveRecord tests with IBM DB
+gem "ibm_db" if ENV['IBM_DB']
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index c3ff677529..e8c619723f 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -56,6 +56,46 @@
*Rails 3.1.1 (unreleased)*
+* javascript_path and stylesheet_path now refer to /assets if asset pipelining
+is on. [Santiago Pastorino]
+
+* button_to support form option. Now you're able to pass for example
+'data-type' => 'json'. [ihower]
+
+* image_path and image_tag should use /assets if asset pipelining is turned
+on. Closes #3126 [Santiago Pastorino and christos]
+
+* Avoid use of existing precompiled assets during rake assets:precompile run.
+Closes #3119 [Guillermo Iguaran]
+
+* Copy assets to nondigested filenames too [Santiago Pastorino]
+
+* Give precedence to `config.digest = false` over the existence of
+manifest.yml asset digests [christos]
+
+* escape options for the stylesheet_link_tag method [Alexey Vakhov]
+
+* Re-launch assets:precompile task using (Rake.)ruby instead of Kernel.exec so
+it works on Windows [cablegram]
+
+* env var passed to process shouldn't be modified in process method. [Santiago
+Pastorino]
+
+* `rake assets:precompile` loads the application but does not initialize
+it.
+
+ To the app developer, this means configuration add in
+ config/initializers/* will not be executed.
+
+ Plugins developers need to special case their initializers that are
+ meant to be run in the assets group by adding :group => :assets. [José Valim]
+
+* Sprockets uses config.assets.prefix for asset_path [asee]
+
+* FileStore key_file_path properly limit filenames to 255 characters. [phuibonhoa]
+
+* Fix Hash#to_query edge case with html_safe strings. [brainopia]
+
* Allow asset tag helper methods to accept :digest => false option in order to completely avoid the digest generation.
Useful for linking assets from static html files or from emails when the user
could probably look at an older html email with an older asset. [Santiago Pastorino]
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index f1b7966b9c..96d583730a 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -16,16 +16,16 @@ Gem::Specification.new do |s|
s.require_path = 'lib'
s.requirements << 'none'
- s.add_dependency('activesupport', version)
- s.add_dependency('activemodel', version)
- s.add_dependency('rack-cache', '~> 1.0.3')
- s.add_dependency('builder', '~> 3.0.0')
- s.add_dependency('i18n', '~> 0.6')
- s.add_dependency('rack', '~> 1.3.2')
- s.add_dependency('rack-test', '~> 0.6.1')
- s.add_dependency('journey', '~> 1.0.0')
- s.add_dependency('sprockets', '~> 2.0.0')
- s.add_dependency('erubis', '~> 2.7.0')
+ s.add_dependency('activesupport', version)
+ s.add_dependency('activemodel', version)
+ s.add_dependency('rack-cache', '~> 1.1')
+ s.add_dependency('builder', '~> 3.0.0')
+ s.add_dependency('i18n', '~> 0.6')
+ s.add_dependency('rack', '~> 1.3.2')
+ s.add_dependency('rack-test', '~> 0.6.1')
+ s.add_dependency('journey', '~> 1.0.0')
+ s.add_dependency('sprockets', '~> 2.0.2')
+ s.add_dependency('erubis', '~> 2.7.0')
- s.add_development_dependency('tzinfo', '~> 0.3.29')
+ s.add_development_dependency('tzinfo', '~> 0.3.29')
end
diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb
index b104d34fb5..c2a6809f58 100644
--- a/actionpack/lib/abstract_controller/asset_paths.rb
+++ b/actionpack/lib/abstract_controller/asset_paths.rb
@@ -3,7 +3,8 @@ module AbstractController
extend ActiveSupport::Concern
included do
- config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir
+ config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir,
+ :stylesheets_dir, :default_asset_host_protocol
end
end
end
diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb
index ab2c532859..41fdc11196 100644
--- a/actionpack/lib/abstract_controller/rendering.rb
+++ b/actionpack/lib/abstract_controller/rendering.rb
@@ -120,8 +120,6 @@ module AbstractController
view_renderer.render(view_context, options)
end
- private
-
DEFAULT_PROTECTED_INSTANCE_VARIABLES = %w(
@_action_name @_response_body @_formats @_prefixes @_config
@_view_context_class @_view_renderer @_lookup_context
@@ -139,6 +137,8 @@ module AbstractController
hash
end
+ private
+
# Normalize args and options.
# :api: private
def _normalize_render(*args, &block)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index a83fa74795..6913c1ef4a 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -333,9 +333,21 @@ module ActionController
module ClassMethods
# Sets the controller class name. Useful if the name can't be inferred from test class.
- # Expects +controller_class+ as a constant. Example: <tt>tests WidgetController</tt>.
+ # Normalizes +controller_class+ before using. Examples:
+ #
+ # tests WidgetController
+ # tests :widget
+ # tests 'widget'
+ #
def tests(controller_class)
- self.controller_class = controller_class
+ case controller_class
+ when String, Symbol
+ self.controller_class = "#{controller_class.to_s.underscore}_controller".camelize.constantize
+ when Class
+ self.controller_class = controller_class
+ else
+ raise ArgumentError, "controller class must be a String, Symbol, or Class"
+ end
end
def controller_class=(new_class)
@@ -352,9 +364,7 @@ module ActionController
end
def determine_default_controller_class(name)
- name.sub(/Test$/, '').constantize
- rescue NameError
- nil
+ name.sub(/Test$/, '').safe_constantize
end
def prepare_controller_class(new_class)
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
index eaefdc0f15..af06bffa16 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb
@@ -1,4 +1,5 @@
require 'set'
+require 'cgi'
require 'active_support/core_ext/class/attribute'
module HTML
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index caa1decb9e..170c68f3e0 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -64,14 +64,16 @@ module ActionDispatch
end
def host_or_subdomain_and_domain(options)
- return options[:host] unless options[:subdomain] || options[:domain]
+ return options[:host] if options[:subdomain].nil? && options[:domain].nil?
tld_length = options[:tld_length] || @@tld_length
host = ""
- host << (options[:subdomain] || extract_subdomain(options[:host], tld_length))
- host << "."
- host << (options[:domain] || extract_domain(options[:host], tld_length))
+ unless options[:subdomain] == false
+ host << (options[:subdomain] || extract_subdomain(options[:host], tld_length))
+ host << "."
+ end
+ host << (options[:domain] || extract_domain(options[:host], tld_length))
host
end
end
diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb
index 30048cd48a..8fc8dc191b 100644
--- a/actionpack/lib/action_dispatch/routing/url_for.rb
+++ b/actionpack/lib/action_dispatch/routing/url_for.rb
@@ -116,9 +116,10 @@ module ActionDispatch
# If <tt>:only_path</tt> is false, this option must be
# provided either explicitly, or via +default_url_options+.
# * <tt>:subdomain</tt> - Specifies the subdomain of the link, using the +tld_length+
- # to split the domain from the host.
- # * <tt>:domain</tt> - Specifies the domain of the link, using the +tld_length+
# to split the subdomain from the host.
+ # If false, removes all subdomains from the host part of the link.
+ # * <tt>:domain</tt> - Specifies the domain of the link, using the +tld_length+
+ # to split the domain from the host.
# * <tt>:tld_length</tt> - Number of labels the TLD id composed of, only used if
# <tt>:subdomain</tt> or <tt>:domain</tt> are supplied. Defaults to
# <tt>ActionDispatch::Http::URL.tld_length</tt>, which in turn defaults to 1.
diff --git a/actionpack/lib/action_dispatch/testing/test_process.rb b/actionpack/lib/action_dispatch/testing/test_process.rb
index f668b81b45..b08ff41950 100644
--- a/actionpack/lib/action_dispatch/testing/test_process.rb
+++ b/actionpack/lib/action_dispatch/testing/test_process.rb
@@ -5,12 +5,7 @@ require 'active_support/core_ext/hash/indifferent_access'
module ActionDispatch
module TestProcess
def assigns(key = nil)
- assigns = {}.with_indifferent_access
- @controller.instance_variable_names.each do |ivar|
- next if ActionController::Base.protected_instance_variables.include?(ivar)
- assigns[ivar[1..-1]] = @controller.instance_variable_get(ivar)
- end
-
+ assigns = @controller.view_assigns.with_indifferent_access
key.nil? ? assigns : assigns[key]
end
diff --git a/actionpack/lib/action_view/asset_paths.rb b/actionpack/lib/action_view/asset_paths.rb
index cf30ad7e57..1d16e34df6 100644
--- a/actionpack/lib/action_view/asset_paths.rb
+++ b/actionpack/lib/action_view/asset_paths.rb
@@ -16,8 +16,6 @@ module ActionView
# roots. Rewrite the asset path for cache-busting asset ids. Include
# asset host, if configured, with the correct request protocol.
#
- # When include_host is true and the asset host does not specify the protocol
- # the protocol parameter specifies how the protocol will be added.
# When :relative (default), the protocol will be determined by the client using current protocol
# When :request, the protocol will be the request protocol
# Otherwise, the protocol is used (E.g. :http, :https, etc)
@@ -25,11 +23,10 @@ module ActionView
source = source.to_s
return source if is_uri?(source)
- options[:include_host] ||= true
source = rewrite_extension(source, dir, options[:ext]) if options[:ext]
source = rewrite_asset_path(source, dir, options)
source = rewrite_relative_url_root(source, relative_url_root)
- source = rewrite_host_and_protocol(source, options[:protocol]) if options[:include_host]
+ source = rewrite_host_and_protocol(source, options[:protocol])
source
end
@@ -89,9 +86,7 @@ module ActionView
end
def default_protocol
- protocol = @config.action_controller.default_asset_host_protocol if @config.action_controller.present?
- protocol ||= @config.default_asset_host_protocol
- protocol || (has_request? ? :request : :relative)
+ @config.default_asset_host_protocol || (has_request? ? :request : :relative)
end
def invalid_asset_host!(help_message)
@@ -120,19 +115,11 @@ module ActionView
end
def relative_url_root
- if config.action_controller.present?
- config.action_controller.relative_url_root
- else
- config.relative_url_root
- end
+ config.relative_url_root
end
def asset_host_config
- if config.action_controller.present?
- config.action_controller.asset_host
- else
- config.asset_host
- end
+ config.asset_host
end
# Returns the current request if one exists.
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index acd5e46e33..0c2e1aa3a9 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -279,6 +279,7 @@ module ActionView
# processed normally, otherwise no action is taken.
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
# submit behavior. By default this behavior is an ajax submit.
+ # * <tt>:form</tt> - This hash will be form attributes
# * <tt>:form_class</tt> - This controls the class of the form within which the submit button will
# be placed
#
@@ -295,6 +296,12 @@ module ActionView
# # </form>"
#
#
+ # <%= button_to "Create", :action => "create", :remote => true, :form => { "data-type" => "json" } %>
+ # # => "<form method="post" action="/images/create" class="button_to" data-remote="true" data-type="json">
+ # # <div><input value="Create" type="submit" /></div>
+ # # </form>"
+ #
+ #
# <%= button_to "Delete Image", { :action => "delete", :id => @image.id },
# :confirm => "Are you sure?", :method => :delete %>
# # => "<form method="post" action="/images/delete/1" class="button_to">
@@ -324,10 +331,11 @@ module ActionView
end
form_method = method.to_s == 'get' ? 'get' : 'post'
- form_class = html_options.delete('form_class') || 'button_to'
-
+ form_options = html_options.delete('form') || {}
+ form_options[:class] ||= html_options.delete('form_class') || 'button_to'
+
remote = html_options.delete('remote')
-
+
request_token_tag = ''
if form_method == 'post' && protect_against_forgery?
request_token_tag = tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token)
@@ -340,8 +348,10 @@ module ActionView
html_options.merge!("type" => "submit", "value" => name)
- ("<form method=\"#{form_method}\" action=\"#{ERB::Util.html_escape(url)}\" #{"data-remote=\"true\"" if remote} class=\"#{ERB::Util.html_escape(form_class)}\"><div>" +
- method_tag + tag("input", html_options) + request_token_tag + "</div></form>").html_safe
+ form_options.merge!(:method => form_method, :action => url)
+ form_options.merge!("data-remote" => "true") if remote
+
+ "#{tag(:form, form_options, true)}<div>#{method_tag}#{tag("input", html_options)}#{request_token_tag}</div></form>".html_safe
end
diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake
index e29661e4e7..a5145080c2 100644
--- a/actionpack/lib/sprockets/assets.rake
+++ b/actionpack/lib/sprockets/assets.rake
@@ -1,60 +1,95 @@
+require "fileutils"
+
namespace :assets do
+ def ruby_rake_task(task)
+ env = ENV['RAILS_ENV'] || 'production'
+ groups = ENV['RAILS_GROUPS'] || 'assets'
+ args = [$0, task,"RAILS_ENV=#{env}","RAILS_GROUPS=#{groups}"]
+ args << "--trace" if Rake.application.options.trace
+ ruby *args
+ end
+
+ # We are currently running with no explicit bundler group
+ # and/or no explicit environment - we have to reinvoke rake to
+ # execute this task.
+ def invoke_or_reboot_rake_task(task)
+ if ENV['RAILS_GROUPS'].to_s.empty? || ENV['RAILS_ENV'].to_s.empty?
+ ruby_rake_task task
+ else
+ Rake::Task[task].invoke
+ end
+ end
+
desc "Compile all the assets named in config.assets.precompile"
task :precompile do
- # We need to do this dance because RAILS_GROUPS is used
- # too early in the boot process and changing here is already too late.
- if ENV["RAILS_GROUPS"].to_s.empty? || ENV["RAILS_ENV"].to_s.empty?
- ENV["RAILS_GROUPS"] ||= "assets"
- ENV["RAILS_ENV"] ||= "production"
- ruby $0, *ARGV
- else
- require "fileutils"
- Rake::Task["tmp:cache:clear"].invoke
- Rake::Task["assets:environment"].invoke
+ invoke_or_reboot_rake_task "assets:precompile:all"
+ end
+ namespace :precompile do
+ def internal_precompile(digest=nil)
unless Rails.application.config.assets.enabled
- raise "Cannot precompile assets if sprockets is disabled. Please set config.assets.enabled to true"
+ warn "Cannot precompile assets if sprockets is disabled. Please set config.assets.enabled to true"
+ exit
end
- # Ensure that action view is loaded and the appropriate sprockets hooks get executed
- ActionView::Base
+ # Ensure that action view is loaded and the appropriate
+ # sprockets hooks get executed
+ _ = ActionView::Base
config = Rails.application.config
config.assets.compile = true
- config.assets.digest = false if ENV["RAILS_ASSETS_NONDIGEST"]
-
- env = Rails.application.assets
-
- # Always compile files and avoid use of existing precompiled assets
- config.assets.compile = true
+ config.assets.digest = digest unless digest.nil?
config.assets.digests = {}
- target = File.join(Rails.public_path, config.assets.prefix)
- static_compiler = Sprockets::StaticCompiler.new(env, target, :digest => config.assets.digest)
+ env = Rails.application.assets
+ target = File.join(Rails.public_path, config.assets.prefix)
+ compiler = Sprockets::StaticCompiler.new(env,
+ target,
+ config.assets.precompile,
+ :manifest_path => config.assets.manifest,
+ :digest => config.assets.digest,
+ :manifest => digest.nil?)
+ compiler.compile
+ end
- manifest = static_compiler.precompile(config.assets.precompile)
- manifest_path = config.assets.manifest || target
- FileUtils.mkdir_p(manifest_path)
+ task :all do
+ Rake::Task["assets:precompile:primary"].invoke
+ # We need to reinvoke in order to run the secondary digestless
+ # asset compilation run - a fresh Sprockets environment is
+ # required in order to compile digestless assets as the
+ # environment has already cached the assets on the primary
+ # run.
+ ruby_rake_task "assets:precompile:nondigest" if Rails.application.config.assets.digest
+ end
- unless ENV["RAILS_ASSETS_NONDIGEST"]
- File.open("#{manifest_path}/manifest.yml", 'wb') do |f|
- YAML.dump(manifest, f)
- end
- ENV["RAILS_ASSETS_NONDIGEST"] = "true"
- ruby $0, *ARGV
- end
+ task :primary => ["assets:environment", "tmp:cache:clear"] do
+ internal_precompile
+ end
+
+ task :nondigest => ["assets:environment", "tmp:cache:clear"] do
+ internal_precompile(false)
end
end
desc "Remove compiled assets"
- task :clean => ['assets:environment', 'tmp:cache:clear'] do
- config = Rails.application.config
- public_asset_path = File.join(Rails.public_path, config.assets.prefix)
- rm_rf public_asset_path, :secure => true
+ task :clean do
+ invoke_or_reboot_rake_task "assets:clean:all"
+ end
+
+ namespace :clean do
+ task :all => ["assets:environment", "tmp:cache:clear"] do
+ config = Rails.application.config
+ public_asset_path = File.join(Rails.public_path, config.assets.prefix)
+ rm_rf public_asset_path, :secure => true
+ end
end
task :environment do
- Rails.application.initialize!(:assets)
- Sprockets::Bootstrap.new(Rails.application).run
+ if Rails.application.config.assets.initialize_on_precompile
+ Rake::Task["environment"].invoke
+ else
+ Rails.application.initialize!(:assets)
+ Sprockets::Bootstrap.new(Rails.application).run
+ end
end
end
diff --git a/actionpack/lib/sprockets/helpers.rb b/actionpack/lib/sprockets/helpers.rb
index a952a55c5e..fee48386e0 100644
--- a/actionpack/lib/sprockets/helpers.rb
+++ b/actionpack/lib/sprockets/helpers.rb
@@ -1,5 +1,6 @@
module Sprockets
module Helpers
- autoload :RailsHelper, "sprockets/helpers/rails_helper"
+ autoload :RailsHelper, "sprockets/helpers/rails_helper"
+ autoload :IsolatedHelper, "sprockets/helpers/isolated_helper"
end
end
diff --git a/actionpack/lib/sprockets/helpers/isolated_helper.rb b/actionpack/lib/sprockets/helpers/isolated_helper.rb
new file mode 100644
index 0000000000..3adb928c45
--- /dev/null
+++ b/actionpack/lib/sprockets/helpers/isolated_helper.rb
@@ -0,0 +1,13 @@
+module Sprockets
+ module Helpers
+ module IsolatedHelper
+ def controller
+ nil
+ end
+
+ def config
+ Rails.application.config.action_controller
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb
index c8c6c3ddd9..f866bc626e 100644
--- a/actionpack/lib/sprockets/helpers/rails_helper.rb
+++ b/actionpack/lib/sprockets/helpers/rails_helper.rb
@@ -8,9 +8,6 @@ module Sprockets
def asset_paths
@asset_paths ||= begin
- config = self.config if respond_to?(:config)
- config ||= Rails.application.config
- controller = self.controller if respond_to?(:controller)
paths = RailsHelper::AssetPaths.new(config, controller)
paths.asset_environment = asset_environment
paths.asset_digests = asset_digests
@@ -65,6 +62,16 @@ module Sprockets
end
alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
+ def javascript_path(source)
+ asset_path(source)
+ end
+ alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with an javascript_path named route
+
+ def stylesheet_path(source)
+ asset_path(source)
+ end
+ alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with an stylesheet_path named route
+
private
def debug_assets?
compile_assets? && (Rails.application.config.assets.debug || params[:debug_assets])
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index 6b67fb1d2d..3d330bd91a 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -1,3 +1,5 @@
+require "action_controller/railtie"
+
module Sprockets
autoload :Bootstrap, "sprockets/bootstrap"
autoload :Helpers, "sprockets/helpers"
@@ -8,13 +10,13 @@ module Sprockets
# TODO: Get rid of config.assets.enabled
class Railtie < ::Rails::Railtie
- config.default_asset_host_protocol = :relative
+ config.action_controller.default_asset_host_protocol = :relative
rake_tasks do
load "sprockets/assets.rake"
end
- initializer "sprockets.environment", :group => :assets do |app|
+ initializer "sprockets.environment", :group => :all do |app|
config = app.config
next unless config.assets.enabled
@@ -41,8 +43,8 @@ module Sprockets
ActiveSupport.on_load(:action_view) do
include ::Sprockets::Helpers::RailsHelper
-
app.assets.context_class.instance_eval do
+ include ::Sprockets::Helpers::IsolatedHelper
include ::Sprockets::Helpers::RailsHelper
end
end
diff --git a/actionpack/lib/sprockets/static_compiler.rb b/actionpack/lib/sprockets/static_compiler.rb
index 4a0078be46..32a9d66e6e 100644
--- a/actionpack/lib/sprockets/static_compiler.rb
+++ b/actionpack/lib/sprockets/static_compiler.rb
@@ -2,41 +2,50 @@ require 'fileutils'
module Sprockets
class StaticCompiler
- attr_accessor :env, :target, :digest
+ attr_accessor :env, :target, :paths
- def initialize(env, target, options = {})
+ def initialize(env, target, paths, options = {})
@env = env
@target = target
+ @paths = paths
@digest = options.key?(:digest) ? options.delete(:digest) : true
+ @manifest = options.key?(:manifest) ? options.delete(:manifest) : true
+ @manifest_path = options.delete(:manifest_path) || target
end
- def precompile(paths)
- Rails.application.config.assets.digest = digest
+ def compile
manifest = {}
-
env.each_logical_path do |logical_path|
- next unless precompile_path?(logical_path, paths)
+ next unless compile_path?(logical_path)
if asset = env.find_asset(logical_path)
- manifest[logical_path] = compile(asset)
+ manifest[logical_path] = write_asset(asset)
end
end
- manifest
+ write_manifest(manifest) if @manifest
end
- def compile(asset)
- asset_path = digest_asset(asset)
- filename = File.join(target, asset_path)
- FileUtils.mkdir_p File.dirname(filename)
- asset.write_to(filename)
- asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/
- asset_path
+ def write_manifest(manifest)
+ FileUtils.mkdir_p(@manifest_path)
+ File.open("#{@manifest_path}/manifest.yml", 'wb') do |f|
+ YAML.dump(manifest, f)
+ end
+ end
+
+ def write_asset(asset)
+ path_for(asset).tap do |path|
+ filename = File.join(target, path)
+ FileUtils.mkdir_p File.dirname(filename)
+ asset.write_to(filename)
+ asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/
+ end
end
- def precompile_path?(logical_path, paths)
+ def compile_path?(logical_path)
paths.each do |path|
- if path.is_a?(Regexp)
+ case path
+ when Regexp
return true if path.match(logical_path)
- elsif path.is_a?(Proc)
+ when Proc
return true if path.call(logical_path)
else
return true if File.fnmatch(path.to_s, logical_path)
@@ -45,8 +54,8 @@ module Sprockets
false
end
- def digest_asset(asset)
- digest ? asset.digest_path : asset.logical_path
+ def path_for(asset)
+ @digest ? asset.digest_path : asset.logical_path
end
end
end
diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb
index cba3aded2f..b64e275363 100644
--- a/actionpack/test/controller/test_test.rb
+++ b/actionpack/test/controller/test_test.rb
@@ -146,6 +146,17 @@ XML
end
end
+ class ViewAssignsController < ActionController::Base
+ def test_assigns
+ @foo = "foo"
+ render :nothing => true
+ end
+
+ def view_assigns
+ { "bar" => "bar" }
+ end
+ end
+
def test_raw_post_handling
params = ActiveSupport::OrderedHash[:page, {:name => 'page name'}, 'some key', 123]
post :render_raw_post, params.dup
@@ -256,6 +267,15 @@ XML
assert_equal "foo", assigns["foo"]
end
+ def test_view_assigns
+ @controller = ViewAssignsController.new
+ process :test_assigns
+ assert_equal nil, assigns(:foo)
+ assert_equal nil, assigns[:foo]
+ assert_equal "bar", assigns(:bar)
+ assert_equal "bar", assigns[:bar]
+ end
+
def test_assert_tag_tag
process :test_html_output
@@ -754,6 +774,22 @@ class CrazyNameTest < ActionController::TestCase
end
end
+class CrazySymbolNameTest < ActionController::TestCase
+ tests :content
+
+ def test_set_controller_class_using_symbol
+ assert_equal ContentController, self.class.controller_class
+ end
+end
+
+class CrazyStringNameTest < ActionController::TestCase
+ tests 'content'
+
+ def test_set_controller_class_using_string
+ assert_equal ContentController, self.class.controller_class
+ end
+end
+
class NamedRoutesControllerTest < ActionController::TestCase
tests ContentController
diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb
index 484e996f31..11ced2df2a 100644
--- a/actionpack/test/controller/url_for_test.rb
+++ b/actionpack/test/controller/url_for_test.rb
@@ -67,6 +67,20 @@ module AbstractController
)
end
+ def test_subdomain_may_be_removed
+ add_host!
+ assert_equal('http://basecamphq.com/c/a/i',
+ W.new.url_for(:subdomain => false, :controller => 'c', :action => 'a', :id => 'i')
+ )
+ end
+
+ def test_multiple_subdomains_may_be_removed
+ W.default_url_options[:host] = 'mobile.www.api.basecamphq.com'
+ assert_equal('http://basecamphq.com/c/a/i',
+ W.new.url_for(:subdomain => false, :controller => 'c', :action => 'a', :id => 'i')
+ )
+ end
+
def test_domain_may_be_changed
add_host!
assert_equal('http://www.37signals.com/c/a/i',
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 060bcfb5ec..a611252b31 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -15,6 +15,7 @@ class RequestTest < ActiveSupport::TestCase
assert_equal 'http://www.example.com', url_for
assert_equal 'http://api.example.com', url_for(:subdomain => 'api')
+ assert_equal 'http://example.com', url_for(:subdomain => false)
assert_equal 'http://www.ror.com', url_for(:domain => 'ror.com')
assert_equal 'http://api.ror.co.uk', url_for(:host => 'www.ror.co.uk', :subdomain => 'api', :tld_length => 2)
assert_equal 'http://www.example.com:8080', url_for(:port => 8080)
diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb
index b1e6db7b34..08b66fec8b 100644
--- a/actionpack/test/template/sprockets_helper_test.rb
+++ b/actionpack/test/template/sprockets_helper_test.rb
@@ -28,7 +28,6 @@ class SprocketsHelperTest < ActionView::TestCase
application = Struct.new(:config, :assets).new(config, @assets)
Rails.stubs(:application).returns(application)
@config = config
- @config.action_controller ||= ActiveSupport::InheritableOptions.new
@config.perform_caching = true
@config.assets.digest = true
@config.assets.compile = true
@@ -38,6 +37,10 @@ class SprocketsHelperTest < ActionView::TestCase
"http://www.example.com"
end
+ def config
+ @controller ? @controller.config : @config
+ end
+
test "asset_path" do
assert_match %r{/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
@@ -75,8 +78,9 @@ class SprocketsHelperTest < ActionView::TestCase
end
test "with a simple asset host the url should default to protocol relative" do
+ @controller.config.default_asset_host_protocol = :relative
@controller.config.asset_host = "assets-%d.example.com"
- assert_match %r{//assets-\d.example.com/assets/logo-[0-9a-f]+.png},
+ assert_match %r{^//assets-\d.example.com/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
end
@@ -88,10 +92,11 @@ class SprocketsHelperTest < ActionView::TestCase
end
test "With a proc asset host that returns no protocol the url should be protocol relative" do
+ @controller.config.default_asset_host_protocol = :relative
@controller.config.asset_host = Proc.new do |asset|
"assets-999.example.com"
end
- assert_match %r{//assets-999.example.com/assets/logo-[0-9a-f]+.png},
+ assert_match %r{^//assets-999.example.com/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
end
@@ -114,7 +119,7 @@ class SprocketsHelperTest < ActionView::TestCase
test "stylesheets served without a controller in scope cannot access the request" do
@controller = nil
- @config.action_controller.asset_host = Proc.new do |asset, request|
+ @config.asset_host = Proc.new do |asset, request|
fail "This should not have been called."
end
assert_raises ActionController::RoutingError do
@@ -134,11 +139,27 @@ class SprocketsHelperTest < ActionView::TestCase
path_to_image("logo.png")
end
+ test "javascript_path" do
+ assert_match %r{/assets/application-[0-9a-f]+.js},
+ javascript_path("application.js")
+
+ assert_match %r{/assets/application-[0-9a-f]+.js},
+ path_to_javascript("application.js")
+ end
+
+ test "stylesheet_path" do
+ assert_match %r{/assets/application-[0-9a-f]+.css},
+ stylesheet_path("application.css")
+
+ assert_match %r{/assets/application-[0-9a-f]+.css},
+ path_to_stylesheet("application.css")
+ end
+
test "stylesheets served without a controller in do not use asset hosts when the default protocol is :request" do
@controller = nil
- @config.action_controller.asset_host = "assets-%d.example.com"
- @config.action_controller.default_asset_host_protocol = :request
- @config.action_controller.perform_caching = true
+ @config.asset_host = "assets-%d.example.com"
+ @config.default_asset_host_protocol = :request
+ @config.perform_caching = true
assert_match %r{/assets/logo-[0-9a-f]+.png},
asset_path("logo.png")
@@ -152,12 +173,12 @@ class SprocketsHelperTest < ActionView::TestCase
test "asset path with relative url root when controller isn't present but relative_url_root is" do
@controller = nil
- @config.action_controller.relative_url_root = "/collaboration/hieraki"
+ @config.relative_url_root = "/collaboration/hieraki"
assert_equal "/collaboration/hieraki/images/logo.gif",
asset_path("/images/logo.gif")
end
- test "javascript path" do
+ test "javascript path through asset_path" do
assert_match %r{/assets/application-[0-9a-f]+.js},
asset_path(:application, :ext => "js")
@@ -202,7 +223,7 @@ class SprocketsHelperTest < ActionView::TestCase
javascript_include_tag(:application)
end
- test "stylesheet path" do
+ test "stylesheet path through asset_path" do
assert_match %r{/assets/application-[0-9a-f]+.css}, asset_path(:application, :ext => "css")
assert_match %r{/assets/style-[0-9a-f]+.css}, asset_path("style", :ext => "css")
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index dbac2e1fc0..bc45fabf34 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -88,6 +88,10 @@ class UrlHelperTest < ActiveSupport::TestCase
)
end
+ def test_button_to_with_remote_and_form_options
+ assert_dom_equal "<form method=\"post\" action=\"http://www.example.com\" class=\"custom-class\" data-remote=\"true\" data-type=\"json\"><div><input type=\"submit\" value=\"Hello\" /></div></form>", button_to("Hello", "http://www.example.com", :remote => true, :form => { :class => "custom-class", "data-type" => "json" } )
+ end
+
def test_button_to_with_remote_and_javascript_confirm
assert_dom_equal(
"<form method=\"post\" action=\"http://www.example.com\" class=\"button_to\" data-remote=\"true\"><div><input data-confirm=\"Are you sure?\" type=\"submit\" value=\"Hello\" /></div></form>",
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index a756b9f205..7bc3f997b5 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -78,7 +78,8 @@ module ActiveModel
attribute_names -= Array.wrap(except).map(&:to_s)
end
- hash = attributes.slice(*attribute_names)
+ hash = {}
+ attribute_names.each { |n| hash[n] = read_attribute_for_serialization(n) }
method_names = Array.wrap(options[:methods]).select { |n| respond_to?(n) }
method_names.each { |n| hash[n] = send(n) }
@@ -95,13 +96,33 @@ module ActiveModel
end
private
+
+ # Hook method defining how an attribute value should be retrieved for
+ # serialization. By default this is assumed to be an instance named after
+ # the attribute. Override this method in subclasses should you need to
+ # retrieve the value for a given attribute differently:
+ #
+ # class MyClass
+ # include ActiveModel::Validations
+ #
+ # def initialize(data = {})
+ # @data = data
+ # end
+ #
+ # def read_attribute_for_serialization(key)
+ # @data[key]
+ # end
+ # end
+ #
+ alias :read_attribute_for_serialization :send
+
# Add associations specified via the <tt>:include</tt> option.
#
# Expects a block that takes as arguments:
# +association+ - name of the association
# +records+ - the association record(s) to be serialized
# +opts+ - options for the association records
- def serializable_add_includes(options = {})
+ def serializable_add_includes(options = {}) #:nodoc:
return unless include = options[:include]
unless include.is_a?(Hash)
diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb
index 29bcdeae67..1ec915d245 100644
--- a/activemodel/test/cases/serialization_test.rb
+++ b/activemodel/test/cases/serialization_test.rb
@@ -77,12 +77,12 @@ class SerializationTest < ActiveModel::TestCase
assert_equal expected , @user.serializable_hash(:methods => [:bar])
end
- def test_should_not_call_methods_for_attributes
- def @user.name
+ def test_should_use_read_attribute_for_serialization
+ def @user.read_attribute_for_serialization(n)
"Jon"
end
- expected = { "name" => "David" }
+ expected = { "name" => "Jon" }
assert_equal expected, @user.serializable_hash(:only => :name)
end
diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb
index 40fdcf20ca..a754d610b9 100644
--- a/activemodel/test/cases/serializers/json_serialization_test.rb
+++ b/activemodel/test/cases/serializers/json_serialization_test.rb
@@ -206,4 +206,14 @@ class JsonSerializationTest < ActiveModel::TestCase
assert_no_match %r{"preferences":}, json
end
+ test "custom as_json options should be extendible" do
+ def @contact.as_json(options = {}); super(options.merge(:only => [:name])); end
+ json = @contact.to_json
+
+ assert_match %r{"name":"Konata Izumi"}, json
+ assert_no_match %r{"created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}}, json
+ assert_no_match %r{"awesome":}, json
+ assert_no_match %r{"preferences":}, json
+ end
+
end
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index a54526dd41..f974b5d237 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,4 +1,28 @@
-Wed Sep 7 15:25:02 2011 Aaron Patterson <aaron@tenderlovemaking.com>
+*Rails 3.1.1 (unreleased)*
+
+* Add deprecation for the preload_associations method. Fixes #3022.
+
+ [Jon Leighton]
+
+* Don't require a DB connection when loading a model that uses set_primary_key. GH #2807.
+
+ [Jon Leighton]
+
+* Fix using select() with a habtm association, e.g. Person.friends.select(:name). GH #3030 and
+ #2923.
+
+ [Hendy Tanata]
+
+* Fix belongs_to polymorphic with custom primary key on target. GH #3104.
+
+ [Jon Leighton]
+
+* CollectionProxy#replace should change the DB records rather than just mutating the array.
+ Fixes #3020.
+
+ [Jon Leighton]
+
+* LRU cache in mysql and sqlite are now per-process caches.
* lib/active_record/connection_adapters/mysql_adapter.rb: LRU cache
keys are per process id.
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index a404a5edd7..36d7f4ad11 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -14,6 +14,8 @@ module ActiveRecord
# primary_key_prefix_type setting, though.
def primary_key
@primary_key ||= reset_primary_key
+ raise ActiveRecord::UnknownPrimaryKey.new(self) unless @primary_key
+ @primary_key
end
# Returns a quoted version of the primary key name, used to construct SQL statements.
@@ -29,6 +31,11 @@ module ActiveRecord
key
end
+ def primary_key? #:nodoc:
+ @primary_key ||= reset_primary_key
+ !@primary_key.nil?
+ end
+
def get_primary_key(base_name) #:nodoc:
return 'id' unless base_name && !base_name.blank?
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 4174e4da09..8566ecad14 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -40,7 +40,7 @@ module ActiveRecord
define_read_method(attr_name, attr_name, columns_hash[attr_name])
end
- if attr_name == primary_key && attr_name != "id"
+ if primary_key? && attr_name == primary_key && attr_name != "id"
define_read_method('id', attr_name, columns_hash[attr_name])
end
end
@@ -63,7 +63,7 @@ module ActiveRecord
cast_code = column.type_cast_code('v')
access_code = "(v=@attributes['#{attr_name}']) && #{cast_code}"
- unless attr_name.to_s == self.primary_key.to_s
+ unless primary_key? && attr_name.to_s == primary_key.to_s
access_code.insert(0, "missing_attribute('#{attr_name}', caller) unless @attributes.has_key?('#{attr_name}'); ")
end
@@ -107,7 +107,7 @@ module ActiveRecord
def _read_attribute(attr_name)
attr_name = attr_name.to_s
- attr_name = self.class.primary_key if attr_name == 'id'
+ attr_name = self.class.primary_key? && self.class.primary_key if attr_name == 'id'
value = @attributes[attr_name]
unless value.nil?
if column = column_for_attribute(attr_name)
diff --git a/activerecord/lib/active_record/attribute_methods/write.rb b/activerecord/lib/active_record/attribute_methods/write.rb
index e9cdb130db..4db6d71ba6 100644
--- a/activerecord/lib/active_record/attribute_methods/write.rb
+++ b/activerecord/lib/active_record/attribute_methods/write.rb
@@ -18,7 +18,7 @@ module ActiveRecord
end
end
- if attr_name == primary_key && attr_name != "id"
+ if primary_key? && attr_name == primary_key && attr_name != "id"
generated_attribute_methods.module_eval("alias :id= :'#{primary_key}='")
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 78159d13d4..137b4c6534 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -708,7 +708,7 @@ module ActiveRecord #:nodoc:
# Returns an array of column objects for the table associated with this class.
def columns
if defined?(@primary_key)
- connection_pool.primary_keys[table_name] ||= primary_key
+ connection_pool.primary_keys[table_name] ||= @primary_key
end
connection_pool.columns[table_name]
@@ -953,7 +953,7 @@ module ActiveRecord #:nodoc:
# objects of different types from the same table.
def instantiate(record)
sti_class = find_sti_class(record[inheritance_column])
- record_id = sti_class.primary_key && record[sti_class.primary_key]
+ record_id = sti_class.primary_key? && record[sti_class.primary_key]
if ActiveRecord::IdentityMap.enabled? && record_id
if (column = sti_class.columns_hash[sti_class.primary_key]) && column.number?
@@ -1941,8 +1941,9 @@ MSG
# The primary key and inheritance column can never be set by mass-assignment for security reasons.
def self.attributes_protected_by_default
- default = [ primary_key, inheritance_column ]
- default << 'id' unless primary_key.eql? 'id'
+ default = [ inheritance_column ]
+ default << primary_key if primary_key?
+ default << 'id' unless primary_key? && primary_key == 'id'
default
end
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
index ad7d8cd63c..8262b60f6e 100644
--- a/activerecord/lib/active_record/errors.rb
+++ b/activerecord/lib/active_record/errors.rb
@@ -169,4 +169,18 @@ module ActiveRecord
@errors = errors
end
end
+
+ # Raised when a model attempts to fetch its primary key from the database, but the table
+ # has no primary key declared.
+ class UnknownPrimaryKey < ActiveRecordError
+ attr_reader :model
+
+ def initialize(model)
+ @model = model
+ end
+
+ def message
+ "Unknown primary key for table #{model.table_name} in model #{model}."
+ end
+ end
end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 6f1ec7f9b3..97af15c9e8 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -622,7 +622,7 @@ module ActiveRecord
private
def primary_key_name
- @primary_key_name ||= model_class && model_class.primary_key
+ @primary_key_name ||= model_class && model_class.primary_key? && model_class.primary_key
end
def has_primary_key_column?
diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb
index 5e65e46a7d..b5dadb929d 100644
--- a/activerecord/lib/active_record/persistence.rb
+++ b/activerecord/lib/active_record/persistence.rb
@@ -314,7 +314,7 @@ module ActiveRecord
new_id = self.class.unscoped.insert attributes_values
- self.id ||= new_id if self.class.primary_key
+ self.id ||= new_id if self.class.primary_key?
IdentityMap.add(self) if IdentityMap.enabled?
@new_record = false
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index b3316fd1a2..f4a813d704 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -341,7 +341,7 @@ db_namespace = namespace :db do
namespace :schema do
desc 'Create a db/schema.rb file that can be portably used against any DB supported by AR'
- task :dump => :load_config do
+ task :dump => [:environment, :load_config] do
require 'active_record/schema_dumper'
filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
File.open(filename, "w:utf-8") do |file|
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 1929a808ed..120ff0cac6 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -212,8 +212,8 @@ module ActiveRecord
end
# klass option is necessary to support loading polymorphic associations
- def association_primary_key(klass = self.klass)
- options[:primary_key] || klass.primary_key
+ def association_primary_key(klass = nil)
+ options[:primary_key] || (klass || self.klass).primary_key
end
def active_record_primary_key
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index ecefaa633c..bf61d79a2c 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -13,7 +13,7 @@ module ActiveRecord
# These are explicitly delegated to improve performance (avoids method_missing)
delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to => :to_a
- delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key, :connection, :column_hash,:to => :klass
+ delegate :table_name, :quoted_table_name, :primary_key, :primary_key?, :quoted_primary_key, :connection, :column_hash,:to => :klass
attr_reader :table, :klass, :loaded
attr_accessor :extensions, :default_scoped
@@ -36,7 +36,7 @@ module ActiveRecord
def insert(values)
primary_key_value = nil
- if primary_key && Hash === values
+ if primary_key? && Hash === values
primary_key_value = values[values.keys.find { |k|
k.name == primary_key
}]
@@ -70,7 +70,7 @@ module ActiveRecord
conn.insert(
im,
'SQL',
- primary_key,
+ primary_key? && primary_key,
primary_key_value,
nil,
binds)
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index ae97a3f3ca..d4870dd3f2 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -303,7 +303,7 @@ module ActiveRecord
# Save the new record state and id of a record so it can be restored later if a transaction fails.
def remember_transaction_record_state #:nodoc
@_start_transaction_state ||= {}
- @_start_transaction_state[:id] = id if has_attribute?(self.class.primary_key)
+ @_start_transaction_state[:id] = id if self.class.primary_key?
unless @_start_transaction_state.include?(:new_record)
@_start_transaction_state[:new_record] = @new_record
end
diff --git a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
index d1d02c25d5..34d90cc395 100644
--- a/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
@@ -651,7 +651,7 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
end
def test_habtm_selects_all_columns_by_default
- assert_equal Project.column_names, developers(:david).projects.first.attributes.keys
+ assert_equal Project.column_names.sort, developers(:david).projects.first.attributes.keys.sort
end
def test_habtm_respects_select_query_method
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index fdfbcbefac..cddd2a6f8c 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -486,7 +486,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
end
def test_default_select
- assert_equal Comment.column_names, posts(:welcome).comments.first.attributes.keys
+ assert_equal Comment.column_names.sort, posts(:welcome).comments.first.attributes.keys.sort
end
def test_select_query_method
diff --git a/activerecord/test/cases/attribute_methods/read_test.rb b/activerecord/test/cases/attribute_methods/read_test.rb
index e03ed33591..814476ce73 100644
--- a/activerecord/test/cases/attribute_methods/read_test.rb
+++ b/activerecord/test/cases/attribute_methods/read_test.rb
@@ -24,6 +24,10 @@ module ActiveRecord
def self.primary_key
end
+ def self.primary_key?
+ false
+ end
+
def self.columns
column_names.map { FakeColumn.new(name) }
end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 12c1cfb30e..77fd1d2fad 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -97,10 +97,6 @@ class BasicsTest < ActiveRecord::TestCase
assert pk.primary, 'nick should be primary key'
end
- def test_primary_key_with_no_id
- assert_nil Edge.primary_key
- end
-
unless current_adapter?(:PostgreSQLAdapter,:OracleAdapter,:SQLServerAdapter)
def test_limit_with_comma
assert_nothing_raised do
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 489c7d8310..58badd6266 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -5,6 +5,7 @@ require 'models/subscriber'
require 'models/movie'
require 'models/keyboard'
require 'models/mixed_case_monkey'
+require 'models/edge'
class PrimaryKeysTest < ActiveRecord::TestCase
fixtures :topics, :subscribers, :movies, :mixed_case_monkeys
@@ -161,4 +162,17 @@ class PrimaryKeysTest < ActiveRecord::TestCase
assert_equal 'foo', model.primary_key
end
+
+ def test_no_primary_key_raises
+ assert_raises(ActiveRecord::UnknownPrimaryKey) do
+ Edge.primary_key
+ end
+
+ begin
+ Edge.primary_key
+ rescue ActiveRecord::UnknownPrimaryKey => e
+ assert e.message.include?('edges')
+ assert e.message.include?('Edge')
+ end
+ end
end
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 0a48f418b1..ca9d88fbd5 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -244,6 +244,7 @@ class ReflectionTest < ActiveRecord::TestCase
# Normal association
assert_equal "id", Author.reflect_on_association(:posts).association_primary_key.to_s
assert_equal "name", Author.reflect_on_association(:essay).association_primary_key.to_s
+ assert_equal "name", Essay.reflect_on_association(:writer).association_primary_key.to_s
# Through association (uses the :primary_key option from the source reflection)
assert_equal "nick", Author.reflect_on_association(:subscribers).association_primary_key.to_s
diff --git a/activerecord/test/config.example.yml b/activerecord/test/config.example.yml
index 8c1a45430e..f450efd839 100644
--- a/activerecord/test/config.example.yml
+++ b/activerecord/test/config.example.yml
@@ -37,11 +37,13 @@ connections:
db2:
arunit:
+ adapter: ibm_db
host: localhost
username: arunit
password: arunit
database: arunit
arunit2:
+ adapter: ibm_db
host: localhost
username: arunit
password: arunit
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 1ffd83b91d..03c4cc5b9e 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -1384,6 +1384,10 @@ module ActiveResource
private
+ def read_attribute_for_serialization(n)
+ attributes[n]
+ end
+
# Determine whether the response is allowed to have a body per HTTP 1.1 spec section 4.4.1
def response_code_allows_body?(c)
!((100..199).include?(c) || [204,304].include?(c))
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index d923204dde..592fca96a4 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -238,8 +238,11 @@ module ActiveResource
def digest_auth_header(http_method, uri)
params = extract_params_from_response
+ request_uri = uri.path
+ request_uri << "?#{uri.query}" if uri.query
+
ha1 = Digest::MD5.hexdigest("#{@user}:#{params['realm']}:#{@password}")
- ha2 = Digest::MD5.hexdigest("#{http_method.to_s.upcase}:#{uri.path}")
+ ha2 = Digest::MD5.hexdigest("#{http_method.to_s.upcase}:#{request_uri}")
params.merge!('cnonce' => client_nonce)
request_digest = Digest::MD5.hexdigest([ha1, params['nonce'], "0", params['cnonce'], params['qop'], ha2].join(":"))
diff --git a/activeresource/test/cases/authorization_test.rb b/activeresource/test/cases/authorization_test.rb
index 69ef9a2821..17cd9b30fc 100644
--- a/activeresource/test/cases/authorization_test.rb
+++ b/activeresource/test/cases/authorization_test.rb
@@ -131,6 +131,12 @@ class AuthorizationTest < Test::Unit::TestCase
assert_equal blank_digest_auth_header("/people/2.json", "fad396f6a34aeba28e28b9b96ddbb671"), authorization_header['Authorization']
end
+ def test_authorization_header_with_query_string_if_auth_type_is_digest
+ @authenticated_conn.auth_type = :digest
+ authorization_header = @authenticated_conn.__send__(:authorization_header, :get, URI.parse('/people/2.json?only=name'))
+ assert_equal blank_digest_auth_header("/people/2.json?only=name", "f8457b0b5d21b6b80737a386217afb24"), authorization_header['Authorization']
+ end
+
def test_get
david = decode(@authenticated_conn.get("/people/2.json"))
assert_equal "David", david["name"]
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index 3f516d4808..b431041b76 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -161,6 +161,7 @@ module ActiveSupport
end
def search_dir(dir, &callback)
+ return if !File.exist?(dir)
Dir.foreach(dir) do |d|
next if d == "." || d == ".."
name = File.join(dir, d)
diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb
index 544e63132d..43134b4314 100644
--- a/activesupport/lib/active_support/core_ext/range/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/range/conversions.rb
@@ -7,7 +7,7 @@ class Range
#
# ==== Example
#
- # [1..100].to_formatted_s # => "1..100"
+ # (1..100).to_formatted_s # => "1..100"
def to_formatted_s(format = :default)
if formatter = RANGE_FORMATS[format]
formatter.call(first, last)
diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb
index 2daf4016cd..5d7f74bb65 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -75,7 +75,7 @@ end
module ActiveSupport #:nodoc:
class SafeBuffer < String
- UNSAFE_STRING_METHODS = ["capitalize", "chomp", "chop", "delete", "downcase", "gsub", "lstrip", "next", "reverse", "rstrip", "slice", "squeeze", "strip", "sub", "succ", "swapcase", "tr", "tr_s", "upcase"].freeze
+ UNSAFE_STRING_METHODS = ["capitalize", "chomp", "chop", "delete", "downcase", "gsub", "lstrip", "next", "reverse", "rstrip", "slice", "squeeze", "strip", "sub", "succ", "swapcase", "tr", "tr_s", "upcase", "prepend"].freeze
alias_method :original_concat, :concat
private :original_concat
@@ -142,16 +142,18 @@ module ActiveSupport #:nodoc:
end
UNSAFE_STRING_METHODS.each do |unsafe_method|
- class_eval <<-EOT, __FILE__, __LINE__ + 1
- def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
- to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
- end # end
-
- def #{unsafe_method}!(*args) # def capitalize!(*args)
- @dirty = true # @dirty = true
- super # super
- end # end
- EOT
+ if 'String'.respond_to?(unsafe_method)
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
+ to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
+ end # end
+
+ def #{unsafe_method}!(*args) # def capitalize!(*args)
+ @dirty = true # @dirty = true
+ super # super
+ end # end
+ EOT
+ end
end
protected
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index a15a06d0e4..372dd69212 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -9,7 +9,7 @@ class Time
class << self
# Overriding case equality method so that it returns true for ActiveSupport::TimeWithZone instances
def ===(other)
- other.is_a?(::Time)
+ super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
end
# Return the number of days in the given month.
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 67698c1cff..469ae69258 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -38,7 +38,7 @@ module ActiveSupport
attr_reader :options
def initialize(options = nil)
- @options = options
+ @options = options || {}
@seen = Set.new
end
@@ -59,7 +59,7 @@ module ActiveSupport
def options_for(value)
if value.is_a?(Array) || value.is_a?(Hash)
# hashes and arrays need to get encoder in the options, so that they can detect circular references
- (options || {}).merge(:encoder => self)
+ options.merge(:encoder => self)
else
options
end
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index b692a41312..cb5362525f 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -566,6 +566,14 @@ class FileStoreTest < ActiveSupport::TestCase
assert path.split('/').all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}
assert_equal 'B', File.basename(path)
end
+
+ # If nothing has been stored in the cache, there is a chance the cache directory does not yet exist
+ # Ensure delete_matched gracefully handles this case
+ def test_delete_matched_when_cache_directory_does_not_exist
+ assert_nothing_raised(Exception) do
+ ActiveSupport::Cache::FileStore.new('/test/cache/directory').delete_matched(/does_not_exist/)
+ end
+ end
end
class MemoryStoreTest < ActiveSupport::TestCase
diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb
index c4c4381957..ab9be4b18b 100644
--- a/activesupport/test/core_ext/time_ext_test.rb
+++ b/activesupport/test/core_ext/time_ext_test.rb
@@ -764,7 +764,10 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase
def test_case_equality
assert Time === Time.utc(2000)
assert Time === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC'])
+ assert Time === Class.new(Time).utc(2000)
assert_equal false, Time === DateTime.civil(2000)
+ assert_equal false, Class.new(Time) === Time.utc(2000)
+ assert_equal false, Class.new(Time) === ActiveSupport::TimeWithZone.new(Time.utc(2000), ActiveSupport::TimeZone['UTC'])
end
def test_all_day
diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb
index bf4f5265ef..c28ffa50f2 100644
--- a/activesupport/test/rescuable_test.rb
+++ b/activesupport/test/rescuable_test.rb
@@ -70,7 +70,7 @@ class CoolStargate < Stargate
end
-class RescueableTest < Test::Unit::TestCase
+class RescuableTest < Test::Unit::TestCase
def setup
@stargate = Stargate.new
@cool_stargate = CoolStargate.new
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 54eef0473c..187dd2428f 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.2.0 (unreleased)*
+* Default options to `rails new` can be set in ~/.railsrc [Guillermo Iguaran]
+
* Added destroy alias to Rails engines. [Guillermo Iguaran]
* Added destroy alias for Rails command line. This allows the following: `rails d model post`. [Andrey Ognevsky]
@@ -13,7 +15,10 @@
*Rails 3.1.1
-* `rake assets:precompile` loads the application but does not initialize it.
+* Add jquery-rails to Gemfile of plugins, test/dummy app needs it. Closes #3091. [Santiago Pastorino]
+
+* Add config.assets.initialize_on_precompile which, when set to false, forces
+ `rake assets:precompile` to load the application but does not initialize it.
To the app developer, this means configuration add in
config/initializers/* will not be executed.
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index b343e8d01d..7795b297f3 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -152,15 +152,15 @@ Images can also be organized into subdirectories if required, and they can be ac
h5. CSS and ERB
-If you add an +erb+ extension to a CSS asset, making it something such as +application.css.erb+, then helpers like +image_path+ are available in your CSS rules:
+If you add an +erb+ extension to a CSS asset, making it something such as +application.css.erb+, then helpers like +asset_path+ are available in your CSS rules:
<plain>
-.class { background-image: url(<%= image_path 'image.png' %>) }
+.class { background-image: url(<%= asset_path 'image.png' %>) }
</plain>
This writes the path to the particular asset being referenced. In this example, it would make sense to have an image in one of the asset load paths, such as +app/assets/images/image.png+, which would be referenced here. If this image is already available in +public/assets+ as a fingerprinted file, then that path is referenced.
-If you want to use a "css data URI":http://en.wikipedia.org/wiki/Data_URI_scheme -- a method of embedding the image data directly into the CSS file -- you can use the +asset_data_uri+ helper.
+If you want to use a "data URI":http://en.wikipedia.org/wiki/Data_URI_scheme -- a method of embedding the image data directly into the CSS file -- you can use the +asset_data_uri+ helper.
<plain>
#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
@@ -186,27 +186,28 @@ h5. JavaScript/CoffeeScript and ERB
If you add an +erb+ extension to a JavaScript asset, making it something such as +application.js.erb+, then you can use the +asset_path+ helper in your JavaScript code:
-<plain>
+<erb>
$('#logo').attr({
src: "<%= asset_path('logo.png') %>"
});
-</plain>
+</erb>
This writes the path to the particular asset being referenced.
-Similarly, you can use the +asset_path+ helper in CoffeeScript files with +erb+ extension (eg. application.js.coffee.erb):
+Similarly, you can use the +asset_path+ helper in CoffeeScript files with +erb+ extension (eg. +application.js.coffee.erb+):
<plain>
-$('#logo').attr src: "<% asset_path('logo.png') %>"
+$('#logo').attr src: "<%= asset_path('logo.png') %>"
</plain>
h4. Manifest Files and Directives
-Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain _directives_ -- instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets loads the files specified, processes them if necessary, concatenates them into one single file and then compresses them (if +Rails.application.config.assets.compress+ is set to +true+). By serving one file rather than many, the load time of pages are greatly reduced as there are fewer requests to make.
+Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain _directives_ -- instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets loads the files specified, processes them if necessary, concatenates them into one single file and then compresses them (if +Rails.application.config.assets.compress+ is true). By serving one file rather than many, the load time of pages are greatly reduced as there are fewer requests to make.
For example, in the default Rails application there's a +app/assets/javascripts/application.js+ file which contains the following lines:
<plain>
+// ...
//= require jquery
//= require jquery_ujs
//= require_tree .
@@ -214,9 +215,11 @@ For example, in the default Rails application there's a +app/assets/javascripts/
In JavaScript files, the directives begin with +//=+. In this case, the file is using the +require+ and the +require_tree+ directives. The +require+ directive is used to tell Sprockets the files that you wish to require. Here, you are requiring the files +jquery.js+ and +jquery_ujs.js+ that are available somewhere in the search path for Sprockets. You need not supply the extensions explicitly. Sprockets assumes you are requiring a +.js+ file when done from within a +.js+ file.
-NOTE. In Rails 3.1, the +jquery.js+ and +jquery_ujs.js+ files are located inside the +vendor/assets/javascripts+ directory contained within the +jquery-rails+ gem.
+NOTE. In Rails 3.1 the +jquery-rails+ gem provides the +jquery.js+ and +jquery_ujs.js+ files via the asset pipeline. You won't see them in the application tree.
-The +require_tree .+ directive tells Sprockets to include _all_ JavaScript files in this directory into the output. Only a path relative to the file can be specified. There is also a +require_directory+ directive which includes all JavaScript files only in the directory specified (no nesting).
+The +require_tree+ directive tells Sprockets to recursively include _all_ JavaScript files in this directory into the output. Only a path relative to the manifest file can be specified. There is also a +require_directory+ directive which includes all JavaScript files only in the directory specified (no nesting).
+
+Directives are processed top to bottom, but the order in which files are included by +require_tree+ is unspecified. You should not rely on any particular order among those. If you need to ensure some particular JavaScript ends up above some other, require it before in the manifest. Note that the family of +require+ directives prevents files from being included twice in the output.
There's also a default +app/assets/stylesheets/application.css+ file which contains these lines:
@@ -233,7 +236,7 @@ In this example +require_self+ is used. This puts the CSS contained within the f
You can have as many manifest files as you need. For example the +admin.css+ and +admin.js+ manifest could contain the JS and CSS files that are used for the admin section of an application.
-For some assets (like CSS) the compiled order is important. You can specify individual files and they are compiled in the order specified:
+The same remarks about ordering made above apply. In particular, you can specify individual files and they are compiled in the order specified:
<plain>
/* ...
@@ -246,19 +249,19 @@ For some assets (like CSS) the compiled order is important. You can specify indi
h4. Preprocessing
-The file extensions used on an asset determine what preprocessing is applied. When a controller or a scaffold is generated with the default Rails gemset, a CoffeeScript file and a SCSS file are generated in place of a regular JavaScript and CSS file. The example used before was a controller called "projects", which generated an +app/assets/javascripts/projects.js.coffee+ and a +app/assets/stylesheets/projects.css.scss+ file.
+The file extensions used on an asset determine what preprocessing is applied. When a controller or a scaffold is generated with the default Rails gemset, a CoffeeScript file and a SCSS file are generated in place of a regular JavaScript and CSS file. The example used before was a controller called "projects", which generated an +app/assets/javascripts/projects.js.coffee+ and an +app/assets/stylesheets/projects.css.scss+ file.
When these files are requested, they are processed by the processors provided by the +coffee-script+ and +sass-rails+ gems and then sent back to the browser as JavaScript and CSS respectively.
-Additional layers of pre-processing can be requested by adding other extensions, where each extension is processed in a right-to-left manner. These should be used in the order the processing should be applied. For example, a stylesheet called +app/assets/stylesheets/projects.css.scss.erb+ is first processed as ERB, then SCSS and finally served as CSS. The same applies to a JavaScript file -- +app/assets/javascripts/projects.js.coffee.erb+ is processed as ERB, CoffeeScript and served as JavaScript.
+Additional layers of preprocessing can be requested by adding other extensions, where each extension is processed in a right-to-left manner. These should be used in the order the processing should be applied. For example, a stylesheet called +app/assets/stylesheets/projects.css.scss.erb+ is first processed as ERB, then SCSS and finally served as CSS. The same applies to a JavaScript file -- +app/assets/javascripts/projects.js.coffee.erb+ is processed as ERB, CoffeeScript, and served as JavaScript.
-Keep in mind that the order of these pre-processors is important. For example, if you called your JavaScript file +app/assets/javascripts/projects.js.erb.coffee+ then it is processed with the CoffeeScript interpreter first, which wouldn't understand ERB and therefore you would run into problems.
+Keep in mind that the order of these preprocessors is important. For example, if you called your JavaScript file +app/assets/javascripts/projects.js.erb.coffee+ then it would be processed with the CoffeeScript interpreter first, which wouldn't understand ERB and therefore you would run into problems.
h3. In Development
In development mode assets are served as separate files in the order they are specified in the manifest file.
-This manifest +application.js+:
+This manifest +app/assets/javascripts/application.js+:
<plain>
//= require core
@@ -269,45 +272,42 @@ This manifest +application.js+:
would generate this HTML:
<html>
-<script src='/assets/core.js?body=1'></script>
-<script src='/assets/projects.js?body=1'></script>
-<script src='/assets/tickets.js?body=1'></script>
+<script src="/assets/core.js?body=1" type="text/javascript"></script>
+<script src="/assets/projects.js?body=1" type="text/javascript"></script>
+<script src="/assets/tickets.js?body=1" type="text/javascript"></script>
</html>
The +body+ param is required by Sprockets.
h4. Turning Debugging off
-You can turn off debug mode by updating +development.rb+ to include:
+You can turn off debug mode by updating +config/environments/development.rb+ to include:
-<erb>
+<ruby>
config.assets.debug = false
-</erb>
+</ruby>
-When debug mode is off Sprockets will concatenate and run the necessary preprocessors on all files, generating the following HTML:
+When debug mode is off Sprockets concatenates and runs the necessary preprocessors on all files. With debug mode turned off the manifest above would generate instead:
<html>
-<script src='/assets/application.js'></script>
+<script src="/assets/application.js" type="text/javascript"></script>
</html>
-Assets are compiled and cached on the first request after the server is started. Sprockets sets a +must-revalidate+ Cache-Control HTTP header to reduce request overhead on subsequent requests -- on these the browser gets a 304 (not-modified) response.
+Assets are compiled and cached on the first request after the server is started. Sprockets sets a +must-revalidate+ Cache-Control HTTP header to reduce request overhead on subsequent requests -- on these the browser gets a 304 (Not Modified) response.
If any of the files in the manifest have changed between requests, the server responds with a new compiled file.
-You can put +?debug_assets=true+ or +?debug_assets=1+ at the end of a URL to enable debug mode on-demand, and this will render individual tags for each file. This is useful for tracking down exact line numbers when debugging.
-
-Debug can also be set in the Rails helper methods:
+Debug mode can also be enabled in the Rails helper methods:
<erb>
<%= stylesheet_link_tag "application", :debug => true %>
<%= javascript_include_tag "application", :debug => true %>
</erb>
-The +:debug+ option is ignored if the debug mode is off.
+The +:debug+ option is redundant if debug mode is on.
You could potentially also enable compression in development mode as a sanity check, and disable it on-demand as required for debugging.
-
h3. In Production
In the production environment Rails uses the fingerprinting scheme outlined above. By default it is assumed that assets have been precompiled and will be served as static assets by your web server.
@@ -346,6 +346,15 @@ The rake task is:
bundle exec rake assets:precompile
</plain>
+For faster asset precompiles, you can partially load your application by setting
++config.assets.initialize_on_precompile+ to false, though in that case templates
+cannot see application objects or methods. *Heroku requires this to be false.*
+
+WARNING: If you set +config.assets.initialize_on_precompile+ to false, be sure to
+test +rake assets:precompile+ locally before deploying. It may expose bugs where
+your assets reference application objects or methods, since those are still
+in scope in development mode regardless of the value of this flag.
+
Capistrano (v2.8.0 and above) has a recipe to handle this in deployment. Add the following line to +Capfile+:
<erb>
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 2e412147d3..cbb2d23238 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -91,7 +91,7 @@ module Rails
@routes_reloader ||= RoutesReloader.new
end
- def initialize!(group=nil)
+ def initialize!(group=:default)
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index c363e53c10..448521d2f0 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -37,19 +37,20 @@ module Rails
@cache_store = [ :file_store, "#{root}/tmp/cache/" ]
@assets = ActiveSupport::OrderedOptions.new
- @assets.enabled = false
- @assets.paths = []
- @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) },
- /(?:\/|\\|\A)application\.(css|js)$/ ]
- @assets.prefix = "/assets"
- @assets.version = ''
- @assets.debug = false
- @assets.compile = true
- @assets.digest = false
- @assets.manifest = nil
- @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ]
- @assets.js_compressor = nil
- @assets.css_compressor = nil
+ @assets.enabled = false
+ @assets.paths = []
+ @assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) },
+ /(?:\/|\\|\A)application\.(css|js)$/ ]
+ @assets.prefix = "/assets"
+ @assets.version = ''
+ @assets.debug = false
+ @assets.compile = true
+ @assets.digest = false
+ @assets.manifest = nil
+ @assets.cache_store = [ :file_store, "#{root}/tmp/cache/assets/" ]
+ @assets.js_compressor = nil
+ @assets.css_compressor = nil
+ @assets.initialize_on_precompile = true
end
def compiled_asset_path
diff --git a/railties/lib/rails/commands/application.rb b/railties/lib/rails/commands/application.rb
index 1cf23a8b92..60d1aed73a 100644
--- a/railties/lib/rails/commands/application.rb
+++ b/railties/lib/rails/commands/application.rb
@@ -9,6 +9,14 @@ if ARGV.first != "new"
ARGV[0] = "--help"
else
ARGV.shift
+ railsrc = File.join(File.expand_path("~"), ".railsrc")
+ if File.exist?(railsrc)
+ extra_args_string = File.open(railsrc).read
+ extra_args = extra_args_string.split(/\n+/).map {|l| l.split}.flatten
+ puts "Using #{extra_args.join(" ")} from #{railsrc}"
+ ARGV << extra_args
+ ARGV.flatten!
+ end
end
require 'rubygems' if ARGV.include?("--dev")
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 0e1e719596..2d25273050 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -542,7 +542,7 @@ module Rails
require environment if environment
end
- initializer :append_assets_path, :group => :assets do |app|
+ initializer :append_assets_path, :group => :all do |app|
app.config.assets.paths.unshift(*paths["vendor/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["lib/assets"].existent_directories)
app.config.assets.paths.unshift(*paths["app/assets"].existent_directories)
diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb
index 575f4bb106..b26839644e 100644
--- a/railties/lib/rails/generators/actions.rb
+++ b/railties/lib/rails/generators/actions.rb
@@ -90,7 +90,7 @@ module Rails
append_file "Gemfile", "\ngroup #{name} do\n", :force => true
@in_group = true
- instance_eval &block
+ instance_eval(&block)
@in_group = false
append_file "Gemfile", "end\n", :force => true
@@ -252,7 +252,7 @@ module Rails
#
def rake(command, options={})
log :rake, command
- env = options[:env] || 'development'
+ env = options[:env] || ENV["RAILS_ENV"] || 'development'
sudo = options[:sudo] && RbConfig::CONFIG['host_os'] !~ /mswin|mingw/ ? 'sudo ' : ''
in_root { run("#{sudo}#{extify(:rake)} #{command} RAILS_ENV=#{env}", :verbose => false) }
end
diff --git a/railties/lib/rails/generators/rails/app/USAGE b/railties/lib/rails/generators/rails/app/USAGE
index 9e7a78d132..691095f33f 100644
--- a/railties/lib/rails/generators/rails/app/USAGE
+++ b/railties/lib/rails/generators/rails/app/USAGE
@@ -2,6 +2,12 @@ Description:
The 'rails new' command creates a new Rails application with a default
directory structure and configuration at the path you specify.
+ You can specify extra command-line arguments to be used every time
+ 'rails new' runs in the .railsrc configuration file in your home directory.
+
+ Note that the arguments specified in the .railsrc file don't affect the
+ defaults values shown above in this help message.
+
Example:
rails new ~/Code/Ruby/weblog
diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb
index 4c1da0a5a5..04d5b55c69 100644
--- a/railties/lib/rails/initializable.rb
+++ b/railties/lib/rails/initializable.rb
@@ -10,6 +10,7 @@ module Rails
attr_reader :name, :block
def initialize(name, context, options, &block)
+ options[:group] ||= :default
@name, @context, @options, @block = name, context, options, block
end
@@ -48,10 +49,10 @@ module Rails
end
end
- def run_initializers(group=nil, *args)
+ def run_initializers(group=:default, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort.each do |initializer|
- initializer.run(*args) if group.nil? || initializer.belongs_to?(group)
+ initializer.run(*args) if initializer.belongs_to?(group)
end
@ran = true
end
diff --git a/railties/lib/rails/test_help.rb b/railties/lib/rails/test_help.rb
index 68f566274d..8d0d8cacac 100644
--- a/railties/lib/rails/test_help.rb
+++ b/railties/lib/rails/test_help.rb
@@ -24,7 +24,7 @@ if defined?(MiniTest)
end
end
-if defined?(ActiveRecord)
+if defined?(ActiveRecord::Base)
require 'active_record/test_case'
class ActiveSupport::TestCase
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index 118ffff44b..63427c7792 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -22,13 +22,13 @@ module ApplicationTests
end
def precompile!
- capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
end
end
test "assets routes have higher priority" do
- app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
+ app_file "app/assets/javascripts/demo.js.erb", "a = <%= image_path('rails.png').inspect %>;"
app_file 'config/routes.rb', <<-RUBY
AppTemplate::Application.routes.draw do
@@ -39,7 +39,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
get "/assets/demo.js"
- assert_match "alert()", last_response.body
+ assert_equal 'a = "/assets/rails.png";', last_response.body.strip
end
test "assets do not require compressors until it is used" do
@@ -244,14 +244,16 @@ module ApplicationTests
assert_match(/app.js isn't precompiled/, last_response.body)
end
- test "precompile appends the md5 hash to files referenced with asset_path and run in the provided RAILS_ENV" do
+ test "precompile properly refers files referenced with asset_path and and run in the provided RAILS_ENV" do
app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
# digest is default in false, we must enable it for test environment
- add_to_config "config.assets.digest = true"
+ add_to_env_config "test", "config.assets.digest = true"
- # capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_ENV=test` }
- # end
+ end
+ file = Dir["#{app_path}/public/assets/application.css"].first
+ assert_match(/\/assets\/rails\.png/, File.read(file))
file = Dir["#{app_path}/public/assets/application-*.css"].first
assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
end
@@ -279,7 +281,7 @@ module ApplicationTests
add_to_config "config.assets.compile = true"
ENV["RAILS_ENV"] = nil
- capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:precompile RAILS_GROUPS=assets` }
end
file = Dir["#{app_path}/public/assets/application-*.css"].first
@@ -304,7 +306,7 @@ module ApplicationTests
app_file "public/assets/application.css", "a { color: green; }"
app_file "public/assets/subdir/broken.png", "not really an image file"
- capture(:stdout) do
+ quietly do
Dir.chdir(app_path){ `bundle exec rake assets:clean` }
end
@@ -395,7 +397,62 @@ module ApplicationTests
assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
end
+ test "assets can access model information when precompiling" do
+ app_file "app/models/post.rb", "class Post; end"
+ app_file "app/assets/javascripts/application.js", "//= require_tree ."
+ app_file "app/assets/javascripts/xmlhr.js.erb", "<%= Post.name %>"
+
+ add_to_config "config.assets.digest = false"
+ precompile!
+ assert_equal "Post;\n", File.read("#{app_path}/public/assets/application.js")
+ end
+
+ test "assets can't access model information when precompiling if not initializing the app" do
+ app_file "app/models/post.rb", "class Post; end"
+ app_file "app/assets/javascripts/application.js", "//= require_tree ."
+ app_file "app/assets/javascripts/xmlhr.js.erb", "<%= defined?(Post) || :NoPost %>"
+
+ add_to_config "config.assets.digest = false"
+ add_to_config "config.assets.initialize_on_precompile = false"
+
+ precompile!
+ assert_equal "NoPost;\n", File.read("#{app_path}/public/assets/application.js")
+ end
+
+ test "enhancements to assets:precompile should only run once" do
+ app_file "lib/tasks/enhance.rake", "Rake::Task['assets:precompile'].enhance { puts 'enhancement' }"
+ output = precompile!
+ assert_equal 1, output.scan("enhancement").size
+ end
+
+ test "digested assets are not mistakenly removed" do
+ app_file "app/assets/application.js", "alert();"
+ add_to_config "config.assets.compile = true"
+ add_to_config "config.assets.digest = true"
+
+ quietly do
+ Dir.chdir(app_path){ `bundle exec rake assets:clean assets:precompile` }
+ end
+
+ files = Dir["#{app_path}/public/assets/application-*.js"]
+ assert_equal 1, files.length, "Expected digested application.js asset to be generated, but none found"
+ end
+
+ test "digested assets are removed from configured path" do
+ app_file "public/production_assets/application.js", "alert();"
+ add_to_env_config "production", "config.assets.prefix = 'production_assets'"
+
+ ENV["RAILS_ENV"] = nil
+ quietly do
+ Dir.chdir(app_path){ `bundle exec rake assets:clean` }
+ end
+
+ files = Dir["#{app_path}/public/production_assets/application.js"]
+ assert_equal 0, files.length, "Expected application.js asset to be removed, but still exists"
+ end
+
private
+
def app_with_assets_in_view
app_file "app/assets/javascripts/application.js", "//= require_tree ."
app_file "app/assets/javascripts/xmlhr.js", "function f1() { alert(); }"
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index 448982f9de..97ad47ac14 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -306,7 +306,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors")
end
@@ -319,7 +319,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailInterceptor, ::MyOtherMailInterceptor], ::Mail.send(:class_variable_get, "@@delivery_interceptors")
end
@@ -332,7 +332,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers")
end
@@ -345,7 +345,7 @@ module ApplicationTests
require "#{app_path}/config/environment"
require "mail"
- ActionMailer::Base
+ _ = ActionMailer::Base
assert_equal [::MyMailObserver, ::MyOtherMailObserver], ::Mail.send(:class_variable_get, "@@delivery_notification_observers")
end
diff --git a/railties/test/application/middleware/cache_test.rb b/railties/test/application/middleware/cache_test.rb
index e656ada3c0..050a2161ae 100644
--- a/railties/test/application/middleware/cache_test.rb
+++ b/railties/test/application/middleware/cache_test.rb
@@ -31,6 +31,10 @@ module ApplicationTests
$last_modified ||= Time.now.utc
render_conditionally(:last_modified => $last_modified)
end
+
+ def keeps_if_modified_since
+ render :text => request.headers['If-Modified-Since']
+ end
private
def render_conditionally(headers)
if stale?(headers.merge(:public => !params[:private]))
@@ -47,6 +51,16 @@ module ApplicationTests
RUBY
end
+ def test_cache_keeps_if_modified_since
+ simple_controller
+ expected = "Wed, 30 May 1984 19:43:31 GMT"
+
+ get "/expires/keeps_if_modified_since", {}, "HTTP_IF_MODIFIED_SINCE" => expected
+
+ assert_equal 200, last_response.status
+ assert_equal expected, last_response.body, "cache should have kept If-Modified-Since"
+ end
+
def test_cache_is_disabled_in_dev_mode
simple_controller
app("development")
diff --git a/railties/test/generators/actions_test.rb b/railties/test/generators/actions_test.rb
index 94e9abb3cc..e621f7f6f7 100644
--- a/railties/test/generators/actions_test.rb
+++ b/railties/test/generators/actions_test.rb
@@ -189,6 +189,22 @@ class ActionsTest < Rails::Generators::TestCase
action :rake, 'log:clear', :env => 'production'
end
+ def test_rake_with_rails_env_variable_should_run_rake_command_in_env
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
+ old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "production"
+ action :rake, 'log:clear'
+ ensure
+ ENV["RAILS_ENV"] = old_env
+ end
+
+ def test_env_option_should_win_over_rails_env_variable_when_running_rake
+ generator.expects(:run).once.with('rake log:clear RAILS_ENV=production', :verbose => false)
+ old_env, ENV["RAILS_ENV"] = ENV["RAILS_ENV"], "staging"
+ action :rake, 'log:clear', :env => 'production'
+ ensure
+ ENV["RAILS_ENV"] = old_env
+ end
+
def test_rake_with_sudo_option_should_run_rake_command_with_sudo
generator.expects(:run).once.with('sudo rake log:clear RAILS_ENV=development', :verbose => false)
action :rake, 'log:clear', :sudo => true
diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb
index 1dbcc249ab..c84c7f204c 100644
--- a/railties/test/initializable_test.rb
+++ b/railties/test/initializable_test.rb
@@ -209,7 +209,7 @@ module InitializableTests
$arr = []
instance = Instance.new
instance.run_initializers
- assert_equal [1, 2, 3, 4], $arr
+ assert_equal [2, 3, 4], $arr
end
test "running locals with groups" do
@@ -223,7 +223,7 @@ module InitializableTests
class WithArgsTest < ActiveSupport::TestCase
test "running initializers with args" do
$with_arg = nil
- WithArgs.new.run_initializers(nil, 'foo')
+ WithArgs.new.run_initializers(:default, 'foo')
assert_equal 'foo', $with_arg
end
end