aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionmailer/test/mailers/base_mailer.rb2
-rw-r--r--actionpack/CHANGELOG8
-rwxr-xr-xactionpack/Rakefile5
-rw-r--r--actionpack/lib/action_controller/metal/params_wrapper.rb9
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb4
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb7
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb8
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb2
-rw-r--r--actionpack/lib/action_view/lookup_context.rb227
-rw-r--r--actionpack/lib/action_view/renderer/abstract_renderer.rb27
-rw-r--r--actionpack/lib/action_view/renderer/partial_renderer.rb23
-rw-r--r--actionpack/lib/action_view/renderer/template_renderer.rb24
-rw-r--r--actionpack/lib/action_view/test_case.rb4
-rw-r--r--actionpack/lib/sprockets/assets.rake62
-rw-r--r--actionpack/lib/sprockets/bootstrap.rb37
-rw-r--r--actionpack/lib/sprockets/compressors.rb46
-rw-r--r--actionpack/lib/sprockets/helpers/rails_helper.rb14
-rw-r--r--actionpack/lib/sprockets/railtie.rb61
-rw-r--r--actionpack/lib/sprockets/static_compiler.rb52
-rw-r--r--actionpack/test/abstract/abstract_controller_test.rb6
-rw-r--r--actionpack/test/controller/caching_test.rb2
-rw-r--r--actionpack/test/controller/integration_test.rb11
-rw-r--r--actionpack/test/controller/layout_test.rb4
-rw-r--r--actionpack/test/controller/new_base/render_file_test.rb10
-rw-r--r--actionpack/test/controller/new_base/render_partial_test.rb10
-rw-r--r--actionpack/test/controller/new_base/render_template_test.rb6
-rw-r--r--actionpack/test/controller/render_test.rb32
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb2
-rw-r--r--actionpack/test/dispatch/routing_test.rb11
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb2
-rw-r--r--actionpack/test/fixtures/comments/empty.de.html.erb1
-rw-r--r--actionpack/test/fixtures/comments/empty.html.builder1
-rw-r--r--actionpack/test/fixtures/comments/empty.html.erb1
-rw-r--r--actionpack/test/fixtures/comments/empty.xml.erb1
-rw-r--r--actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb2
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb4
-rw-r--r--actionpack/test/template/compiled_templates_test.rb16
-rw-r--r--actionpack/test/template/compressors_test.rb29
-rw-r--r--actionpack/test/template/log_subscriber_test.rb2
-rw-r--r--actionpack/test/template/lookup_context_test.rb10
-rw-r--r--actionpack/test/template/render_test.rb79
-rw-r--r--actionpack/test/template/sprockets_helper_test.rb30
-rw-r--r--actionpack/test/template/streaming_render_test.rb16
-rw-r--r--activemodel/lib/active_model/serialization.rb4
-rw-r--r--activemodel/lib/active_model/serializers/json.rb20
-rw-r--r--activemodel/test/cases/serialization_test.rb9
-rw-r--r--activemodel/test/cases/serializers/json_serialization_test.rb10
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb11
-rw-r--r--activerecord/lib/active_record/associations/belongs_to_association.rb6
-rw-r--r--activerecord/lib/active_record/associations/collection_proxy.rb2
-rw-r--r--activerecord/lib/active_record/attribute_methods/primary_key.rb1
-rw-r--r--activerecord/lib/active_record/base.rb4
-rw-r--r--activerecord/lib/active_record/reflection.rb26
-rw-r--r--activerecord/test/cases/associations/belongs_to_associations_test.rb8
-rw-r--r--activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb8
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb19
-rw-r--r--activerecord/test/cases/primary_keys_test.rb16
-rw-r--r--activerecord/test/cases/reflection_test.rb1
-rw-r--r--activeresource/test/cases/base_test.rb14
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb17
-rw-r--r--activesupport/lib/active_support/core_ext/module/reachable.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/string/inflections.rb19
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb4
-rw-r--r--activesupport/lib/active_support/inflector/methods.rb46
-rw-r--r--activesupport/test/caching_test.rb11
-rw-r--r--activesupport/test/constantize_test_cases.rb37
-rw-r--r--activesupport/test/core_ext/string_ext_test.rb23
-rw-r--r--activesupport/test/inflector_test.rb27
-rw-r--r--railties/CHANGELOG12
-rw-r--r--railties/guides/source/asset_pipeline.textile44
-rw-r--r--railties/guides/source/configuring.textile2
-rw-r--r--railties/lib/rails/application.rb7
-rw-r--r--railties/lib/rails/application/bootstrap.rb16
-rw-r--r--railties/lib/rails/application/configuration.rb6
-rw-r--r--railties/lib/rails/engine.rb4
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/Gemfile5
-rw-r--r--railties/lib/rails/initializable.rb8
-rw-r--r--railties/test/application/assets_test.rb132
-rw-r--r--railties/test/application/middleware_test.rb8
-rw-r--r--railties/test/initializable_test.rb13
-rw-r--r--railties/test/isolation/abstract_unit.rb9
84 files changed, 1015 insertions, 516 deletions
diff --git a/Gemfile b/Gemfile
index 508d083fe6..a1585e279c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -63,7 +63,7 @@ platforms :ruby do
gem "nokogiri", ">= 1.4.5"
# AR
- gem "sqlite3", "~> 1.3.3"
+ gem "sqlite3", "~> 1.3.4"
group :db do
gem "pg", ">= 0.11.0" unless ENV['TRAVIS'] # once pg is on travis this can be removed
diff --git a/actionmailer/test/mailers/base_mailer.rb b/actionmailer/test/mailers/base_mailer.rb
index 9416bc718e..e55d72fdb4 100644
--- a/actionmailer/test/mailers/base_mailer.rb
+++ b/actionmailer/test/mailers/base_mailer.rb
@@ -113,6 +113,6 @@ class BaseMailer < ActionMailer::Base
end
def email_with_translations
- mail :body => render("email_with_translations.html")
+ mail :body => render("email_with_translations", :formats => [:html])
end
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 5ee14dbdf1..c3ff677529 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,13 @@
*Rails 3.2.0 (unreleased)*
+* Passing formats or handlers to render :template and friends is deprecated. For example: [Nick Sutterer & José Valim]
+
+ render :template => "foo.html.erb"
+
+ Instead, you can provide :handlers and :formats directly as option:
+
+ render :template => "foo", :formats => [:html, :js], :handlers => :erb
+
* Changed log level of warning for missing CSRF token from :debug to :warn. [Mike Dillon]
* content_tag_for and div_for can now take the collection of records. It will also yield the record as the first argument if you set a receiving argument in your block [Prem Sichanugrist]
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index 66dd88f0c6..d9e3e56fcc 100755
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -26,6 +26,11 @@ namespace :test do
Rake::TestTask.new(:isolated) do |t|
t.pattern = 'test/ts_isolated.rb'
end
+
+ Rake::TestTask.new(:template) do |t|
+ t.libs << 'test'
+ t.pattern = 'test/template/**/*.rb'
+ end
end
desc 'ActiveRecord Integration Tests'
diff --git a/actionpack/lib/action_controller/metal/params_wrapper.rb b/actionpack/lib/action_controller/metal/params_wrapper.rb
index 6acbb23907..e0d8e1c992 100644
--- a/actionpack/lib/action_controller/metal/params_wrapper.rb
+++ b/actionpack/lib/action_controller/metal/params_wrapper.rb
@@ -141,19 +141,16 @@ module ActionController
# try to find Foo::Bar::User, Foo::User and finally User.
def _default_wrap_model #:nodoc:
return nil if self.anonymous?
-
model_name = self.name.sub(/Controller$/, '').singularize
begin
- model_klass = model_name.constantize
- rescue NameError, ArgumentError => e
- if e.message =~ /is not missing constant|uninitialized constant #{model_name}/
+ if model_klass = model_name.safe_constantize
+ model_klass
+ else
namespaces = model_name.split("::")
namespaces.delete_at(-2)
break if namespaces.last == model_name
model_name = namespaces.join("::")
- else
- raise
end
end until model_klass
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index fa2948c8db..8a9f9c4315 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -256,6 +256,10 @@ module Mime
@@html_types.include?(to_sym) || @string =~ /html/
end
+ def respond_to?(method, include_private = false) #:nodoc:
+ super || method.to_s =~ /(\w+)\?$/
+ end
+
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index a765c23dae..2fa68c64c5 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -86,8 +86,8 @@ module ActionDispatch
:framework_trace => framework_trace(exception),
:full_trace => full_trace(exception)
)
- file = "rescues/#{@@rescue_templates[exception.class.name]}.erb"
- body = template.render(:file => file, :layout => 'rescues/layout.erb')
+ file = "rescues/#{@@rescue_templates[exception.class.name]}"
+ body = template.render(:template => file, :layout => 'rescues/layout')
render(status_code(exception), body)
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 46a68a32ae..e921269331 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -165,13 +165,14 @@ module ActionDispatch
remove_possible_method :#{selector}
def #{selector}(*args)
options = args.extract_options!
+ result = #{options.inspect}
if args.any?
- options[:_positional_args] = args
- options[:_positional_keys] = #{route.segment_keys.inspect}
+ result[:_positional_args] = args
+ result[:_positional_keys] = #{route.segment_keys.inspect}
end
- options ? #{options.inspect}.merge(options) : #{options.inspect}
+ result.merge(options)
end
protected :#{selector}
END_EVAL
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index aae5752c93..0f1bb9f260 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -241,8 +241,8 @@ module ActionDispatch
end
# Performs the actual request.
- def process(method, path, parameters = nil, env = nil)
- env ||= {}
+ def process(method, path, parameters = nil, rack_env = nil)
+ rack_env ||= {}
if path =~ %r{://}
location = URI.parse(path)
https! URI::HTTPS === location if location.scheme
@@ -258,7 +258,7 @@ module ActionDispatch
hostname, port = host.split(':')
- default_env = {
+ env = {
:method => method,
:params => parameters,
@@ -276,7 +276,7 @@ module ActionDispatch
session = Rack::Test::Session.new(_mock_session)
- env.reverse_merge!(default_env)
+ env.merge!(rack_env)
# NOTE: rack-test v0.5 doesn't build a default uri correctly
# Make sure requested path is always a full uri
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
index 2eb3eb31af..343153c8c5 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb
@@ -17,7 +17,7 @@ module ActionView
def asset_tag(source, options)
# We force the :request protocol here to avoid a double-download bug in IE7 and IE8
- tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => ERB::Util.html_escape(path_to_asset(source, :protocol => :request)) }.merge(options), false, false)
+ tag("link", { "rel" => "stylesheet", "type" => Mime::CSS, "media" => "screen", "href" => path_to_asset(source, :protocol => :request) }.merge(options))
end
def custom_dir
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 9ec410ac2b..fa4bf70f77 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -1,5 +1,6 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
+require 'active_support/core_ext/module/remove_method'
module ActionView
# = Action View Lookup Context
@@ -17,23 +18,25 @@ module ActionView
mattr_accessor :registered_details
self.registered_details = []
- mattr_accessor :registered_detail_setters
- self.registered_detail_setters = []
-
def self.register_detail(name, options = {}, &block)
self.registered_details << name
- self.registered_detail_setters << [name, "#{name}="]
+ initialize = registered_details.map { |n| "self.#{n} = details[:#{n}]" }
- Accessors.send :define_method, :"_#{name}_defaults", &block
+ Accessors.send :define_method, :"default_#{name}", &block
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{name}
@details[:#{name}]
end
def #{name}=(value)
- value = Array.wrap(value.presence || _#{name}_defaults)
+ value = Array.wrap(value.presence || default_#{name})
_set_detail(:#{name}, value) if value != @details[:#{name}]
end
+
+ remove_possible_method :initialize_details
+ def initialize_details(details)
+ #{initialize.join("\n")}
+ end
METHOD
end
@@ -41,8 +44,9 @@ module ActionView
module Accessors #:nodoc:
end
- register_detail(:formats) { Mime::SET.symbols }
register_detail(:locale) { [I18n.locale, I18n.default_locale] }
+ register_detail(:formats) { Mime::SET.symbols }
+ register_detail(:handlers){ Template::Handlers.extensions }
class DetailsKey #:nodoc:
alias :eql? :equal?
@@ -60,18 +64,34 @@ module ActionView
end
end
- def initialize(view_paths, details = {}, prefixes = [])
- @details, @details_key = { :handlers => default_handlers }, nil
- @frozen_formats, @skip_default_locale = false, false
- @cache = true
- @prefixes = prefixes
+ # Add caching behavior on top of Details.
+ module DetailsCache
+ attr_accessor :cache
- self.view_paths = view_paths
- self.registered_detail_setters.each do |key, setter|
- send(setter, details[key])
+ # Calculate the details key. Remove the handlers from calculation to improve performance
+ # since the user cannot modify it explicitly.
+ def details_key #:nodoc:
+ @details_key ||= DetailsKey.get(@details) if @cache
+ end
+
+ # Temporary skip passing the details_key forward.
+ def disable_cache
+ old_value, @cache = @cache, false
+ yield
+ ensure
+ @cache = old_value
+ end
+
+ protected
+
+ def _set_detail(key, value)
+ @details_key = nil
+ @details = @details.dup if @details.frozen?
+ @details[key] = value.freeze
end
end
+ # Helpers related to template lookup using the lookup context information.
module ViewPaths
attr_reader :view_paths
@@ -81,17 +101,17 @@ module ActionView
@view_paths = ActionView::PathSet.new(Array.wrap(paths))
end
- def find(name, prefixes = [], partial = false, keys = [])
- @view_paths.find(*args_for_lookup(name, prefixes, partial, keys))
+ def find(name, prefixes = [], partial = false, keys = [], options = {})
+ @view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
end
alias :find_template :find
- def find_all(name, prefixes = [], partial = false, keys = [])
- @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys))
+ def find_all(name, prefixes = [], partial = false, keys = [], options = {})
+ @view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
end
- def exists?(name, prefixes = [], partial = false, keys = [])
- @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys))
+ def exists?(name, prefixes = [], partial = false, keys = [], options = {})
+ @view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
end
alias :template_exists? :exists?
@@ -110,16 +130,29 @@ module ActionView
protected
- def args_for_lookup(name, prefixes, partial, keys) #:nodoc:
+ def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
name, prefixes = normalize_name(name, prefixes)
- [name, prefixes, partial || false, @details, details_key, keys]
+ details, details_key = detail_args_for(details_options)
+ [name, prefixes, partial || false, details, details_key, keys]
+ end
+
+ # Compute details hash and key according to user options (e.g. passed from #render).
+ def detail_args_for(options)
+ return @details, details_key if options.empty? # most common path.
+ user_details = @details.merge(options)
+ [user_details, DetailsKey.get(user_details)]
end
# Support legacy foo.erb names even though we now ignore .erb
# as well as incorrectly putting part of the path in the template
# name instead of the prefix.
def normalize_name(name, prefixes) #:nodoc:
- name = name.to_s.gsub(handlers_regexp, '')
+ name = name.to_s.sub(handlers_regexp) do |match|
+ ActiveSupport::Deprecation.warn "Passing a template handler in the template name is deprecated. " \
+ "You can simply remove the handler name or pass render :handlers => [:#{match[1..-1]}] instead.", caller
+ ""
+ end
+
parts = name.split('/')
name = parts.pop
@@ -132,120 +165,82 @@ module ActionView
return name, prefixes
end
- def default_handlers #:nodoc:
- @@default_handlers ||= Template::Handlers.extensions
- end
-
def handlers_regexp #:nodoc:
@@handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/
end
end
- module Details
- attr_accessor :cache
-
- # Calculate the details key. Remove the handlers from calculation to improve performance
- # since the user cannot modify it explicitly.
- def details_key #:nodoc:
- @details_key ||= DetailsKey.get(@details) if @cache
- end
-
- # Temporary skip passing the details_key forward.
- def disable_cache
- old_value, @cache = @cache, false
- yield
- ensure
- @cache = old_value
- end
+ include Accessors
+ include DetailsCache
+ include ViewPaths
- # Freeze the current formats in the lookup context. By freezing them, you are guaranteeing
- # that next template lookups are not going to modify the formats. The controller can also
- # use this, to ensure that formats won't be further modified (as it does in respond_to blocks).
- def freeze_formats(formats, unless_frozen=false) #:nodoc:
- return if unless_frozen && @frozen_formats
- self.formats = formats
- @frozen_formats = true
- end
+ def initialize(view_paths, details = {}, prefixes = [])
+ @details, @details_key = {}, nil
+ @frozen_formats, @skip_default_locale = false, false
+ @cache = true
+ @prefixes = prefixes
- # Overload formats= to expand ["*/*"] values and automatically
- # add :html as fallback to :js.
- def formats=(values)
- if values
- values.concat(_formats_defaults) if values.delete "*/*"
- values << :html if values == [:js]
- end
- super(values)
- end
+ self.view_paths = view_paths
+ initialize_details(details)
+ end
- # Do not use the default locale on template lookup.
- def skip_default_locale!
- @skip_default_locale = true
- self.locale = nil
- end
+ # Freeze the current formats in the lookup context. By freezing them, you
+ # that next template lookups are not going to modify the formats. The con
+ # use this, to ensure that formats won't be further modified (as it does
+ def freeze_formats(formats, unless_frozen=false) #:nodoc:
+ return if unless_frozen && @frozen_formats
+ self.formats = formats
+ @frozen_formats = true
+ end
- # Overload locale to return a symbol instead of array.
- def locale
- @details[:locale].first
+ # Override formats= to expand ["*/*"] values and automatically
+ # add :html as fallback to :js.
+ def formats=(values)
+ if values
+ values.concat(default_formats) if values.delete "*/*"
+ values << :html if values == [:js]
end
+ super(values)
+ end
- # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
- # to original_config, it means that it's has a copy of the original I18n configuration and it's
- # acting as proxy, which we need to skip.
- def locale=(value)
- if value
- config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
- config.locale = value
- end
+ # Do not use the default locale on template lookup.
+ def skip_default_locale!
+ @skip_default_locale = true
+ self.locale = nil
+ end
- super(@skip_default_locale ? I18n.locale : _locale_defaults)
- end
+ # Override locale to return a symbol instead of array.
+ def locale
+ @details[:locale].first
+ end
- # A method which only uses the first format in the formats array for layout lookup.
- # This method plays straight with instance variables for performance reasons.
- def with_layout_format
- if formats.size == 1
- yield
- else
- old_formats = formats
- _set_detail(:formats, formats[0,1])
-
- begin
- yield
- ensure
- _set_detail(:formats, old_formats)
- end
- end
+ # Overload locale= to also set the I18n.locale. If the current I18n.config object responds
+ # to original_config, it means that it's has a copy of the original I18n configuration and it's
+ # acting as proxy, which we need to skip.
+ def locale=(value)
+ if value
+ config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
+ config.locale = value
end
- # Update the details keys by merging the given hash into the current
- # details hash. If a block is given, the details are modified just during
- # the execution of the block and reverted to the previous value after.
- def update_details(new_details)
- old_details = @details.dup
+ super(@skip_default_locale ? I18n.locale : default_locale)
+ end
- registered_detail_setters.each do |key, setter|
- send(setter, new_details[key]) if new_details.key?(key)
- end
+ # A method which only uses the first format in the formats array for layout lookup.
+ # This method plays straight with instance variables for performance reasons.
+ def with_layout_format
+ if formats.size == 1
+ yield
+ else
+ old_formats = formats
+ _set_detail(:formats, formats[0,1])
begin
yield
ensure
- @details_key = nil
- @details = old_details
+ _set_detail(:formats, old_formats)
end
end
-
- protected
-
- def _set_detail(key, value)
- @details_key = nil
- @details = @details.dup if @details.frozen?
- @details[key] = value.freeze
- end
end
-
- include Accessors
- include Details
- include ViewPaths
end
end
diff --git a/actionpack/lib/action_view/renderer/abstract_renderer.rb b/actionpack/lib/action_view/renderer/abstract_renderer.rb
index 60c527beeb..c0936441ac 100644
--- a/actionpack/lib/action_view/renderer/abstract_renderer.rb
+++ b/actionpack/lib/action_view/renderer/abstract_renderer.rb
@@ -11,15 +11,22 @@ module ActionView
raise NotImplementedError
end
- # Checks if the given path contains a format and if so, change
- # the lookup context to take this new format into account.
- def wrap_formats(value)
- return yield unless value.is_a?(String)
-
- if value.sub!(formats_regexp, "")
- update_details(:formats => [$1.to_sym]){ yield }
- else
- yield
+ protected
+
+ def extract_details(options)
+ details = {}
+ @lookup_context.registered_details.each do |key|
+ next unless value = options[key]
+ details[key] = Array.wrap(value)
+ end
+ details
+ end
+
+ def extract_format(value, details)
+ if value.is_a?(String) && value.sub!(formats_regexp, "")
+ ActiveSupport::Deprecation.warn "Passing the format in the template name is deprecated. " \
+ "Please pass render with :formats => [:#{$1}] instead.", caller
+ details[:formats] ||= [$1.to_sym]
end
end
@@ -27,8 +34,6 @@ module ActionView
@@formats_regexp ||= /\.(#{Mime::SET.symbols.join('|')})$/
end
- protected
-
def instrument(name, options={})
ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield }
end
diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb
index cd0f7054a9..e808fa3415 100644
--- a/actionpack/lib/action_view/renderer/partial_renderer.rb
+++ b/actionpack/lib/action_view/renderer/partial_renderer.rb
@@ -216,18 +216,15 @@ module ActionView
def render(context, options, block)
setup(context, options, block)
+ identifier = (@template = find_partial) ? @template.identifier : @path
- wrap_formats(@path) do
- identifier = ((@template = find_partial) ? @template.identifier : @path)
-
- if @collection
- instrument(:collection, :identifier => identifier || "collection", :count => @collection.size) do
- render_collection
- end
- else
- instrument(:partial, :identifier => identifier) do
- render_partial
- end
+ if @collection
+ instrument(:collection, :identifier => identifier || "collection", :count => @collection.size) do
+ render_collection
+ end
+ else
+ instrument(:partial, :identifier => identifier) do
+ render_partial
end
end
end
@@ -271,6 +268,7 @@ module ActionView
@options = options
@locals = options[:locals] || {}
@block = block
+ @details = extract_details(options)
if String === partial
@object = options[:object]
@@ -299,6 +297,7 @@ module ActionView
"and is followed by any combinations of letters, numbers, or underscores.")
end
+ extract_format(@path, @details)
self
end
@@ -326,7 +325,7 @@ module ActionView
def find_template(path=@path, locals=@locals.keys)
prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
- @lookup_context.find_template(path, prefixes, true, locals)
+ @lookup_context.find_template(path, prefixes, true, locals, @details)
end
def collection_with_template
diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb
index d04c00fd40..ac91d333ba 100644
--- a/actionpack/lib/action_view/renderer/template_renderer.rb
+++ b/actionpack/lib/action_view/renderer/template_renderer.rb
@@ -4,13 +4,12 @@ require 'active_support/core_ext/array/wrap'
module ActionView
class TemplateRenderer < AbstractRenderer #:nodoc:
def render(context, options)
- @view = context
-
- wrap_formats(options[:template] || options[:file]) do
- template = determine_template(options)
- freeze_formats(template.formats, true)
- render_template(template, options[:layout], options[:locals])
- end
+ @view = context
+ @details = extract_details(options)
+ extract_format(options[:file] || options[:template], @details)
+ template = determine_template(options)
+ freeze_formats(template.formats, true)
+ render_template(template, options[:layout], options[:locals])
end
# Determine the template to be rendered using the given options.
@@ -20,13 +19,13 @@ module ActionView
if options.key?(:text)
Template::Text.new(options[:text], formats.try(:first))
elsif options.key?(:file)
- with_fallbacks { find_template(options[:file], nil, false, keys) }
+ with_fallbacks { find_template(options[:file], nil, false, keys, @details) }
elsif options.key?(:inline)
handler = Template.handler_for_extension(options[:type] || "erb")
Template.new(options[:inline], "inline template", handler, :locals => keys)
elsif options.key?(:template)
options[:template].respond_to?(:render) ?
- options[:template] : find_template(options[:template], options[:prefixes], false, keys)
+ options[:template] : find_template(options[:template], options[:prefixes], false, keys, @details)
end
end
@@ -62,12 +61,11 @@ module ActionView
begin
with_layout_format do
layout =~ /^\// ?
- with_fallbacks { find_template(layout, nil, false, keys) } : find_template(layout, nil, false, keys)
+ with_fallbacks { find_template(layout, nil, false, keys, @details) } : find_template(layout, nil, false, keys, @details)
end
rescue ActionView::MissingTemplate
- update_details(:formats => nil) do
- raise unless template_exists?(layout)
- end
+ all_details = @details.merge(:formats => @lookup_context.default_formats)
+ raise unless template_exists?(layout, nil, false, keys, all_details)
end
end
end
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 2cc85a9f69..c4d51d7946 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -54,10 +54,8 @@ module ActionView
end
def determine_default_helper_class(name)
- mod = name.sub(/Test$/, '').constantize
+ mod = name.sub(/Test$/, '').safe_constantize
mod.is_a?(Class) ? nil : mod
- rescue NameError
- nil
end
def helper_method(*methods)
diff --git a/actionpack/lib/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake
index 81223b7ead..e29661e4e7 100644
--- a/actionpack/lib/sprockets/assets.rake
+++ b/actionpack/lib/sprockets/assets.rake
@@ -6,55 +6,55 @@ namespace :assets do
if ENV["RAILS_GROUPS"].to_s.empty? || ENV["RAILS_ENV"].to_s.empty?
ENV["RAILS_GROUPS"] ||= "assets"
ENV["RAILS_ENV"] ||= "production"
- Kernel.exec $0, *ARGV
+ ruby $0, *ARGV
else
- Rake::Task["environment"].invoke
+ require "fileutils"
Rake::Task["tmp:cache:clear"].invoke
+ Rake::Task["assets:environment"].invoke
+
+ unless Rails.application.config.assets.enabled
+ raise "Cannot precompile assets if sprockets is disabled. Please set config.assets.enabled to true"
+ end
# Ensure that action view is loaded and the appropriate sprockets hooks get executed
ActionView::Base
- # Always compile files
- Rails.application.config.assets.compile = true
-
config = Rails.application.config
+ config.assets.compile = true
+ config.assets.digest = false if ENV["RAILS_ASSETS_NONDIGEST"]
+
env = Rails.application.assets
- target = Pathname.new(File.join(Rails.public_path, config.assets.prefix))
- manifest = {}
+
+ # Always compile files and avoid use of existing precompiled assets
+ config.assets.compile = true
+ config.assets.digests = {}
+
+ target = File.join(Rails.public_path, config.assets.prefix)
+ static_compiler = Sprockets::StaticCompiler.new(env, target, :digest => config.assets.digest)
+
+ manifest = static_compiler.precompile(config.assets.precompile)
manifest_path = config.assets.manifest || target
+ FileUtils.mkdir_p(manifest_path)
- config.assets.precompile.each do |path|
- env.each_logical_path do |logical_path|
- if path.is_a?(Regexp)
- next unless path.match(logical_path)
- elsif path.is_a?(Proc)
- next unless path.call(logical_path)
- else
- next unless File.fnmatch(path.to_s, logical_path)
- end
-
- if asset = env.find_asset(logical_path)
- asset_path = config.assets.digest ? asset.digest_path : logical_path
- manifest[logical_path] = asset_path
- filename = target.join(asset_path)
-
- mkdir_p filename.dirname
- asset.write_to(filename)
- asset.write_to("#{filename}.gz") if filename.to_s =~ /\.(css|js)$/
- end
+ unless ENV["RAILS_ASSETS_NONDIGEST"]
+ File.open("#{manifest_path}/manifest.yml", 'wb') do |f|
+ YAML.dump(manifest, f)
end
- end
-
- File.open("#{manifest_path}/manifest.yml", 'wb') do |f|
- YAML.dump(manifest, f)
+ ENV["RAILS_ASSETS_NONDIGEST"] = "true"
+ ruby $0, *ARGV
end
end
end
desc "Remove compiled assets"
- task :clean => [:environment, 'tmp:cache:clear'] do
+ 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
end
+
+ task :environment do
+ Rails.application.initialize!(:assets)
+ Sprockets::Bootstrap.new(Rails.application).run
+ end
end
diff --git a/actionpack/lib/sprockets/bootstrap.rb b/actionpack/lib/sprockets/bootstrap.rb
new file mode 100644
index 0000000000..395b264fe7
--- /dev/null
+++ b/actionpack/lib/sprockets/bootstrap.rb
@@ -0,0 +1,37 @@
+module Sprockets
+ class Bootstrap
+ def initialize(app)
+ @app = app
+ end
+
+ # TODO: Get rid of config.assets.enabled
+ def run
+ app, config = @app, @app.config
+ return unless app.assets
+
+ config.assets.paths.each { |path| app.assets.append_path(path) }
+
+ if config.assets.compress
+ # temporarily hardcode default JS compressor to uglify. Soon, it will work
+ # the same as SCSS, where a default plugin sets the default.
+ unless config.assets.js_compressor == false
+ app.assets.js_compressor = LazyCompressor.new { Sprockets::Compressors.registered_js_compressor(config.assets.js_compressor || :uglifier) }
+ end
+
+ unless config.assets.css_compressor == false
+ app.assets.css_compressor = LazyCompressor.new { Sprockets::Compressors.registered_css_compressor(config.assets.css_compressor) }
+ end
+ end
+
+ if config.assets.compile
+ app.routes.prepend do
+ mount app.assets => config.assets.prefix
+ end
+ end
+
+ if config.assets.digest
+ app.assets = app.assets.index
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/sprockets/compressors.rb b/actionpack/lib/sprockets/compressors.rb
index 351eff1085..cb3e13314b 100644
--- a/actionpack/lib/sprockets/compressors.rb
+++ b/actionpack/lib/sprockets/compressors.rb
@@ -1,4 +1,50 @@
module Sprockets
+ module Compressors
+ @@css_compressors = {}
+ @@js_compressors = {}
+ @@default_css_compressor = nil
+ @@default_js_compressor = nil
+
+ def self.register_css_compressor(name, klass, options = {})
+ @@default_css_compressor = name.to_sym if options[:default] || @@default_css_compressor.nil?
+ @@css_compressors[name.to_sym] = {:klass => klass.to_s, :require => options[:require]}
+ end
+
+ def self.register_js_compressor(name, klass, options = {})
+ @@default_js_compressor = name.to_sym if options[:default] || @@default_js_compressor.nil?
+ @@js_compressors[name.to_sym] = {:klass => klass.to_s, :require => options[:require]}
+ end
+
+ def self.registered_css_compressor(name)
+ if name.respond_to?(:to_sym)
+ compressor = @@css_compressors[name.to_sym] || @@css_compressors[@@default_css_compressor]
+ require compressor[:require] if compressor[:require]
+ compressor[:klass].constantize.new
+ else
+ name
+ end
+ end
+
+ def self.registered_js_compressor(name)
+ if name.respond_to?(:to_sym)
+ compressor = @@js_compressors[name.to_sym] || @@js_compressors[@@default_js_compressor]
+ require compressor[:require] if compressor[:require]
+ compressor[:klass].constantize.new
+ else
+ name
+ end
+ end
+
+ # The default compressors must be registered in default plugins (ex. Sass-Rails)
+ register_css_compressor(:scss, 'Sass::Rails::Compressor', :require => 'sass/rails/compressor', :default => true)
+ register_js_compressor(:uglifier, 'Uglifier', :require => 'uglifier', :default => true)
+
+ # Automaticaly register some compressors
+ register_css_compressor(:yui, 'YUI::CssCompressor', :require => 'yui/compressor')
+ register_js_compressor(:closure, 'Closure::Compiler', :require => 'closure-compiler')
+ register_js_compressor(:yui, 'YUI::JavaScriptCompressor', :require => 'yui/compressor')
+ end
+
# An asset compressor which does nothing.
#
# This compressor simply returns the asset as-is, without any compression
diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb
index 457ab93ae3..c8c6c3ddd9 100644
--- a/actionpack/lib/sprockets/helpers/rails_helper.rb
+++ b/actionpack/lib/sprockets/helpers/rails_helper.rb
@@ -13,7 +13,6 @@ module Sprockets
controller = self.controller if respond_to?(:controller)
paths = RailsHelper::AssetPaths.new(config, controller)
paths.asset_environment = asset_environment
- paths.asset_prefix = asset_prefix
paths.asset_digests = asset_digests
paths.compile_assets = compile_assets?
paths.digest_assets = digest_assets?
@@ -57,10 +56,15 @@ module Sprockets
def asset_path(source, options = {})
source = source.logical_path if source.respond_to?(:logical_path)
- path = asset_paths.compute_public_path(source, 'assets', options.merge(:body => true))
+ path = asset_paths.compute_public_path(source, asset_prefix, options.merge(:body => true))
options[:body] ? "#{path}?body=1" : path
end
+ def image_path(source)
+ asset_path(source)
+ end
+ alias_method :path_to_image, :image_path # aliased to avoid conflicts with an image_path named route
+
private
def debug_assets?
compile_assets? && (Rails.application.config.assets.debug || params[:debug_assets])
@@ -102,10 +106,6 @@ module Sprockets
class AssetNotPrecompiledError < StandardError; end
- def compute_public_path(source, dir, options = {})
- super(source, asset_prefix, options)
- end
-
# Return the filesystem path for the source
def compute_source_path(source, ext)
asset_for(source, ext)
@@ -119,7 +119,7 @@ module Sprockets
end
def digest_for(logical_path)
- if asset_digests && (digest = asset_digests[logical_path])
+ if digest_assets && asset_digests && (digest = asset_digests[logical_path])
return digest
end
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index f05d835554..6b67fb1d2d 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -1,7 +1,10 @@
module Sprockets
- autoload :Helpers, "sprockets/helpers"
+ autoload :Bootstrap, "sprockets/bootstrap"
+ autoload :Helpers, "sprockets/helpers"
+ autoload :Compressors, "sprockets/compressors"
autoload :LazyCompressor, "sprockets/compressors"
autoload :NullCompressor, "sprockets/compressors"
+ autoload :StaticCompiler, "sprockets/static_compiler"
# TODO: Get rid of config.assets.enabled
class Railtie < ::Rails::Railtie
@@ -11,7 +14,7 @@ module Sprockets
load "sprockets/assets.rake"
end
- initializer "sprockets.environment" do |app|
+ initializer "sprockets.environment", :group => :assets do |app|
config = app.config
next unless config.assets.enabled
@@ -50,59 +53,7 @@ module Sprockets
# are compiled, and so that other Railties have an opportunity to
# register compressors.
config.after_initialize do |app|
- next unless app.assets
- config = app.config
-
- config.assets.paths.each { |path| app.assets.append_path(path) }
-
- if config.assets.compress
- # temporarily hardcode default JS compressor to uglify. Soon, it will work
- # the same as SCSS, where a default plugin sets the default.
- unless config.assets.js_compressor == false
- app.assets.js_compressor = LazyCompressor.new { expand_js_compressor(config.assets.js_compressor || :uglifier) }
- end
-
- unless config.assets.css_compressor == false
- app.assets.css_compressor = LazyCompressor.new { expand_css_compressor(config.assets.css_compressor) }
- end
- end
-
- if config.assets.compile
- app.routes.prepend do
- mount app.assets => config.assets.prefix
- end
- end
-
- if config.assets.digest
- app.assets = app.assets.index
- end
+ Sprockets::Bootstrap.new(app).run
end
-
- protected
- def expand_js_compressor(sym)
- case sym
- when :closure
- require 'closure-compiler'
- Closure::Compiler.new
- when :uglifier
- require 'uglifier'
- Uglifier.new
- when :yui
- require 'yui/compressor'
- YUI::JavaScriptCompressor.new
- else
- sym
- end
- end
-
- def expand_css_compressor(sym)
- case sym
- when :yui
- require 'yui/compressor'
- YUI::CssCompressor.new
- else
- sym
- end
- end
end
end
diff --git a/actionpack/lib/sprockets/static_compiler.rb b/actionpack/lib/sprockets/static_compiler.rb
new file mode 100644
index 0000000000..4a0078be46
--- /dev/null
+++ b/actionpack/lib/sprockets/static_compiler.rb
@@ -0,0 +1,52 @@
+require 'fileutils'
+
+module Sprockets
+ class StaticCompiler
+ attr_accessor :env, :target, :digest
+
+ def initialize(env, target, options = {})
+ @env = env
+ @target = target
+ @digest = options.key?(:digest) ? options.delete(:digest) : true
+ end
+
+ def precompile(paths)
+ Rails.application.config.assets.digest = digest
+ manifest = {}
+
+ env.each_logical_path do |logical_path|
+ next unless precompile_path?(logical_path, paths)
+ if asset = env.find_asset(logical_path)
+ manifest[logical_path] = compile(asset)
+ end
+ end
+ 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
+ end
+
+ def precompile_path?(logical_path, paths)
+ paths.each do |path|
+ if path.is_a?(Regexp)
+ return true if path.match(logical_path)
+ elsif path.is_a?(Proc)
+ return true if path.call(logical_path)
+ else
+ return true if File.fnmatch(path.to_s, logical_path)
+ end
+ end
+ false
+ end
+
+ def digest_asset(asset)
+ digest ? asset.digest_path : asset.logical_path
+ end
+ end
+end
diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb
index 5823e64637..bf068aedcd 100644
--- a/actionpack/test/abstract/abstract_controller_test.rb
+++ b/actionpack/test/abstract/abstract_controller_test.rb
@@ -50,7 +50,7 @@ module AbstractController
end
def index_to_string
- self.response_body = render_to_string "index.erb"
+ self.response_body = render_to_string "index"
end
def action_with_ivars
@@ -63,11 +63,11 @@ module AbstractController
end
def rendering_to_body
- self.response_body = render_to_body :template => "naked_render.erb"
+ self.response_body = render_to_body :template => "naked_render"
end
def rendering_to_string
- self.response_body = render_to_string :template => "naked_render.erb"
+ self.response_body = render_to_string :template => "naked_render"
end
end
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index da3314fe6d..f3b180283f 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -197,7 +197,7 @@ class ActionCachingTestController < CachingController
caches_action :layout_false, :layout => false
caches_action :record_not_found, :four_oh_four, :simple_runtime_error
- layout 'talk_from_action.erb'
+ layout 'talk_from_action'
def index
@cache_this = MockTime.now.to_f.to_s
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 23709e44e2..2ad95f5c29 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -493,7 +493,7 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
routes.draw do
match '', :to => 'application_integration_test/test#index', :as => :empty_string
-
+
match 'foo', :to => 'application_integration_test/test#index', :as => :foo
match 'bar', :to => 'application_integration_test/test#index', :as => :bar
end
@@ -511,7 +511,7 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
test "route helpers after controller access" do
get '/'
assert_equal '/', empty_string_path
-
+
get '/foo'
assert_equal '/foo', foo_path
@@ -528,11 +528,10 @@ class ApplicationIntegrationTest < ActionDispatch::IntegrationTest
assert_raise(NameError) { missing_path }
end
- test "process reuse the env we pass as argument" do
+ test "process do not modify the env passed as argument" do
env = { :SERVER_NAME => 'server', 'action_dispatch.custom' => 'custom' }
+ old_env = env.dup
get '/foo', nil, env
- assert_equal :get, env[:method]
- assert_equal 'server', env[:SERVER_NAME]
- assert_equal 'custom', env['action_dispatch.custom']
+ assert_equal old_env, env
end
end
diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb
index cafe2b9320..25299eb8b8 100644
--- a/actionpack/test/controller/layout_test.rb
+++ b/actionpack/test/controller/layout_test.rb
@@ -79,7 +79,7 @@ class DefaultLayoutController < LayoutTest
end
class AbsolutePathLayoutController < LayoutTest
- layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test.erb')
+ layout File.expand_path(File.expand_path(__FILE__) + '/../../fixtures/layout_tests/layouts/layout_test')
end
class HasOwnLayoutController < LayoutTest
@@ -184,7 +184,7 @@ class RenderWithTemplateOptionController < LayoutTest
end
class SetsNonExistentLayoutFile < LayoutTest
- layout "nofile.erb"
+ layout "nofile"
end
class LayoutExceptionRaised < ActionController::TestCase
diff --git a/actionpack/test/controller/new_base/render_file_test.rb b/actionpack/test/controller/new_base/render_file_test.rb
index 8b2fdf8f96..a961cbf849 100644
--- a/actionpack/test/controller/new_base/render_file_test.rb
+++ b/actionpack/test/controller/new_base/render_file_test.rb
@@ -10,7 +10,7 @@ module RenderFile
def with_instance_variables
@secret = 'in the sauce'
- render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar.erb')
+ render :file => File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar')
end
def without_file_key
@@ -19,7 +19,7 @@ module RenderFile
def without_file_key_with_instance_variable
@secret = 'in the sauce'
- render File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar.erb')
+ render File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_ivar')
end
def relative_path
@@ -34,16 +34,16 @@ module RenderFile
def pathname
@secret = 'in the sauce'
- render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar.erb])
+ render :file => Pathname.new(File.dirname(__FILE__)).join(*%w[.. .. fixtures test dot.directory render_file_with_ivar])
end
def with_locals
- path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals.erb')
+ path = File.join(File.dirname(__FILE__), '../../fixtures/test/render_file_with_locals')
render :file => path, :locals => {:secret => 'in the sauce'}
end
def without_file_key_with_locals
- path = FIXTURES.join('test/render_file_with_locals.erb').to_s
+ path = FIXTURES.join('test/render_file_with_locals').to_s
render path, :locals => {:secret => 'in the sauce'}
end
end
diff --git a/actionpack/test/controller/new_base/render_partial_test.rb b/actionpack/test/controller/new_base/render_partial_test.rb
index 83b0d039ad..b4a25c49c9 100644
--- a/actionpack/test/controller/new_base/render_partial_test.rb
+++ b/actionpack/test/controller/new_base/render_partial_test.rb
@@ -7,12 +7,12 @@ module RenderPartial
self.view_paths = [ActionView::FixtureResolver.new(
"render_partial/basic/_basic.html.erb" => "BasicPartial!",
"render_partial/basic/basic.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'basic' %><%= @test_unchanged %>",
- "render_partial/basic/with_json.html.erb" => "<%= render 'with_json.json' %>",
- "render_partial/basic/_with_json.json.erb" => "<%= render 'final' %>",
+ "render_partial/basic/with_json.html.erb" => "<%= render :partial => 'with_json', :formats => [:json] %>",
+ "render_partial/basic/_with_json.json.erb" => "<%= render :partial => 'final', :formats => [:json] %>",
"render_partial/basic/_final.json.erb" => "{ final: json }",
- "render_partial/basic/overriden.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'overriden' %><%= @test_unchanged %>",
- "render_partial/basic/_overriden.html.erb" => "ParentPartial!",
- "render_partial/child/_overriden.html.erb" => "OverridenPartial!"
+ "render_partial/basic/overriden.html.erb" => "<%= @test_unchanged = 'goodbye' %><%= render :partial => 'overriden' %><%= @test_unchanged %>",
+ "render_partial/basic/_overriden.html.erb" => "ParentPartial!",
+ "render_partial/child/_overriden.html.erb" => "OverridenPartial!"
)]
def html_with_json_inside_json
diff --git a/actionpack/test/controller/new_base/render_template_test.rb b/actionpack/test/controller/new_base/render_template_test.rb
index 584f2d772c..ba804421da 100644
--- a/actionpack/test/controller/new_base/render_template_test.rb
+++ b/actionpack/test/controller/new_base/render_template_test.rb
@@ -10,8 +10,8 @@ module RenderTemplate
"xml_template.xml.builder" => "xml.html do\n xml.p 'Hello'\nend",
"with_raw.html.erb" => "Hello <%=raw '<strong>this is raw</strong>' %>",
"with_implicit_raw.html.erb" => "Hello <%== '<strong>this is also raw</strong>' %>",
- "test/with_json.html.erb" => "<%= render :template => 'test/with_json.json' %>",
- "test/with_json.json.erb" => "<%= render :template => 'test/final' %>",
+ "test/with_json.html.erb" => "<%= render :template => 'test/with_json', :formats => [:json] %>",
+ "test/with_json.json.erb" => "<%= render :template => 'test/final', :formats => [:json] %>",
"test/final.json.erb" => "{ final: json }",
"test/with_error.html.erb" => "<%= idontexist %>"
)]
@@ -117,7 +117,7 @@ module RenderTemplate
assert_response "{ final: json }"
end
- test "rendering a template with error properly exceprts the code" do
+ test "rendering a template with error properly excerts the code" do
get :with_error
assert_status 500
assert_match "undefined local variable or method `idontexist'", response.body
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index c46755417f..aea603b014 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -163,14 +163,14 @@ class TestController < ActionController::Base
# :ported:
def render_file_with_instance_variables
@secret = 'in the sauce'
- path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb')
+ path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar')
render :file => path
end
# :ported:
def render_file_as_string_with_instance_variables
@secret = 'in the sauce'
- path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb'))
+ path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar'))
render path
end
@@ -187,21 +187,21 @@ class TestController < ActionController::Base
def render_file_using_pathname
@secret = 'in the sauce'
- render :file => Pathname.new(File.dirname(__FILE__)).join('..', 'fixtures', 'test', 'dot.directory', 'render_file_with_ivar.erb')
+ render :file => Pathname.new(File.dirname(__FILE__)).join('..', 'fixtures', 'test', 'dot.directory', 'render_file_with_ivar')
end
def render_file_from_template
@secret = 'in the sauce'
- @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar.erb'))
+ @path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_ivar'))
end
def render_file_with_locals
- path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb')
+ path = File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals')
render :file => path, :locals => {:secret => 'in the sauce'}
end
def render_file_as_string_with_locals
- path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals.erb'))
+ path = File.expand_path(File.join(File.dirname(__FILE__), '../fixtures/test/render_file_with_locals'))
render path, :locals => {:secret => 'in the sauce'}
end
@@ -453,17 +453,13 @@ class TestController < ActionController::Base
render :action => "potential_conflicts"
end
- # :deprecated:
- # Tests being able to pick a .builder template over a .erb
- # For instance, being able to have hello.xml.builder and hello.xml.erb
- # and select one via "hello.builder" or "hello.erb"
def hello_world_from_rxml_using_action
- render :action => "hello_world_from_rxml.builder"
+ render :action => "hello_world_from_rxml", :handlers => [:builder]
end
# :deprecated:
def hello_world_from_rxml_using_template
- render :template => "test/hello_world_from_rxml.builder"
+ render :template => "test/hello_world_from_rxml", :handlers => [:builder]
end
def action_talk_to_layout
@@ -525,8 +521,8 @@ class TestController < ActionController::Base
render :action => "using_layout_around_block", :layout => "layouts/block_with_layout"
end
- def partial_dot_html
- render :partial => 'partial.html.erb'
+ def partial_formats_html
+ render :partial => 'partial', :formats => [:html]
end
def partial
@@ -797,7 +793,9 @@ class RenderTest < ActionController::TestCase
end
def test_render_file
- get :hello_world_file
+ assert_deprecated do
+ get :hello_world_file
+ end
assert_equal "Hello world!", @response.body
end
@@ -1233,8 +1231,8 @@ class RenderTest < ActionController::TestCase
assert_equal 'partial html', @response.body
end
- def test_should_render_html_partial_with_dot
- get :partial_dot_html
+ def test_should_render_html_partial_with_formats
+ get :partial_formats_html
assert_equal 'partial html', @response.body
end
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index 851fb59d51..08fe2127b9 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -107,8 +107,10 @@ class MimeTypeTest < ActiveSupport::TestCase
# Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE
types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) }
+
types.each do |type|
mime = Mime.const_get(type.to_s.upcase)
+ assert mime.respond_to?("#{type}?"), "#{mime.inspect} does not respond to #{type}?"
assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?"
invalid_types = types - [type]
invalid_types.delete(:html) if Mime::Type.html_types.include?(type)
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index 9685b24c1c..c0b74bc9f9 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -863,6 +863,17 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal original_options, options
end
+ # tests the arguments modification free version of define_hash_access
+ def test_named_route_with_no_side_effects
+ original_options = { :host => 'test.host' }
+ options = original_options.dup
+
+ profile_customer_url("customer_model", options)
+
+ # verify that the options passed in have not changed from the original ones
+ assert_equal original_options, options
+ end
+
def test_projects_status
with_test_routes do
assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true)
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index 301bf9c6d2..92df6967d6 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -5,7 +5,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
SessionKey = '_myapp_session'
SessionSecret = 'b3c631c314c0bbca50c1b2843150fe33'
- Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, 'SHA1')
+ Verifier = ActiveSupport::MessageVerifier.new(SessionSecret, :digest => 'SHA1')
SignedBar = Verifier.generate(:foo => "bar", :session_id => SecureRandom.hex(16))
class TestController < ActionController::Base
diff --git a/actionpack/test/fixtures/comments/empty.de.html.erb b/actionpack/test/fixtures/comments/empty.de.html.erb
new file mode 100644
index 0000000000..cffd90dd26
--- /dev/null
+++ b/actionpack/test/fixtures/comments/empty.de.html.erb
@@ -0,0 +1 @@
+<h1>Kein Kommentar</h1> \ No newline at end of file
diff --git a/actionpack/test/fixtures/comments/empty.html.builder b/actionpack/test/fixtures/comments/empty.html.builder
new file mode 100644
index 0000000000..2b0c7207a3
--- /dev/null
+++ b/actionpack/test/fixtures/comments/empty.html.builder
@@ -0,0 +1 @@
+xml.h1 'No Comment' \ No newline at end of file
diff --git a/actionpack/test/fixtures/comments/empty.html.erb b/actionpack/test/fixtures/comments/empty.html.erb
new file mode 100644
index 0000000000..827f3861de
--- /dev/null
+++ b/actionpack/test/fixtures/comments/empty.html.erb
@@ -0,0 +1 @@
+<h1>No Comment</h1> \ No newline at end of file
diff --git a/actionpack/test/fixtures/comments/empty.xml.erb b/actionpack/test/fixtures/comments/empty.xml.erb
new file mode 100644
index 0000000000..db1027cd7d
--- /dev/null
+++ b/actionpack/test/fixtures/comments/empty.xml.erb
@@ -0,0 +1 @@
+<error>No Comment</error> \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb b/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb
index 5db0822f07..820e7db789 100644
--- a/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb
+++ b/actionpack/test/fixtures/test/_layout_with_partial_and_yield.html.erb
@@ -1,4 +1,4 @@
Before
-<%= render :partial => "test/partial.html.erb" %>
+<%= render :partial => "test/partial" %>
<%= yield %>
After
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index d93433deac..aa7304b3ed 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -366,6 +366,10 @@ class AssetTagHelperTest < ActionView::TestCase
assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe?
end
+ def test_stylesheet_link_tag_escapes_options
+ assert_dom_equal %(<link href="/file.css" media="&lt;script&gt;" rel="stylesheet" type="text/css" />), stylesheet_link_tag('/file', :media => '<script>')
+ end
+
def test_custom_stylesheet_expansions
ENV["RAILS_ASSET_ID"] = ''
ActionView::Helpers::AssetTagHelper::register_stylesheet_expansion :robbery => ["bank", "robber"]
diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb
index 8be0f452fb..8fc78283d8 100644
--- a/actionpack/test/template/compiled_templates_test.rb
+++ b/actionpack/test/template/compiled_templates_test.rb
@@ -10,24 +10,24 @@ class CompiledTemplatesTest < Test::Unit::TestCase
end
def test_template_gets_recompiled_when_using_different_keys_in_local_assigns
- assert_equal "one", render(:file => "test/render_file_with_locals_and_default.erb")
- assert_equal "two", render(:file => "test/render_file_with_locals_and_default.erb", :locals => { :secret => "two" })
+ assert_equal "one", render(:file => "test/render_file_with_locals_and_default")
+ assert_equal "two", render(:file => "test/render_file_with_locals_and_default", :locals => { :secret => "two" })
end
def test_template_changes_are_not_reflected_with_cached_templates
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", render(:file => "test/hello_world")
modify_template "test/hello_world.erb", "Goodbye world!" do
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", render(:file => "test/hello_world")
end
- assert_equal "Hello world!", render(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", render(:file => "test/hello_world")
end
def test_template_changes_are_reflected_with_uncached_templates
- assert_equal "Hello world!", render_without_cache(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", render_without_cache(:file => "test/hello_world")
modify_template "test/hello_world.erb", "Goodbye world!" do
- assert_equal "Goodbye world!", render_without_cache(:file => "test/hello_world.erb")
+ assert_equal "Goodbye world!", render_without_cache(:file => "test/hello_world")
end
- assert_equal "Hello world!", render_without_cache(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", render_without_cache(:file => "test/hello_world")
end
private
diff --git a/actionpack/test/template/compressors_test.rb b/actionpack/test/template/compressors_test.rb
new file mode 100644
index 0000000000..583a1455ba
--- /dev/null
+++ b/actionpack/test/template/compressors_test.rb
@@ -0,0 +1,29 @@
+require 'abstract_unit'
+require 'rails/railtie'
+require 'sprockets/railtie'
+
+class CompressorsTest < ActiveSupport::TestCase
+ def test_register_css_compressor
+ Sprockets::Compressors.register_css_compressor(:null, Sprockets::NullCompressor)
+ compressor = Sprockets::Compressors.registered_css_compressor(:null)
+ assert_kind_of Sprockets::NullCompressor, compressor
+ end
+
+ def test_register_js_compressor
+ Sprockets::Compressors.register_js_compressor(:uglifier, 'Uglifier', :require => 'uglifier')
+ compressor = Sprockets::Compressors.registered_js_compressor(:uglifier)
+ assert_kind_of Uglifier, compressor
+ end
+
+ def test_register_default_css_compressor
+ Sprockets::Compressors.register_css_compressor(:null, Sprockets::NullCompressor, :default => true)
+ compressor = Sprockets::Compressors.registered_css_compressor(:default)
+ assert_kind_of Sprockets::NullCompressor, compressor
+ end
+
+ def test_register_default_js_compressor
+ Sprockets::Compressors.register_js_compressor(:null, Sprockets::NullCompressor, :default => true)
+ compressor = Sprockets::Compressors.registered_js_compressor(:default)
+ assert_kind_of Sprockets::NullCompressor, compressor
+ end
+end
diff --git a/actionpack/test/template/log_subscriber_test.rb b/actionpack/test/template/log_subscriber_test.rb
index 50e1cccd3b..752b0f23a8 100644
--- a/actionpack/test/template/log_subscriber_test.rb
+++ b/actionpack/test/template/log_subscriber_test.rb
@@ -27,7 +27,7 @@ class AVLogSubscriberTest < ActiveSupport::TestCase
end
def test_render_file_template
- @view.render(:file => "test/hello_world.erb")
+ @view.render(:file => "test/hello_world")
wait
assert_equal 1, @logger.logged(:info).size
diff --git a/actionpack/test/template/lookup_context_test.rb b/actionpack/test/template/lookup_context_test.rb
index 47b70f05ab..bac2530e3d 100644
--- a/actionpack/test/template/lookup_context_test.rb
+++ b/actionpack/test/template/lookup_context_test.rb
@@ -31,16 +31,6 @@ class LookupContextTest < ActiveSupport::TestCase
assert @lookup_context.formats.frozen?
end
- test "allows me to change some details to execute an specific block of code" do
- formats = Mime::SET
- @lookup_context.update_details(:locale => :pt) do
- assert_equal formats, @lookup_context.formats
- assert_equal :pt, @lookup_context.locale
- end
- assert_equal formats, @lookup_context.formats
- assert_equal :en, @lookup_context.locale
- end
-
test "provides getters and setters for formats" do
@lookup_context.formats = [:html]
assert_equal [:html], @lookup_context.formats
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 8a582030f6..0ef3239f83 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -21,18 +21,48 @@ module RenderTestCases
end
def test_render_file
- assert_equal "Hello world!", @view.render(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", @view.render(:file => "test/hello_world")
end
def test_render_file_not_using_full_path
- assert_equal "Hello world!", @view.render(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", @view.render(:file => "test/hello_world")
end
def test_render_file_without_specific_extension
assert_equal "Hello world!", @view.render(:file => "test/hello_world")
end
- def test_render_file_with_localization
+ # Test if :formats, :locale etc. options are passed correctly to the resolvers.
+ def test_render_file_with_format
+ assert_match "<h1>No Comment</h1>", @view.render(:file => "comments/empty", :formats => [:html])
+ assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => [:xml])
+ assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => :xml)
+ end
+
+ def test_render_template_with_format
+ assert_match "<h1>No Comment</h1>", @view.render(:template => "comments/empty", :formats => [:html])
+ assert_match "<error>No Comment</error>", @view.render(:template => "comments/empty", :formats => [:xml])
+ end
+
+ def test_render_file_with_locale
+ assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => [:de])
+ assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => :de)
+ end
+
+ def test_render_template_with_locale
+ assert_equal "<h1>Kein Kommentar</h1>", @view.render(:template => "comments/empty", :locale => [:de])
+ end
+
+ def test_render_file_with_handlers
+ assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => [:builder])
+ assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => :builder)
+ end
+
+ def test_render_template_with_handlers
+ assert_equal "<h1>No Comment</h1>\n", @view.render(:template => "comments/empty", :handlers => [:builder])
+ end
+
+ def test_render_file_with_localization_on_context_level
old_locale, @view.locale = @view.locale, :da
assert_equal "Hey verden", @view.render(:file => "test/hello_world")
ensure
@@ -51,17 +81,17 @@ module RenderTestCases
end
def test_render_file_with_full_path
- template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world.erb')
+ template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world')
assert_equal "Hello world!", @view.render(:file => template_path)
end
def test_render_file_with_instance_variables
- assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_ivar.erb")
+ assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_ivar")
end
def test_render_file_with_locals
locals = { :secret => 'in the sauce' }
- assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_locals.erb", :locals => locals)
+ assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_locals", :locals => locals)
end
def test_render_file_not_using_full_path_with_dot_in_path
@@ -80,13 +110,18 @@ module RenderTestCases
assert_equal 'partial html', @view.render(:partial => 'test/partial')
end
+ def test_render_partial_with_selected_format
+ assert_equal 'partial html', @view.render(:partial => 'test/partial', :formats => :html)
+ assert_equal 'partial js', @view.render(:partial => 'test/partial', :formats => [:js])
+ end
+
def test_render_partial_at_top_level
- # file fixtures/_top_level_partial_only.erb (not fixtures/test)
+ # file fixtures/_top_level_partial_only (not fixtures/test)
assert_equal 'top level partial', @view.render(:partial => '/top_level_partial_only')
end
def test_render_partial_with_format_at_top_level
- # file fixtures/_top_level_partial.html.erb (not fixtures/test, with format extension)
+ # file fixtures/_top_level_partial.html (not fixtures/test, with format extension)
assert_equal 'top level partial html', @view.render(:partial => '/top_level_partial')
end
@@ -245,7 +280,7 @@ module RenderTestCases
end
def test_render_layout_with_block_and_other_partial_inside
- render = @view.render(:layout => "test/layout_with_partial_and_yield.html.erb") { "Yield!" }
+ render = @view.render(:layout => "test/layout_with_partial_and_yield") { "Yield!" }
assert_equal "Before\npartial html\nYield!\nAfter\n", render
end
@@ -282,24 +317,26 @@ module RenderTestCases
end
def test_render_ignores_templates_with_malformed_template_handlers
- %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name|
- assert_raise(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") }
+ ActiveSupport::Deprecation.silence do
+ %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name|
+ assert_raise(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") }
+ end
end
end
def test_render_with_layout
assert_equal %(<title></title>\nHello world!\n),
- @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield")
+ @view.render(:file => "test/hello_world", :layout => "layouts/yield")
end
def test_render_with_layout_which_has_render_inline
assert_equal %(welcome\nHello world!\n),
- @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_inline_inside")
+ @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside")
end
def test_render_with_layout_which_renders_another_partial
assert_equal %(partial html\nHello world!\n),
- @view.render(:file => "test/hello_world.erb", :layout => "layouts/yield_with_render_partial_inside")
+ @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside")
end
def test_render_layout_with_block_and_yield
@@ -344,17 +381,17 @@ module RenderTestCases
def test_render_with_nested_layout
assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n),
- @view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield")
+ @view.render(:file => "test/nested_layout", :layout => "layouts/yield")
end
def test_render_with_file_in_layout
assert_equal %(\n<title>title</title>\n\n),
- @view.render(:file => "test/layout_render_file.erb")
+ @view.render(:file => "test/layout_render_file")
end
def test_render_layout_with_object
assert_equal %(<title>David</title>),
- @view.render(:file => "test/layout_render_object.erb")
+ @view.render(:file => "test/layout_render_object")
end
end
@@ -392,7 +429,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase
if '1.9'.respond_to?(:force_encoding)
def test_render_utf8_template_with_magic_comment
with_external_encoding Encoding::ASCII_8BIT do
- result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield")
+ result = @view.render(:file => "test/utf8_magic.html", :layouts => "layouts/yield")
assert_equal Encoding::UTF_8, result.encoding
assert_equal "\nРусский \nтекст\n\nUTF-8\nUTF-8\nUTF-8\n", result
end
@@ -400,7 +437,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase
def test_render_utf8_template_with_default_external_encoding
with_external_encoding Encoding::UTF_8 do
- result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield")
+ result = @view.render(:file => "test/utf8.html", :layouts => "layouts/yield")
assert_equal Encoding::UTF_8, result.encoding
assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result
end
@@ -409,7 +446,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase
def test_render_utf8_template_with_incompatible_external_encoding
with_external_encoding Encoding::SHIFT_JIS do
begin
- @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield")
+ @view.render(:file => "test/utf8.html", :layouts => "layouts/yield")
flunk 'Should have raised incompatible encoding error'
rescue ActionView::Template::Error => error
assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message
@@ -420,7 +457,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase
def test_render_utf8_template_with_partial_with_incompatible_encoding
with_external_encoding Encoding::SHIFT_JIS do
begin
- @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield")
+ @view.render(:file => "test/utf8_magic_with_bare_partial.html", :layouts => "layouts/yield")
flunk 'Should have raised incompatible encoding error'
rescue ActionView::Template::Error => error
assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message
diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb
index c0fb07a29b..b1e6db7b34 100644
--- a/actionpack/test/template/sprockets_helper_test.rb
+++ b/actionpack/test/template/sprockets_helper_test.rb
@@ -47,6 +47,16 @@ class SprocketsHelperTest < ActionView::TestCase
asset_path("logo.png", :digest => false)
end
+ test "custom_asset_path" do
+ @config.assets.prefix = '/s'
+ assert_match %r{/s/logo-[0-9a-f]+.png},
+ asset_path("logo.png")
+ assert_match %r{/s/logo-[0-9a-f]+.png},
+ asset_path("logo.png", :digest => true)
+ assert_match %r{/s/logo.png},
+ asset_path("logo.png", :digest => false)
+ end
+
test "asset_path with root relative assets" do
assert_equal "/images/logo",
asset_path("/images/logo")
@@ -112,6 +122,18 @@ class SprocketsHelperTest < ActionView::TestCase
end
end
+ test "image_tag" do
+ assert_dom_equal '<img alt="Xml" src="/assets/xml.png" />', image_tag("xml.png")
+ end
+
+ test "image_path" do
+ assert_match %r{/assets/logo-[0-9a-f]+.png},
+ image_path("logo.png")
+
+ assert_match %r{/assets/logo-[0-9a-f]+.png},
+ path_to_image("logo.png")
+ 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"
@@ -252,4 +274,12 @@ class SprocketsHelperTest < ActionView::TestCase
assert_not_equal prod_path, dev_path
end
+
+ test "precedence of `config.digest = false` over manifest.yml asset digests" do
+ Rails.application.config.assets.digests = {'logo.png' => 'logo-d1g3st.png'}
+ @config.assets.digest = false
+
+ assert_equal '/assets/logo.png',
+ asset_path("logo.png")
+ end
end
diff --git a/actionpack/test/template/streaming_render_test.rb b/actionpack/test/template/streaming_render_test.rb
index 023ce723ed..4d01352b43 100644
--- a/actionpack/test/template/streaming_render_test.rb
+++ b/actionpack/test/template/streaming_render_test.rb
@@ -28,7 +28,7 @@ class FiberedTest < ActiveSupport::TestCase
def test_streaming_works
content = []
- body = render_body(:template => "test/hello_world.erb", :layout => "layouts/yield")
+ body = render_body(:template => "test/hello_world", :layout => "layouts/yield")
body.each do |piece|
content << piece
@@ -42,12 +42,12 @@ class FiberedTest < ActiveSupport::TestCase
end
def test_render_file
- assert_equal "Hello world!", buffered_render(:file => "test/hello_world.erb")
+ assert_equal "Hello world!", buffered_render(:file => "test/hello_world")
end
def test_render_file_with_locals
locals = { :secret => 'in the sauce' }
- assert_equal "The secret is in the sauce\n", buffered_render(:file => "test/render_file_with_locals.erb", :locals => locals)
+ assert_equal "The secret is in the sauce\n", buffered_render(:file => "test/render_file_with_locals", :locals => locals)
end
def test_render_partial
@@ -64,27 +64,27 @@ class FiberedTest < ActiveSupport::TestCase
def test_render_with_layout
assert_equal %(<title></title>\nHello world!\n),
- buffered_render(:template => "test/hello_world.erb", :layout => "layouts/yield")
+ buffered_render(:template => "test/hello_world", :layout => "layouts/yield")
end
def test_render_with_layout_which_has_render_inline
assert_equal %(welcome\nHello world!\n),
- buffered_render(:template => "test/hello_world.erb", :layout => "layouts/yield_with_render_inline_inside")
+ buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside")
end
def test_render_with_layout_which_renders_another_partial
assert_equal %(partial html\nHello world!\n),
- buffered_render(:template => "test/hello_world.erb", :layout => "layouts/yield_with_render_partial_inside")
+ buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside")
end
def test_render_with_nested_layout
assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n),
- buffered_render(:template => "test/nested_layout.erb", :layout => "layouts/yield")
+ buffered_render(:template => "test/nested_layout", :layout => "layouts/yield")
end
def test_render_with_file_in_layout
assert_equal %(\n<title>title</title>\n\n),
- buffered_render(:template => "test/layout_render_file.erb")
+ buffered_render(:template => "test/layout_render_file")
end
def test_render_with_handler_without_streaming_support
diff --git a/activemodel/lib/active_model/serialization.rb b/activemodel/lib/active_model/serialization.rb
index b9f6f6cbbf..a756b9f205 100644
--- a/activemodel/lib/active_model/serialization.rb
+++ b/activemodel/lib/active_model/serialization.rb
@@ -78,8 +78,10 @@ module ActiveModel
attribute_names -= Array.wrap(except).map(&:to_s)
end
+ hash = attributes.slice(*attribute_names)
+
method_names = Array.wrap(options[:methods]).select { |n| respond_to?(n) }
- hash = Hash[(attribute_names + method_names).map { |n| [n, send(n)] }]
+ method_names.each { |n| hash[n] = send(n) }
serializable_add_includes(options) do |association, records, opts|
hash[association] = if records.is_a?(Enumerable)
diff --git a/activemodel/lib/active_model/serializers/json.rb b/activemodel/lib/active_model/serializers/json.rb
index 4fbccd7419..885964633f 100644
--- a/activemodel/lib/active_model/serializers/json.rb
+++ b/activemodel/lib/active_model/serializers/json.rb
@@ -86,21 +86,15 @@ module ActiveModel
# "title": "Welcome to the weblog"},
# {"comments": [{"body": "Don't think too hard"}],
# "title": "So I was thinking"}]}
-
def as_json(options = nil)
- hash = serializable_hash(options)
-
- include_root = include_root_in_json
- if options.try(:key?, :root)
- include_root = options[:root]
+ root = include_root_in_json
+ root = options[:root] if options.try(:key?, :root)
+ if root
+ root = self.class.model_name.element if root == true
+ { root => serializable_hash(options) }
+ else
+ serializable_hash(options)
end
-
- if include_root
- custom_root = options && options[:root]
- hash = { custom_root || self.class.model_name.element => hash }
- end
-
- hash
end
def from_json(json, include_root=include_root_in_json)
diff --git a/activemodel/test/cases/serialization_test.rb b/activemodel/test/cases/serialization_test.rb
index 071cb9ff4e..29bcdeae67 100644
--- a/activemodel/test/cases/serialization_test.rb
+++ b/activemodel/test/cases/serialization_test.rb
@@ -77,6 +77,15 @@ class SerializationTest < ActiveModel::TestCase
assert_equal expected , @user.serializable_hash(:methods => [:bar])
end
+ def test_should_not_call_methods_for_attributes
+ def @user.name
+ "Jon"
+ end
+
+ expected = { "name" => "David" }
+ assert_equal expected, @user.serializable_hash(:only => :name)
+ end
+
def test_include_option_with_singular_association
expected = {"name"=>"David", "gender"=>"male", "email"=>"david@example.com",
:address=>{"street"=>"123 Lane", "city"=>"Springfield", "state"=>"CA", "zip"=>11111}}
diff --git a/activemodel/test/cases/serializers/json_serialization_test.rb b/activemodel/test/cases/serializers/json_serialization_test.rb
index 5e1e7d897a..40fdcf20ca 100644
--- a/activemodel/test/cases/serializers/json_serialization_test.rb
+++ b/activemodel/test/cases/serializers/json_serialization_test.rb
@@ -56,6 +56,16 @@ class JsonSerializationTest < ActiveModel::TestCase
end
end
+ test "should include root in json (option) even if the default is set to false" do
+ begin
+ Contact.include_root_in_json = false
+ json = @contact.to_json(:root => true)
+ assert_match %r{^\{"contact":\{}, json
+ ensure
+ Contact.include_root_in_json = true
+ end
+ end
+
test "should not include root in json (option)" do
json = @contact.to_json(:root => false)
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index 9e6d9e73c5..6cc401e6cc 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -42,10 +42,6 @@ module ActiveRecord
select_value ||= options[:uniq] && "DISTINCT #{reflection.quoted_table_name}.*"
end
- if reflection.macro == :has_and_belongs_to_many
- select_value ||= reflection.klass.arel_table[Arel.star]
- end
-
select_value
end
@@ -68,7 +64,12 @@ module ActiveRecord
end
if reflection.source_macro == :belongs_to
- key = reflection.association_primary_key
+ if reflection.options[:polymorphic]
+ key = reflection.association_primary_key(klass)
+ else
+ key = reflection.association_primary_key
+ end
+
foreign_key = reflection.foreign_key
else
key = reflection.foreign_key
diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb
index 58c9648ce8..97f531d064 100644
--- a/activerecord/lib/active_record/associations/belongs_to_association.rb
+++ b/activerecord/lib/active_record/associations/belongs_to_association.rb
@@ -45,7 +45,11 @@ module ActiveRecord
end
def replace_keys(record)
- owner[reflection.foreign_key] = record && record[reflection.association_primary_key]
+ if record
+ owner[reflection.foreign_key] = record[reflection.association_primary_key(record.class)]
+ else
+ owner[reflection.foreign_key] = nil
+ end
end
def foreign_key_present?
diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb
index 6ba3d45aff..3181ca9a32 100644
--- a/activerecord/lib/active_record/associations/collection_proxy.rb
+++ b/activerecord/lib/active_record/associations/collection_proxy.rb
@@ -46,7 +46,7 @@ module ActiveRecord
delegate :select, :find, :first, :last,
:build, :create, :create!,
- :concat, :delete_all, :destroy_all, :delete, :destroy, :uniq,
+ :concat, :replace, :delete_all, :destroy_all, :delete, :destroy, :uniq,
:sum, :count, :size, :length, :empty?,
:any?, :many?, :include?,
:to => :@association
diff --git a/activerecord/lib/active_record/attribute_methods/primary_key.rb b/activerecord/lib/active_record/attribute_methods/primary_key.rb
index ed71b5e7d4..a404a5edd7 100644
--- a/activerecord/lib/active_record/attribute_methods/primary_key.rb
+++ b/activerecord/lib/active_record/attribute_methods/primary_key.rb
@@ -66,7 +66,6 @@ module ActiveRecord
@primary_key ||= ''
self.original_primary_key = @primary_key
value &&= value.to_s
- connection_pool.primary_keys[table_name] = value
self.primary_key = block_given? ? instance_eval(&block) : value
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 558b341c06..78159d13d4 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -707,6 +707,10 @@ 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
+ end
+
connection_pool.columns[table_name]
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 89179779e3..1929a808ed 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -211,11 +211,9 @@ module ActiveRecord
@association_foreign_key ||= options[:association_foreign_key] || class_name.foreign_key
end
- def association_primary_key
- @association_primary_key ||=
- options[:primary_key] ||
- !options[:polymorphic] && klass.primary_key ||
- 'id'
+ # klass option is necessary to support loading polymorphic associations
+ def association_primary_key(klass = self.klass)
+ options[:primary_key] || klass.primary_key
end
def active_record_primary_key
@@ -463,17 +461,15 @@ module ActiveRecord
# We want to use the klass from this reflection, rather than just delegate straight to
# the source_reflection, because the source_reflection may be polymorphic. We still
# need to respect the source_reflection's :primary_key option, though.
- def association_primary_key
- @association_primary_key ||= begin
- # Get the "actual" source reflection if the immediate source reflection has a
- # source reflection itself
- source_reflection = self.source_reflection
- while source_reflection.source_reflection
- source_reflection = source_reflection.source_reflection
- end
-
- source_reflection.options[:primary_key] || klass.primary_key
+ def association_primary_key(klass = self.klass)
+ # Get the "actual" source reflection if the immediate source reflection has a
+ # source reflection itself
+ source_reflection = self.source_reflection
+ while source_reflection.source_reflection
+ source_reflection = source_reflection.source_reflection
end
+
+ source_reflection.options[:primary_key] || klass.primary_key
end
# Gets an array of possible <tt>:through</tt> source reflection names:
diff --git a/activerecord/test/cases/associations/belongs_to_associations_test.rb b/activerecord/test/cases/associations/belongs_to_associations_test.rb
index 866a3cca10..1160d236c9 100644
--- a/activerecord/test/cases/associations/belongs_to_associations_test.rb
+++ b/activerecord/test/cases/associations/belongs_to_associations_test.rb
@@ -13,6 +13,7 @@ require 'models/comment'
require 'models/sponsor'
require 'models/member'
require 'models/essay'
+require 'models/toy'
class BelongsToAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :companies, :developers, :projects, :topics,
@@ -696,4 +697,11 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
assert_equal nil, comment.reload.parent
assert_equal 0, comments(:greetings).reload.children_count
end
+
+ def test_polymorphic_with_custom_primary_key
+ toy = Toy.create!
+ sponsor = Sponsor.create!(:sponsorable => toy)
+
+ assert_equal toy, sponsor.reload.sponsorable
+ end
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 d8d2a113ff..d1d02c25d5 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
@@ -650,6 +650,14 @@ class HasAndBelongsToManyAssociationsTest < ActiveRecord::TestCase
assert_respond_to categories(:technology).select_testing_posts.find(:first), :correctness_marker
end
+ def test_habtm_selects_all_columns_by_default
+ assert_equal Project.column_names, developers(:david).projects.first.attributes.keys
+ end
+
+ def test_habtm_respects_select_query_method
+ assert_equal ['id'], developers(:david).projects.select(:id).first.attributes.keys
+ end
+
def test_join_table_alias
assert_equal 3, Developer.find(:all, :include => {:projects => :developers}, :conditions => 'developers_projects_join.joined_on IS NOT NULL').size
end
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 1e59931963..fdfbcbefac 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -485,6 +485,14 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal 0, authors(:mary).popular_grouped_posts.length
end
+ def test_default_select
+ assert_equal Comment.column_names, posts(:welcome).comments.first.attributes.keys
+ end
+
+ def test_select_query_method
+ assert_equal ['id'], posts(:welcome).comments.select(:id).first.attributes.keys
+ end
+
def test_adding
force_signal37_to_load_all_clients_of_firm
natural = Client.new("name" => "Natural Company")
@@ -1578,4 +1586,15 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
assert_equal car.id, bulb.attributes_after_initialize['car_id']
end
+
+ def test_replace
+ car = Car.create(:name => 'honda')
+ bulb1 = car.bulbs.create
+ bulb2 = Bulb.create
+
+ assert_equal [bulb1], car.bulbs
+ car.bulbs.replace([bulb2])
+ assert_equal [bulb2], car.bulbs
+ assert_equal [bulb2], car.reload.bulbs
+ end
end
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 05a41d8a0a..489c7d8310 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -145,4 +145,20 @@ class PrimaryKeysTest < ActiveRecord::TestCase
k.set_primary_key "bar"
assert_equal k.connection.quote_column_name("bar"), k.quoted_primary_key
end
+
+ def test_set_primary_key_with_no_connection
+ return skip("disconnect wipes in-memory db") if in_memory_db?
+
+ connection = ActiveRecord::Base.remove_connection
+
+ model = Class.new(ActiveRecord::Base) do
+ set_primary_key 'foo'
+ end
+
+ assert_equal 'foo', model.primary_key
+
+ ActiveRecord::Base.establish_connection(connection)
+
+ assert_equal 'foo', model.primary_key
+ end
end
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 41312e8661..0a48f418b1 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -244,7 +244,6 @@ 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 "id", Tagging.reflect_on_association(:taggable).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/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb
index d4063fa299..7b42f64a35 100644
--- a/activeresource/test/cases/base_test.rb
+++ b/activeresource/test/cases/base_test.rb
@@ -1004,9 +1004,17 @@ class BaseTest < Test::Unit::TestCase
def test_to_xml_with_private_method_name_as_attribute
Person.format = :xml
- assert_nothing_raised(ArgumentError) {
- Customer.new(:test => true).to_xml
- }
+
+ customer = Customer.new(:foo => "foo")
+ customer.singleton_class.class_eval do
+ def foo
+ "bar"
+ end
+ private :foo
+ end
+
+ assert !customer.to_xml.include?("<foo>bar</foo>")
+ assert customer.to_xml.include?("<foo>foo</foo>")
ensure
Person.format = :json
end
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 537980d6a1..63f406cd9f 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.2.0 (unreleased)*
+* Added safe_constantize that constantizes a string but returns nil instead of an exception if the constant (or part of it) does not exist [Ryan Oblak]
+
* ActiveSupport::OrderedHash is now marked as extractable when using Array#extract_options! [Prem Sichanugrist]
* Added Array#prepend as an alias for Array#unshift and Array#append as an alias for Array#<< [DHH]
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index f7c01948b4..3f516d4808 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -13,6 +13,7 @@ module ActiveSupport
attr_reader :cache_path
DIR_FORMATTER = "%03X"
+ FILENAME_MAX_SIZE = 230 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
def initialize(cache_path, options = nil)
super(options)
@@ -129,15 +130,13 @@ module ActiveSupport
hash, dir_1 = hash.divmod(0x1000)
dir_2 = hash.modulo(0x1000)
fname_paths = []
- # Make sure file name is < 255 characters so it doesn't exceed file system limits.
- if fname.size <= 255
- fname_paths << fname
- else
- while fname.size <= 255
- fname_path << fname[0, 255]
- fname = fname[255, -1]
- end
- end
+
+ # Make sure file name doesn't exceed file system limits.
+ begin
+ fname_paths << fname[0, FILENAME_MAX_SIZE]
+ fname = fname[FILENAME_MAX_SIZE..-1]
+ end until fname.blank?
+
File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
end
diff --git a/activesupport/lib/active_support/core_ext/module/reachable.rb b/activesupport/lib/active_support/core_ext/module/reachable.rb
index 443d2c3d53..5d3d0e9851 100644
--- a/activesupport/lib/active_support/core_ext/module/reachable.rb
+++ b/activesupport/lib/active_support/core_ext/module/reachable.rb
@@ -3,8 +3,6 @@ require 'active_support/core_ext/string/inflections'
class Module
def reachable? #:nodoc:
- !anonymous? && name.constantize.equal?(self)
- rescue NameError
- false
+ !anonymous? && name.safe_constantize.equal?(self)
end
end
diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb
index 002688d6c0..c7ceeb9de4 100644
--- a/activesupport/lib/active_support/core_ext/string/inflections.rb
+++ b/activesupport/lib/active_support/core_ext/string/inflections.rb
@@ -33,14 +33,27 @@ class String
# +constantize+ tries to find a declared constant with the name specified
# in the string. It raises a NameError when the name is not in CamelCase
- # or is not initialized.
+ # or is not initialized. See ActiveSupport::Inflector.constantize
#
# Examples
- # "Module".constantize # => Module
- # "Class".constantize # => Class
+ # "Module".constantize # => Module
+ # "Class".constantize # => Class
+ # "blargle".constantize # => NameError: wrong constant name blargle
def constantize
ActiveSupport::Inflector.constantize(self)
end
+
+ # +safe_constantize+ tries to find a declared constant with the name specified
+ # in the string. It returns nil when the name is not in CamelCase
+ # or is not initialized. See ActiveSupport::Inflector.safe_constantize
+ #
+ # Examples
+ # "Module".safe_constantize # => Module
+ # "Class".safe_constantize # => Class
+ # "blargle".safe_constantize # => nil
+ def safe_constantize
+ ActiveSupport::Inflector.safe_constantize(self)
+ end
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
# is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
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 3ae3d64fa4..2daf4016cd 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -20,7 +20,7 @@ class ERB
if s.html_safe?
s
else
- s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;").html_safe
+ s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;").html_safe
end
end
@@ -144,7 +144,7 @@ module ActiveSupport #:nodoc:
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.gsub(*args, &block)
+ to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
end # end
def #{unsafe_method}!(*args) # def capitalize!(*args)
diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb
index 423b5abd20..934529d496 100644
--- a/activesupport/lib/active_support/inflector/methods.rb
+++ b/activesupport/lib/active_support/inflector/methods.rb
@@ -224,6 +224,39 @@ module ActiveSupport
end
end
+ # Tries to find a constant with the name specified in the argument string:
+ #
+ # "Module".safe_constantize # => Module
+ # "Test::Unit".safe_constantize # => Test::Unit
+ #
+ # The name is assumed to be the one of a top-level constant, no matter whether
+ # it starts with "::" or not. No lexical context is taken into account:
+ #
+ # C = 'outside'
+ # module M
+ # C = 'inside'
+ # C # => 'inside'
+ # "C".safe_constantize # => 'outside', same as ::C
+ # end
+ #
+ # nil is returned when the name is not in CamelCase or the constant (or part of it) is
+ # unknown.
+ #
+ # "blargle".safe_constantize # => nil
+ # "UnknownModule".safe_constantize # => nil
+ # "UnknownModule::Foo::Bar".safe_constantize # => nil
+ #
+ def safe_constantize(camel_cased_word)
+ begin
+ constantize(camel_cased_word)
+ rescue NameError => e
+ raise unless e.message =~ /uninitialized constant #{const_regexp(camel_cased_word)}$/ ||
+ e.name.to_s == camel_cased_word.to_s
+ rescue ArgumentError => e
+ raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
+ end
+ end
+
# Turns a number into an ordinal string used to denote the position in an
# ordered sequence such as 1st, 2nd, 3rd, 4th.
#
@@ -246,5 +279,18 @@ module ActiveSupport
end
end
end
+
+ private
+
+ # Mount a regular expression that will match part by part of the constant.
+ # For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
+ def const_regexp(camel_cased_word) #:nodoc:
+ parts = camel_cased_word.split("::")
+ last = parts.pop
+
+ parts.reverse.inject(last) do |acc, part|
+ part.empty? ? acc : "#{part}(::#{acc})?"
+ end
+ end
end
end
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index 6bb13ec9b8..b692a41312 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -357,7 +357,7 @@ module CacheStoreBehavior
def test_really_long_keys
key = ""
- 1000.times{key << "x"}
+ 900.times{key << "x"}
assert_equal true, @cache.write(key, "bar")
assert_equal "bar", @cache.read(key)
assert_equal "bar", @cache.fetch(key)
@@ -557,6 +557,15 @@ class FileStoreTest < ActiveSupport::TestCase
key = @cache_with_pathname.send(:key_file_path, "views/index?id=1")
assert_equal "views/index?id=1", @cache_with_pathname.send(:file_path_key, key)
end
+
+ # Because file systems have a maximum filename size, filenames > max size should be split in to directories
+ # If filename is 'AAAAB', where max size is 4, the returned path should be AAAA/B
+ def test_key_transformation_max_filename_size
+ key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}B"
+ path = @cache.send(:key_file_path, key)
+ assert path.split('/').all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}
+ assert_equal 'B', File.basename(path)
+ end
end
class MemoryStoreTest < ActiveSupport::TestCase
diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb
new file mode 100644
index 0000000000..81d200a0c8
--- /dev/null
+++ b/activesupport/test/constantize_test_cases.rb
@@ -0,0 +1,37 @@
+module Ace
+ module Base
+ class Case
+ end
+ end
+end
+
+module ConstantizeTestCases
+ def run_constantize_tests_on
+ assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") }
+ assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") }
+ assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") }
+ assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") }
+ assert_raise(NameError) { yield("UnknownClass") }
+ assert_raise(NameError) { yield("UnknownClass::Ace") }
+ assert_raise(NameError) { yield("UnknownClass::Ace::Base") }
+ assert_raise(NameError) { yield("An invalid string") }
+ assert_raise(NameError) { yield("InvalidClass\n") }
+ assert_raise(NameError) { yield("Ace::ConstantizeTestCases") }
+ assert_raise(NameError) { yield("Ace::Base::ConstantizeTestCases") }
+ end
+
+ def run_safe_constantize_tests_on
+ assert_nothing_raised { assert_equal Ace::Base::Case, yield("Ace::Base::Case") }
+ assert_nothing_raised { assert_equal Ace::Base::Case, yield("::Ace::Base::Case") }
+ assert_nothing_raised { assert_equal ConstantizeTestCases, yield("ConstantizeTestCases") }
+ assert_nothing_raised { assert_equal ConstantizeTestCases, yield("::ConstantizeTestCases") }
+ assert_nothing_raised { assert_equal nil, yield("UnknownClass") }
+ assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace") }
+ assert_nothing_raised { assert_equal nil, yield("UnknownClass::Ace::Base") }
+ assert_nothing_raised { assert_equal nil, yield("An invalid string") }
+ assert_nothing_raised { assert_equal nil, yield("InvalidClass\n") }
+ assert_nothing_raised { assert_equal nil, yield("blargle") }
+ assert_nothing_raised { assert_equal nil, yield("Ace::ConstantizeTestCases") }
+ assert_nothing_raised { assert_equal nil, yield("Ace::Base::ConstantizeTestCases") }
+ end
+end \ No newline at end of file
diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb
index 81a284dded..5c1dddaf96 100644
--- a/activesupport/test/core_ext/string_ext_test.rb
+++ b/activesupport/test/core_ext/string_ext_test.rb
@@ -2,6 +2,7 @@
require 'date'
require 'abstract_unit'
require 'inflector_test_cases'
+require 'constantize_test_cases'
require 'active_support/inflector'
require 'active_support/core_ext/string'
@@ -9,9 +10,17 @@ require 'active_support/time'
require 'active_support/core_ext/string/strip'
require 'active_support/core_ext/string/output_safety'
+module Ace
+ module Base
+ class Case
+ end
+ end
+end
+
class StringInflectionsTest < Test::Unit::TestCase
include InflectorTestCases
-
+ include ConstantizeTestCases
+
def test_erb_escape
string = [192, 60].pack('CC')
expected = 192.chr + "&lt;"
@@ -292,6 +301,18 @@ class StringInflectionsTest < Test::Unit::TestCase
"\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding('UTF-8').truncate(10)
end
end
+
+ def test_constantize
+ run_constantize_tests_on do |string|
+ string.constantize
+ end
+ end
+
+ def test_safe_constantize
+ run_safe_constantize_tests_on do |string|
+ string.safe_constantize
+ end
+ end
end
class StringBehaviourTest < Test::Unit::TestCase
diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb
index b9e299af75..5c956e0075 100644
--- a/activesupport/test/inflector_test.rb
+++ b/activesupport/test/inflector_test.rb
@@ -2,16 +2,11 @@ require 'abstract_unit'
require 'active_support/inflector'
require 'inflector_test_cases'
-
-module Ace
- module Base
- class Case
- end
- end
-end
+require 'constantize_test_cases'
class InflectorTest < Test::Unit::TestCase
include InflectorTestCases
+ include ConstantizeTestCases
def test_pluralize_plurals
assert_equal "plurals", ActiveSupport::Inflector.pluralize("plurals")
@@ -282,17 +277,15 @@ class InflectorTest < Test::Unit::TestCase
end
def test_constantize
- assert_nothing_raised { assert_equal Ace::Base::Case, ActiveSupport::Inflector.constantize("Ace::Base::Case") }
- assert_nothing_raised { assert_equal Ace::Base::Case, ActiveSupport::Inflector.constantize("::Ace::Base::Case") }
- assert_nothing_raised { assert_equal InflectorTest, ActiveSupport::Inflector.constantize("InflectorTest") }
- assert_nothing_raised { assert_equal InflectorTest, ActiveSupport::Inflector.constantize("::InflectorTest") }
- assert_raise(NameError) { ActiveSupport::Inflector.constantize("UnknownClass") }
- assert_raise(NameError) { ActiveSupport::Inflector.constantize("An invalid string") }
- assert_raise(NameError) { ActiveSupport::Inflector.constantize("InvalidClass\n") }
+ run_constantize_tests_on do |string|
+ ActiveSupport::Inflector.constantize(string)
+ end
end
-
- def test_constantize_does_lexical_lookup
- assert_raise(NameError) { ActiveSupport::Inflector.constantize("Ace::Base::InflectorTest") }
+
+ def test_safe_constantize
+ run_safe_constantize_tests_on do |string|
+ ActiveSupport::Inflector.safe_constantize(string)
+ end
end
def test_ordinal
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 72e5921d6d..54eef0473c 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -10,6 +10,18 @@
* Removed old 'config.paths.app.controller' API in favor of 'config.paths["app/controller"]' API. [Guillermo Iguaran]
+
+*Rails 3.1.1
+
+* `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.
+
+
*Rails 3.1.0 (August 30, 2011)*
* The default database schema file is written as UTF-8. [Aaron Patterson]
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index 3428c09bcd..b343e8d01d 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -17,13 +17,13 @@ The asset pipeline provides a framework to concatenate and minify or compress Ja
Prior to Rails 3.1 these features were added through third-party Ruby libraries such as Jammit and Sprockets. Rails 3.1 is integrated with Sprockets through Action Pack which depends on the +sprockets+ gem, by default.
-By having this as a core feature of Rails, all developers can benefit from the power of having their assets pre-processed, compressed and minified by one central library, Sprockets. This is part of Rails' "Fast by default" strategy as outlined by DHH in his 2011 keynote at Railsconf.
+By having this as a core feature of Rails, all developers can benefit from the power of having their assets pre-processed, compressed and minified by one central library, Sprockets. This is part of Rails' "fast by default" strategy as outlined by DHH in his keynote at RailsConf 2011.
-In Rails 3.1, the asset pipeline is enabled by default. It can be disabled in +application.rb+ by putting this line inside the +Application+ class definition:
+In Rails 3.1, the asset pipeline is enabled by default. It can be disabled in +config/application.rb+ by putting this line inside the application class definition:
-<plain>
+<ruby>
config.assets.enabled = false
-</plain>
+</ruby>
You can also disable it while creating a new application by passing the <tt>--skip-sprockets</tt> option.
@@ -36,7 +36,9 @@ It is recommended that you use the defaults for all new apps.
h4. Main Features
-The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser must make to render a web page. While Rails already has a feature to concatenate these types of assets -- by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+ -- many people do not use it.
+The first feature of the pipeline is to concatenate assets. This is important in a production environment, as it reduces the number of requests that a browser must make to render a web page.
+
+While Rails already has a feature to concatenate these types of assets -- by placing +:cache => true+ at the end of tags such as +javascript_include_tag+ and +stylesheet_link_tag+ --, it has a series of limitations. For example, it cannot generate the caches in advance, and it is not able to transparently include assets provided by third-party libraries.
The default behavior in Rails 3.1 and onward is to concatenate all files into one master file each for JS and CSS. However, you can separate files or groups of files if required (see below). In production, an MD5 fingerprint is inserted into each filename so that the file is cached by the web browser but can be invalidated if the fingerprint is altered.
@@ -46,14 +48,14 @@ The third feature is the ability to code these assets using another language, or
h4. What is Fingerprinting and Why Should I Care?
-Fingerprinting is a technique whereby the filenames of content that is static or infrequently updated is altered to be unique to the content contained in the file.
+Fingerprinting is a technique whereby the filenames of content that is static or infrequently updated are altered to be unique to the content contained in the file.
-When a filename is unique and based on its content, HTTP headers can be set to encourage caches everywhere (at ISPs, in browsers) to keep their own copy of the content. When the content is updated, the fingerprint will change and the remote clients will request the new file. This is generally known as _cachebusting_.
+When a filename is unique and based on its content, HTTP headers can be set to encourage caches everywhere (at ISPs, in browsers) to keep their own copy of the content. When the content is updated, the fingerprint will change and the remote clients will request the new file. This is generally known as _cache busting_.
-The most effective technique is to insert a hash of the content into the name, usually at the end. For example a CSS file +global.css+ is hashed and the filename is updated to incorporate the hash.
+The most effective technique is to insert a hash of the content into the name, usually at the end. For example a CSS file +global.css+ is hashed and the filename is updated to incorporate the digest, for example becoming:
<plain>
-global.css => global-908e25f4bf641868d8683022a5b62f54.css
+global-908e25f4bf641868d8683022a5b62f54.css
</plain>
This is the strategy adopted by the Rails asset pipeline.
@@ -68,8 +70,8 @@ This has several disadvantages:
<ol>
<li>
- <strong>Not all caches will cache content with a query string</strong><br>
- "Steve Souders recommends":http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/, "...avoiding a querystring for cacheable resources". He found that in this case 5-20% of requests will not be cached.
+ <strong>Not all caches will cache content with a query string</strong>.<br>
+ "Steve Souders recommends":http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/, "...avoiding a querystring for cacheable resources". He found that in this case 5-20% of requests will not be cached. Query strings in particular do not work at all with some CDNs for cache invalidation.
</li>
<li>
<strong>The file name can change between nodes in multi-server environments.</strong><br>
@@ -77,9 +79,9 @@ This has several disadvantages:
</li>
</ol>
-The other problem is that when static assets are deployed with each new release of code, the mtime of *all* these files changes, forcing all remote clients to fetch them again, even when the content of those assets has not changed.
+The other problem is that when static assets are deployed with each new release of code, the mtime of _all_ these files changes, forcing all remote clients to fetch them again, even when the content of those assets has not changed.
-Fingerprinting avoids all these problems by ensuring filenames are consistent based on their content.
+Fingerprinting fixes these problems by avoiding query strings, and by ensuring filenames are consistent based on their content.
Fingerprinting is enabled by default for production and disabled for all the others environments. You can enable or disable it in your configuration through the +config.assets.digest+ option.
@@ -95,7 +97,7 @@ In previous versions of Rails, all assets were located in subdirectories of +pub
This is not to say that assets can (or should) no longer be placed in +public+; they still can be and will be served as static files by the application or web server. You would only use +app/assets+ if you wish your files to undergo some pre-processing before they are served.
-In production, the default is to precompile these files to +public/assets+ so that they can be more efficiently delivered by the webserver.
+In production, the default is to precompile these files to +public/assets+ so that they can be more efficiently delivered by the web server.
When a scaffold or controller is generated for the application, Rails also generates a JavaScript file (or CoffeeScript file if the +coffee-rails+ gem is in the +Gemfile+) and a Cascading Style Sheet file (or SCSS file if +sass-rails+ is in the +Gemfile+) for that controller.
@@ -115,11 +117,11 @@ Assets can be placed inside an application in one of three locations: +app/asset
All subdirectories that exist within these three locations are added to the search path for Sprockets (visible by calling +Rails.application.config.assets.paths+ in a console). When an asset is requested, these paths are traversed to see if they contain an asset matching the name specified. Once an asset has been found, it's processed by Sprockets and served.
-You can add additional (fully qualified) paths to the pipeline in +application.rb+. For example:
+You can add additional (fully qualified) paths to the pipeline in +config/application.rb+. For example:
-<erb>
-config.assets.paths << File.join(Rails.root, 'app', 'assets', 'flash')
-</erb>
+<ruby>
+config.assets.paths << "#{Rails.root}/app/assets/flash"
+</ruby>
h4. Coding Links to Assets
@@ -150,10 +152,10 @@ 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 you can use the +asset_path+ helper 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 +image_path+ are available in your CSS rules:
<plain>
-.class { background-image: url(<%= asset_path 'image.png' %>) }
+.class { background-image: url(<%= image_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.
@@ -654,4 +656,4 @@ Instead of the old Rails 3.0 one
# If you have a Gemfile, require the gems listed there, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env) if defined?(Bundler)
-</ruby> \ No newline at end of file
+</ruby>
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index cad2d03c23..41b53440f7 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -179,7 +179,7 @@ h4. Configuring Middleware
Every Rails application comes with a standard set of middleware which it uses in this order in the development environment:
-* +Rack::SSL+ Will force every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+.
+* +Rack::SSL+ Will force every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. Options passed to this can be configured by using +config.ssl_options+.
* +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is +true+.
* +Rack::Lock+ Will wrap the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default.
* +ActiveSupport::Cache::Strategy::LocalCache+ Serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread.
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 528c96ef3e..2e412147d3 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -83,7 +83,6 @@ module Rails
require environment if environment
end
-
def reload_routes!
routes_reloader.reload!
end
@@ -92,9 +91,9 @@ module Rails
@routes_reloader ||= RoutesReloader.new
end
- def initialize!
+ def initialize!(group=nil)
raise "Application has been already initialized." if @initialized
- run_initializers(self)
+ run_initializers(group, self)
@initialized = true
self
end
@@ -155,7 +154,7 @@ module Rails
if config.force_ssl
require "rack/ssl"
- middleware.use ::Rack::SSL
+ middleware.use ::Rack::SSL, config.ssl_options
end
if config.serve_static_assets
diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb
index c9b147d075..0aff05b681 100644
--- a/railties/lib/rails/application/bootstrap.rb
+++ b/railties/lib/rails/application/bootstrap.rb
@@ -7,21 +7,21 @@ module Rails
module Bootstrap
include Initializable
- initializer :load_environment_hook do end
+ initializer :load_environment_hook, :group => :all do end
- initializer :load_active_support do
+ initializer :load_active_support, :group => :all do
require "active_support/all" unless config.active_support.bare
end
# Preload all frameworks specified by the Configuration#frameworks.
# Used by Passenger to ensure everything's loaded before forking and
# to avoid autoload race conditions in JRuby.
- initializer :preload_frameworks do
+ initializer :preload_frameworks, :group => :all do
ActiveSupport::Autoload.eager_autoload! if config.preload_frameworks
end
# Initialize the logger early in the stack in case we need to log some deprecation.
- initializer :initialize_logger do
+ initializer :initialize_logger, :group => :all do
Rails.logger ||= config.logger || begin
path = config.paths["log"].first
logger = ActiveSupport::BufferedLogger.new(path)
@@ -41,7 +41,7 @@ module Rails
end
# Initialize cache early in the stack so railties can make use of it.
- initializer :initialize_cache do
+ initializer :initialize_cache, :group => :all do
unless defined?(RAILS_CACHE)
silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(config.cache_store) }
@@ -51,7 +51,7 @@ module Rails
end
end
- initializer :set_clear_dependencies_hook do
+ initializer :set_clear_dependencies_hook, :group => :all do
ActionDispatch::Reloader.to_cleanup do
ActiveSupport::DescendantsTracker.clear
ActiveSupport::Dependencies.clear
@@ -60,11 +60,11 @@ module Rails
# Sets the dependency loading mechanism.
# TODO: Remove files from the $" and always use require.
- initializer :initialize_dependency_mechanism do
+ initializer :initialize_dependency_mechanism, :group => :all do
ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load
end
- initializer :bootstrap_hook do |app|
+ initializer :bootstrap_hook, :group => :all do |app|
ActiveSupport.run_load_hooks(:before_initialize, app)
end
end
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index a48db3b6d2..c363e53c10 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -10,7 +10,8 @@ module Rails
:dependency_loading, :filter_parameters,
:force_ssl, :helpers_paths, :logger, :preload_frameworks,
:reload_plugins, :secret_token, :serve_static_assets,
- :static_cache_control, :session_options, :time_zone, :whiny_nils
+ :ssl_options, :static_cache_control, :session_options,
+ :time_zone, :whiny_nils
attr_writer :log_level
attr_reader :encoding
@@ -26,6 +27,7 @@ module Rails
@serve_static_assets = true
@static_cache_control = nil
@force_ssl = false
+ @ssl_options = {}
@session_store = :cookie_store
@session_options = {}
@time_zone = "UTC"
@@ -38,7 +40,7 @@ module Rails
@assets.enabled = false
@assets.paths = []
@assets.precompile = [ Proc.new{ |path| !File.extname(path).in?(['.js', '.css']) },
- /application.(css|js)$/ ]
+ /(?:\/|\\|\A)application\.(css|js)$/ ]
@assets.prefix = "/assets"
@assets.version = ''
@assets.debug = false
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 89b151beb6..0e1e719596 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -537,12 +537,12 @@ module Rails
end
end
- initializer :load_environment_config, :before => :load_environment_hook do
+ initializer :load_environment_config, :before => :load_environment_hook, :group => :all do
environment = paths["config/environments"].existent.first
require environment if environment
end
- initializer :append_assets_path do |app|
+ initializer :append_assets_path, :group => :assets 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/rails/plugin_new/templates/Gemfile b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
index 160baa6906..f4efd3af74 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/Gemfile
@@ -5,6 +5,9 @@ source "http://rubygems.org"
# development dependencies will be added by default to the :development group.
gemspec
+# jquery-rails is used by the dummy application
+gem "jquery-rails"
+
# Declare any dependencies that are still in development here instead of in
# your gemspec. These might include edge Rails or gems from your path or
# Git. Remember to move these dependencies to your gemspec before releasing
@@ -17,4 +20,4 @@ gemspec
<% end -%>
# To use debugger
-# <%= ruby_debugger_gemfile_entry %> \ No newline at end of file
+# <%= ruby_debugger_gemfile_entry %>
diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb
index 686a2dc0cb..4c1da0a5a5 100644
--- a/railties/lib/rails/initializable.rb
+++ b/railties/lib/rails/initializable.rb
@@ -21,6 +21,10 @@ module Rails
@options[:after]
end
+ def belongs_to?(group)
+ @options[:group] == group || @options[:group] == :all
+ end
+
def run(*args)
@context.instance_exec(*args, &block)
end
@@ -44,10 +48,10 @@ module Rails
end
end
- def run_initializers(*args)
+ def run_initializers(group=nil, *args)
return if instance_variable_defined?(:@ran)
initializers.tsort.each do |initializer|
- initializer.run(*args)
+ initializer.run(*args) if group.nil? || initializer.belongs_to?(group)
end
@ran = true
end
diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb
index dfd950aae3..118ffff44b 100644
--- a/railties/test/application/assets_test.rb
+++ b/railties/test/application/assets_test.rb
@@ -21,6 +21,12 @@ module ApplicationTests
@app ||= Rails.application
end
+ def precompile!
+ capture(:stdout) 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 %>();"
@@ -38,7 +44,7 @@ module ApplicationTests
test "assets do not require compressors until it is used" do
app_file "app/assets/javascripts/demo.js.erb", "<%= :alert %>();"
- app_file "config/initializers/compile.rb", "Rails.application.config.assets.compile = true"
+ add_to_env_config "production", "config.assets.compile = true"
ENV["RAILS_ENV"] = "production"
require "#{app_path}/config/environment"
@@ -54,11 +60,12 @@ module ApplicationTests
app_file "app/assets/javascripts/foo/application.js", "alert();"
ENV["RAILS_ENV"] = nil
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
+
files = Dir["#{app_path}/public/assets/application-*.js"]
+ files << Dir["#{app_path}/public/assets/application.js"].first
files << Dir["#{app_path}/public/assets/foo/application-*.js"].first
+ files << Dir["#{app_path}/public/assets/foo/application.js"].first
files.each do |file|
assert_not_nil file, "Expected application.js asset to be generated, but none found"
assert_equal "alert()", File.read(file)
@@ -68,6 +75,10 @@ module ApplicationTests
test "precompile application.js and application.css and all other files not ending with .js or .css by default" do
app_file "app/assets/javascripts/application.js", "alert();"
app_file "app/assets/stylesheets/application.css", "body{}"
+
+ app_file "app/assets/javascripts/someapplication.js", "alert();"
+ app_file "app/assets/stylesheets/someapplication.css", "body{}"
+
app_file "app/assets/javascripts/something.min.js", "alert();"
app_file "app/assets/stylesheets/something.min.css", "body{}"
@@ -76,19 +87,23 @@ module ApplicationTests
"happy.happy.face.png", "happy", "happy.face", "-happyface",
"-happy.png", "-happy.face.png", "_happyface", "_happy.face.png",
"_happy.png"]
+
images_should_compile.each do |filename|
app_file "app/assets/images/#{filename}", "happy"
end
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
images_should_compile.each do |filename|
assert File.exists?("#{app_path}/public/assets/#{filename}")
end
+
assert File.exists?("#{app_path}/public/assets/application.js")
assert File.exists?("#{app_path}/public/assets/application.css")
+
+ assert !File.exists?("#{app_path}/public/assets/someapplication.js")
+ assert !File.exists?("#{app_path}/public/assets/someapplication.css")
+
assert !File.exists?("#{app_path}/public/assets/something.min.js")
assert !File.exists?("#{app_path}/public/assets/something.min.css")
end
@@ -109,10 +124,7 @@ module ApplicationTests
# digest is default in false, we must enable it for test environment
add_to_config "config.assets.digest = true"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
-
+ precompile!
manifest = "#{app_path}/public/assets/manifest.yml"
assets = YAML.load_file(manifest)
@@ -126,12 +138,8 @@ module ApplicationTests
# digest is default in false, we must enable it for test environment
add_to_config "config.assets.digest = true"
add_to_config "config.assets.manifest = '#{app_path}/shared'"
- FileUtils.mkdir "#{app_path}/shared"
-
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
manifest = "#{app_path}/shared/manifest.yml"
assets = YAML.load_file(manifest)
@@ -139,16 +147,13 @@ module ApplicationTests
assert_match(/application-([0-z]+)\.css/, assets["application.css"])
end
-
test "the manifest file should be saved by default in the same assets folder" do
app_file "app/assets/javascripts/application.js", "alert();"
# digest is default in false, we must enable it for test environment
add_to_config "config.assets.digest = true"
add_to_config "config.assets.prefix = '/x'"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
manifest = "#{app_path}/public/x/manifest.yml"
assets = YAML.load_file(manifest)
@@ -160,9 +165,7 @@ module ApplicationTests
app_file "app/assets/javascripts/application.js", "alert();"
add_to_config "config.assets.digest = false"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
assert File.exists?("#{app_path}/public/assets/application.js")
assert File.exists?("#{app_path}/public/assets/application.css")
@@ -176,12 +179,11 @@ module ApplicationTests
test "assets do not require any assets group gem when manifest file is present" do
app_file "app/assets/javascripts/application.js", "alert();"
- app_file "config/initializers/serve_static_assets.rb", "Rails.application.config.serve_static_assets = true"
+ add_to_env_config "production", "config.serve_static_assets = true"
ENV["RAILS_ENV"] = "production"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
+
manifest = "#{app_path}/public/assets/manifest.yml"
assets = YAML.load_file(manifest)
asset_path = assets["application.js"]
@@ -205,9 +207,7 @@ module ApplicationTests
RUBY
ENV["RAILS_ENV"] = "production"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
# Create file after of precompile
app_file "app/assets/javascripts/app.js", "alert();"
@@ -231,9 +231,7 @@ module ApplicationTests
RUBY
ENV["RAILS_ENV"] = "development"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
+ precompile!
# Create file after of precompile
app_file "app/assets/javascripts/app.js", "alert();"
@@ -258,6 +256,24 @@ module ApplicationTests
assert_match(/\/assets\/rails-([0-z]+)\.png/, File.read(file))
end
+ test "precompile shouldn't use the digests present in manifest.yml" do
+ app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
+
+ ENV["RAILS_ENV"] = "production"
+ precompile!
+
+ manifest = "#{app_path}/public/assets/manifest.yml"
+ assets = YAML.load_file(manifest)
+ asset_path = assets["application.css"]
+
+ app_file "app/assets/images/rails.png", "image changed"
+
+ precompile!
+ assets = YAML.load_file(manifest)
+
+ assert_not_equal asset_path, assets["application.css"]
+ end
+
test "precompile appends the md5 hash to files referenced with asset_path and run in production as default even using RAILS_GROUPS=assets" do
app_file "app/assets/stylesheets/application.css.erb", "<%= asset_path('rails.png') %>"
add_to_config "config.assets.compile = true"
@@ -274,10 +290,7 @@ module ApplicationTests
app_file "app/assets/images/レイルズ.png", "not a image really"
add_to_config "config.assets.precompile = [ /\.png$$/, /application.(css|js)$/ ]"
- capture(:stdout) do
- Dir.chdir(app_path){ `bundle exec rake assets:precompile` }
- end
-
+ precompile!
assert File.exists?("#{app_path}/public/assets/レイルズ.png")
manifest = "#{app_path}/public/assets/manifest.yml"
@@ -349,5 +362,50 @@ module ApplicationTests
assert_match "alert();", last_response.body
assert_equal 200, last_response.status
end
+
+ test "assets are concatenated when debug is off and compile is off either if debug_assets param is provided" do
+ app_with_assets_in_view
+
+ # config.assets.debug and config.assets.compile are false for production environment
+ ENV["RAILS_ENV"] = "production"
+ precompile!
+
+ require "#{app_path}/config/environment"
+
+ class ::PostsController < ActionController::Base ; end
+
+ # the debug_assets params isn't used if compile is off
+ get '/posts?debug_assets=true'
+ assert_match(/<script src="\/assets\/application-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body)
+ assert_no_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js" type="text\/javascript"><\/script>/, last_response.body)
+ end
+
+ test "assets aren't concatened when compile is true is on and debug_assets params is true" do
+ app_with_assets_in_view
+ add_to_env_config "production", "config.assets.compile = true"
+ add_to_env_config "production", "config.assets.allow_debugging = true"
+
+ ENV["RAILS_ENV"] = "production"
+ require "#{app_path}/config/environment"
+
+ class ::PostsController < ActionController::Base ; end
+
+ get '/posts?debug_assets=true'
+ assert_match(/<script src="\/assets\/application-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
+ assert_match(/<script src="\/assets\/xmlhr-([0-z]+)\.js\?body=1" type="text\/javascript"><\/script>/, last_response.body)
+ 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(); }"
+ app_file "app/views/posts/index.html.erb", "<%= javascript_include_tag 'application' %>"
+
+ app_file "config/routes.rb", <<-RUBY
+ AppTemplate::Application.routes.draw do
+ match '/posts', :to => "posts#index"
+ end
+ RUBY
+ end
end
end
diff --git a/railties/test/application/middleware_test.rb b/railties/test/application/middleware_test.rb
index bed5ba503f..093cb6ca2a 100644
--- a/railties/test/application/middleware_test.rb
+++ b/railties/test/application/middleware_test.rb
@@ -69,6 +69,14 @@ module ApplicationTests
assert middleware.include?("Rack::SSL")
end
+ test "Rack::SSL is configured with options when given" do
+ add_to_config "config.force_ssl = true"
+ add_to_config "config.ssl_options = { :host => 'example.com' }"
+ boot!
+
+ assert_equal AppTemplate::Application.middleware.first.args, [{:host => 'example.com'}]
+ end
+
test "removing Active Record omits its middleware" do
use_frameworks []
boot!
diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb
index 72c35879c5..1dbcc249ab 100644
--- a/railties/test/initializable_test.rb
+++ b/railties/test/initializable_test.rb
@@ -61,7 +61,7 @@ module InitializableTests
class Instance
include Rails::Initializable
- initializer :one do
+ initializer :one, :group => :assets do
$arr << 1
end
@@ -69,7 +69,7 @@ module InitializableTests
$arr << 2
end
- initializer :three do
+ initializer :three, :group => :all do
$arr << 3
end
@@ -211,12 +211,19 @@ module InitializableTests
instance.run_initializers
assert_equal [1, 2, 3, 4], $arr
end
+
+ test "running locals with groups" do
+ $arr = []
+ instance = Instance.new
+ instance.run_initializers(:assets)
+ assert_equal [1, 3], $arr
+ end
end
class WithArgsTest < ActiveSupport::TestCase
test "running initializers with args" do
$with_arg = nil
- WithArgs.new.run_initializers('foo')
+ WithArgs.new.run_initializers(nil, 'foo')
assert_equal 'foo', $with_arg
end
end
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index 4a6bdb0320..06b658e7bd 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -224,6 +224,15 @@ module TestHelpers
end
end
+ def add_to_env_config(env, str)
+ environment = File.read("#{app_path}/config/environments/#{env}.rb")
+ if environment =~ /(\n\s*end\s*)\Z/
+ File.open("#{app_path}/config/environments/#{env}.rb", 'w') do |f|
+ f.puts $` + "\n#{str}\n" + $1
+ end
+ end
+ end
+
def remove_from_config(str)
file = "#{app_path}/config/application.rb"
contents = File.read(file)