aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2008-05-15 21:54:46 +0100
committerPratik Naik <pratiknaik@gmail.com>2008-05-15 21:54:46 +0100
commit879493c35fd8d9e12e5cf3e56cd67ff07c3345c5 (patch)
tree9615859e1d9a52f71da444b0b7359817bb6acc50
parentd6ecce66f4e125531875006eea8022b73fe135b5 (diff)
parentfc02eabf296d6edb74a95174c7322293a54c9492 (diff)
downloadrails-879493c35fd8d9e12e5cf3e56cd67ff07c3345c5.tar.gz
rails-879493c35fd8d9e12e5cf3e56cd67ff07c3345c5.tar.bz2
rails-879493c35fd8d9e12e5cf3e56cd67ff07c3345c5.zip
Merge commit 'mainstream/master'
Conflicts: actionmailer/lib/action_mailer/base.rb
-rw-r--r--actionmailer/CHANGELOG2
-rw-r--r--actionmailer/MIT-LICENSE2
-rwxr-xr-xactionmailer/Rakefile2
-rwxr-xr-xactionmailer/lib/action_mailer.rb2
-rw-r--r--actionmailer/lib/action_mailer/base.rb96
-rw-r--r--actionmailer/lib/action_mailer/version.rb2
-rw-r--r--actionpack/CHANGELOG3
-rw-r--r--actionpack/MIT-LICENSE2
-rw-r--r--actionpack/Rakefile2
-rwxr-xr-xactionpack/lib/action_controller.rb2
-rwxr-xr-xactionpack/lib/action_controller/base.rb51
-rw-r--r--actionpack/lib/action_controller/caching/actions.rb37
-rw-r--r--actionpack/lib/action_controller/caching/sweeping.rb6
-rw-r--r--actionpack/lib/action_controller/cgi_ext/cookie.rb2
-rw-r--r--actionpack/lib/action_controller/mime_type.rb19
-rw-r--r--actionpack/lib/action_controller/mime_types.rb2
-rw-r--r--actionpack/lib/action_controller/request_forgery_protection.rb2
-rw-r--r--actionpack/lib/action_controller/rescue.rb6
-rw-r--r--actionpack/lib/action_controller/session/cookie_store.rb9
-rw-r--r--actionpack/lib/action_pack.rb2
-rw-r--r--actionpack/lib/action_pack/version.rb2
-rw-r--r--actionpack/lib/action_view.rb2
-rw-r--r--actionpack/lib/action_view/helpers/javascripts/controls.js2
-rw-r--r--actionpack/lib/action_view/helpers/javascripts/dragdrop.js2
-rw-r--r--actionpack/lib/action_view/helpers/javascripts/effects.js2
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb127
-rw-r--r--actionpack/test/controller/caching_test.rb80
-rw-r--r--actionpack/test/controller/cookie_test.rb6
-rw-r--r--actionpack/test/controller/filter_params_test.rb20
-rw-r--r--actionpack/test/controller/mime_type_test.rb25
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb71
-rwxr-xr-xactionpack/test/controller/session/cookie_store_test.rb16
-rw-r--r--actionpack/test/template/prototype_helper_test.rb5
-rw-r--r--actionpack/test/template/text_helper_test.rb41
-rw-r--r--activerecord/CHANGELOG2
-rw-r--r--activerecord/MIT-LICENSE2
-rwxr-xr-xactiverecord/Rakefile2
-rwxr-xr-xactiverecord/lib/active_record.rb2
-rw-r--r--activerecord/lib/active_record/associations.rb31
-rwxr-xr-xactiverecord/lib/active_record/base.rb52
-rw-r--r--activerecord/lib/active_record/dirty.rb16
-rwxr-xr-xactiverecord/lib/active_record/fixtures.rb14
-rw-r--r--activerecord/lib/active_record/version.rb2
-rw-r--r--activerecord/test/cases/dirty_test.rb21
-rw-r--r--activerecord/test/cases/finder_test.rb12
-rwxr-xr-xactiverecord/test/cases/fixtures_test.rb20
-rwxr-xr-xactiverecord/test/cases/inheritance_test.rb28
-rwxr-xr-xactiverecord/test/models/company.rb4
-rw-r--r--activerecord/test/models/pirate.rb2
-rw-r--r--activeresource/CHANGELOG2
-rw-r--r--activeresource/Rakefile2
-rw-r--r--activeresource/lib/active_resource/version.rb2
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/MIT-LICENSE2
-rw-r--r--activesupport/lib/active_support.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb2
-rw-r--r--activesupport/lib/active_support/deprecation.rb13
-rw-r--r--activesupport/lib/active_support/ordered_hash.rb43
-rw-r--r--activesupport/lib/active_support/ordered_options.rb44
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb2
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb9
-rw-r--r--activesupport/lib/active_support/version.rb2
-rw-r--r--activesupport/test/core_ext/time_with_zone_test.rb2
-rw-r--r--activesupport/test/deprecation_test.rb10
-rw-r--r--activesupport/test/ordered_hash_test.rb45
-rw-r--r--activesupport/test/ordered_options_test.rb44
-rwxr-xr-xpushgems.rb2
-rw-r--r--railties/CHANGELOG2
-rw-r--r--railties/MIT-LICENSE2
-rw-r--r--railties/Rakefile12
-rw-r--r--railties/configs/initializers/new_rails_defaults.rb3
-rw-r--r--railties/html/javascripts/controls.js2
-rw-r--r--railties/html/javascripts/dragdrop.js2
-rw-r--r--railties/html/javascripts/effects.js2
-rw-r--r--railties/lib/commands/dbconsole.rb3
-rw-r--r--railties/lib/dispatcher.rb2
-rw-r--r--railties/lib/rails/plugin/locator.rb5
-rw-r--r--railties/lib/rails/version.rb2
-rw-r--r--railties/lib/rails_generator/commands.rb25
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb3
-rw-r--r--railties/lib/tasks/databases.rake4
-rw-r--r--railties/test/generators/generator_test_helper.rb34
-rw-r--r--railties/test/generators/rails_controller_generator_test.rb20
84 files changed, 733 insertions, 483 deletions
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG
index 15c9964d9b..b2ce462f0c 100644
--- a/actionmailer/CHANGELOG
+++ b/actionmailer/CHANGELOG
@@ -1,4 +1,4 @@
-*SVN*
+*2.1.0 RC1 (May 11th, 2008)*
* Fixed that a return-path header would be ignored #7572 [joost]
diff --git a/actionmailer/MIT-LICENSE b/actionmailer/MIT-LICENSE
index 007cc942e1..13c90d46e9 100644
--- a/actionmailer/MIT-LICENSE
+++ b/actionmailer/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2007 David Heinemeier Hansson
+Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/actionmailer/Rakefile b/actionmailer/Rakefile
index 75c3eb2db9..22ed396417 100755
--- a/actionmailer/Rakefile
+++ b/actionmailer/Rakefile
@@ -55,7 +55,7 @@ spec = Gem::Specification.new do |s|
s.rubyforge_project = "actionmailer"
s.homepage = "http://www.rubyonrails.org"
- s.add_dependency('actionpack', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.0.991' + PKG_BUILD)
s.has_rdoc = true
s.requirements << 'none'
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index ec803f5a8e..2e324d4637 100755
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2004-2007 David Heinemeier Hansson
+# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 908bd1c5f2..7ed133d099 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -11,11 +11,11 @@ module ActionMailer #:nodoc:
# = Mailer Models
#
# To use ActionMailer, you need to create a mailer model.
- #
+ #
# $ script/generate mailer Notifier
#
- # The generated model inherits from ActionMailer::Base. Emails are defined by creating methods within the model which are then
- # used to set variables to be used in the mail template, to change options on the mail, or
+ # The generated model inherits from ActionMailer::Base. Emails are defined by creating methods within the model which are then
+ # used to set variables to be used in the mail template, to change options on the mail, or
# to add attachments.
#
# Examples:
@@ -48,7 +48,7 @@ module ActionMailer #:nodoc:
# named after each key in the hash containing the value that that key points to.
#
# So, for example, <tt>body :account => recipient</tt> would result
- # in an instance variable <tt>@account</tt> with the value of <tt>recipient</tt> being accessible in the
+ # in an instance variable <tt>@account</tt> with the value of <tt>recipient</tt> being accessible in the
# view.
#
#
@@ -57,7 +57,7 @@ module ActionMailer #:nodoc:
# Like ActionController, each mailer class has a corresponding view directory
# in which each method of the class looks for a template with its name.
# To define a template to be used with a mailing, create an <tt>.erb</tt> file with the same name as the method
- # in your mailer model. For example, in the mailer defined above, the template at
+ # in your mailer model. For example, in the mailer defined above, the template at
# <tt>app/views/notifier/signup_notification.erb</tt> would be used to generate the email.
#
# Variables defined in the model are accessible as instance variables in the view.
@@ -71,48 +71,48 @@ module ActionMailer #:nodoc:
#
# You got a new note!
# <%= truncate(note.body, 25) %>
- #
+ #
#
# = Generating URLs
- #
+ #
# URLs can be generated in mailer views using <tt>url_for</tt> or named routes.
- # Unlike controllers from Action Pack, the mailer instance doesn't have any context about the incoming request,
- # so you'll need to provide all of the details needed to generate a URL.
+ # Unlike controllers from Action Pack, the mailer instance doesn't have any context about the incoming request,
+ # so you'll need to provide all of the details needed to generate a URL.
#
# When using <tt>url_for</tt> you'll need to provide the <tt>:host</tt>, <tt>:controller</tt>, and <tt>:action</tt>:
- #
+ #
# <%= url_for(:host => "example.com", :controller => "welcome", :action => "greeting") %>
#
# When using named routes you only need to supply the <tt>:host</tt>:
- #
+ #
# <%= users_url(:host => "example.com") %>
#
# You will want to avoid using the <tt>name_of_route_path</tt> form of named routes because it doesn't make sense to
# generate relative URLs in email messages.
#
- # It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt> option in
+ # It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt> option in
# the <tt>ActionMailer::Base.default_url_options</tt> hash as follows:
#
# ActionMailer::Base.default_url_options[:host] = "example.com"
- #
+ #
# This can also be set as a configuration option in <tt>config/environment.rb</tt>:
#
# config.action_mailer.default_url_options = { :host => "example.com" }
#
# If you do decide to set a default <tt>:host</tt> for your mailers you will want to use the
# <tt>:only_path => false</tt> option when using <tt>url_for</tt>. This will ensure that absolute URLs are generated because
- # the <tt>url_for</tt> view helper will, by default, generate relative URLs when a <tt>:host</tt> option isn't
+ # the <tt>url_for</tt> view helper will, by default, generate relative URLs when a <tt>:host</tt> option isn't
# explicitly provided.
#
# = Sending mail
#
- # Once a mailer action and template are defined, you can deliver your message or create it and save it
+ # Once a mailer action and template are defined, you can deliver your message or create it and save it
# for delivery later:
#
# Notifier.deliver_signup_notification(david) # sends the email
# mail = Notifier.create_signup_notification(david) # => a tmail object
# Notifier.deliver(mail)
- #
+ #
# You never instantiate your mailer class. Rather, your delivery instance
# methods are automatically wrapped in class methods that start with the word
# <tt>deliver_</tt> followed by the name of the mailer method that you would
@@ -133,7 +133,7 @@ module ActionMailer #:nodoc:
# body :account => recipient
# content_type "text/html"
# end
- # end
+ # end
#
#
# = Multipart email
@@ -156,17 +156,17 @@ module ActionMailer #:nodoc:
# end
# end
# end
- #
+ #
# Multipart messages can also be used implicitly because ActionMailer will automatically
# detect and use multipart templates, where each template is named after the name of the action, followed
# by the content type. Each such detected template will be added as separate part to the message.
- #
+ #
# For example, if the following templates existed:
# * signup_notification.text.plain.erb
# * signup_notification.text.html.erb
# * signup_notification.text.xml.builder
# * signup_notification.text.x-yaml.erb
- #
+ #
# Each would be rendered and added as a separate part to the message,
# with the corresponding content type. The content type for the entire
# message is automatically set to <tt>multipart/alternative</tt>, which indicates
@@ -197,7 +197,7 @@ module ActionMailer #:nodoc:
# a.body = generate_your_pdf_here()
# end
# end
- # end
+ # end
#
#
# = Configuration options
@@ -255,16 +255,16 @@ module ActionMailer #:nodoc:
cattr_accessor :template_extensions
@@template_extensions = ['erb', 'builder', 'rhtml', 'rxml']
- @@smtp_settings = {
- :address => "localhost",
- :port => 25,
- :domain => 'localhost.localdomain',
- :user_name => nil,
- :password => nil,
+ @@smtp_settings = {
+ :address => "localhost",
+ :port => 25,
+ :domain => 'localhost.localdomain',
+ :user_name => nil,
+ :password => nil,
:authentication => nil
}
cattr_accessor :smtp_settings
-
+
@@sendmail_settings = {
:location => '/usr/sbin/sendmail',
:arguments => '-i -t'
@@ -276,10 +276,10 @@ module ActionMailer #:nodoc:
superclass_delegating_accessor :delivery_method
self.delivery_method = :smtp
-
+
@@perform_deliveries = true
cattr_accessor :perform_deliveries
-
+
@@deliveries = []
cattr_accessor :deliveries
@@ -288,7 +288,7 @@ module ActionMailer #:nodoc:
@@default_content_type = "text/plain"
cattr_accessor :default_content_type
-
+
@@default_mime_version = "1.0"
cattr_accessor :default_mime_version
@@ -297,47 +297,47 @@ module ActionMailer #:nodoc:
# Specify the BCC addresses for the message
adv_attr_accessor :bcc
-
+
# Define the body of the message. This is either a Hash (in which case it
# specifies the variables to pass to the template when it is rendered),
# or a string, in which case it specifies the actual text of the message.
adv_attr_accessor :body
-
+
# Specify the CC addresses for the message.
adv_attr_accessor :cc
-
+
# Specify the charset to use for the message. This defaults to the
# +default_charset+ specified for ActionMailer::Base.
adv_attr_accessor :charset
-
+
# Specify the content type for the message. This defaults to <tt>text/plain</tt>
# in most cases, but can be automatically set in some situations.
adv_attr_accessor :content_type
-
+
# Specify the from address for the message.
adv_attr_accessor :from
-
+
# Specify additional headers to be added to the message.
adv_attr_accessor :headers
-
+
# Specify the order in which parts should be sorted, based on content-type.
# This defaults to the value for the +default_implicit_parts_order+.
adv_attr_accessor :implicit_parts_order
-
+
# Defaults to "1.0", but may be explicitly given if needed.
adv_attr_accessor :mime_version
-
+
# The recipient addresses for the message, either as a string (for a single
# address) or an array (for multiple addresses).
adv_attr_accessor :recipients
-
+
# The date on which the message was sent. If not set (the default), the
# header will be set by the delivery agent.
adv_attr_accessor :sent_on
-
+
# Specify the subject of the message.
adv_attr_accessor :subject
-
+
# Specify the template name to use for current message. This is the "base"
# template name, without the extension or directory, and may be used to
# have multiple mailer methods share the same template.
@@ -353,7 +353,7 @@ module ActionMailer #:nodoc:
self.class.mailer_name
end
end
-
+
def mailer_name=(value)
self.class.mailer_name = value
end
@@ -431,7 +431,7 @@ module ActionMailer #:nodoc:
# remain uninitialized (useful when you only need to invoke the "receive"
# method, for instance).
def initialize(method_name=nil, *parameters) #:nodoc:
- create!(method_name, *parameters) if method_name
+ create!(method_name, *parameters) if method_name
end
# Initialize the mailer via the given +method_name+. The body will be
@@ -517,7 +517,7 @@ module ActionMailer #:nodoc:
@content_type ||= @@default_content_type.dup
@implicit_parts_order ||= @@default_implicit_parts_order.dup
@template ||= method_name
- @mailer_name ||= Inflector.underscore(self.class.name)
+ @mailer_name ||= self.class.name.underscore
@parts ||= []
@headers ||= {}
@body ||= {}
@@ -603,7 +603,7 @@ module ActionMailer #:nodoc:
part = (TMail::Mail === p ? p : p.to_mail(self))
m.parts << part
end
-
+
if real_content_type =~ /multipart/
ctype_attrs.delete "charset"
m.set_content_type(real_content_type, nil, ctype_attrs)
@@ -618,7 +618,7 @@ module ActionMailer #:nodoc:
mail.ready_to_send
sender = mail['return-path'] || mail.from
- Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain],
+ Net::SMTP.start(smtp_settings[:address], smtp_settings[:port], smtp_settings[:domain],
smtp_settings[:user_name], smtp_settings[:password], smtp_settings[:authentication]) do |smtp|
smtp.sendmail(mail.encoded, sender, destinations)
end
diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb
index 954a472757..88b9a3c200 100644
--- a/actionmailer/lib/action_mailer/version.rb
+++ b/actionmailer/lib/action_mailer/version.rb
@@ -2,7 +2,7 @@ module ActionMailer
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
- TINY = 2
+ TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 2caaa40bf6..4a24d2f8b9 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,9 +1,10 @@
-*SVN*
+*2.1.0 RC1 (May 11th, 2008)*
* Fixed that forgery protection can be used without session tracking (Peter Jones) [#139]
* Added session(:on) to turn session management back on in a controller subclass if the superclass turned it off (Peter Jones) [#136]
+* Change the request forgery protection to go by Content-Type instead of request.format so that you can't bypass it by POSTing to "#{request.uri}.xml" [rick]
* InstanceTag#default_time_from_options with hash args uses Time.current as default; respects hash settings when time falls in system local spring DST gap [Geoff Buesing]
* select_date defaults to Time.zone.today when config.time_zone is set [Geoff Buesing]
diff --git a/actionpack/MIT-LICENSE b/actionpack/MIT-LICENSE
index 007cc942e1..13c90d46e9 100644
--- a/actionpack/MIT-LICENSE
+++ b/actionpack/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2007 David Heinemeier Hansson
+Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/actionpack/Rakefile b/actionpack/Rakefile
index e460d820ba..0147a5c1e8 100644
--- a/actionpack/Rakefile
+++ b/actionpack/Rakefile
@@ -76,7 +76,7 @@ spec = Gem::Specification.new do |s|
s.has_rdoc = true
s.requirements << 'none'
- s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'action_controller'
diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb
index 919fbc6c6a..810a5fb9b5 100755
--- a/actionpack/lib/action_controller.rb
+++ b/actionpack/lib/action_controller.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2004-2007 David Heinemeier Hansson
+# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index e1bf005f39..ea55fe42ce 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -259,12 +259,12 @@ module ActionController #:nodoc:
DEFAULT_RENDER_STATUS_CODE = "200 OK"
include StatusCodes
-
+
# Controller specific instance variables which will not be accessible inside views.
@@protected_view_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller
@action_name @before_filter_chain_aborted @action_cache_path @_session @_cookies @_headers @_params
@_flash @_response)
-
+
# Prepends all the URL-generating helpers from AssetHelper. This makes it possible to easily move javascripts, stylesheets,
# and images to a dedicated asset server away from the main web server. Example:
# ActionController::Base.asset_host = "http://assets.example.com"
@@ -325,7 +325,7 @@ module ActionController #:nodoc:
# Controls the default charset for all renders.
@@default_charset = "utf-8"
cattr_accessor :default_charset
-
+
# The logger is used for generating information on the action run-time (including benchmarking) if available.
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
cattr_accessor :logger
@@ -333,7 +333,7 @@ module ActionController #:nodoc:
# Controls the resource action separator
@@resource_action_separator = "/"
cattr_accessor :resource_action_separator
-
+
# Allow to override path names for default resources' actions
@@resources_path_names = { :new => 'new', :edit => 'edit' }
cattr_accessor :resources_path_names
@@ -433,7 +433,7 @@ module ActionController #:nodoc:
end
# Adds a view_path to the front of the view_paths array.
- # If the current class has no view paths, copy them from
+ # If the current class has no view paths, copy them from
# the superclass. This change will be visible for all future requests.
#
# ArticleController.prepend_view_path("views/default")
@@ -444,9 +444,9 @@ module ActionController #:nodoc:
view_paths.unshift(*path)
ActionView::TemplateFinder.process_view_paths(path)
end
-
+
# Adds a view_path to the end of the view_paths array.
- # If the current class has no view paths, copy them from
+ # If the current class has no view paths, copy them from
# the superclass. This change will be visible for all future requests.
#
# ArticleController.append_view_path("views/default")
@@ -457,7 +457,7 @@ module ActionController #:nodoc:
view_paths.push(*path)
ActionView::TemplateFinder.process_view_paths(path)
end
-
+
# Replace sensitive parameter data from the request log.
# Filters parameters that have any of the arguments as a substring.
# Looks in all subhashes of the param hash for keys to filter.
@@ -504,6 +504,7 @@ module ActionController #:nodoc:
filtered_parameters
end
+ protected :filter_parameters
end
# Don't render layouts for templates with the given extensions.
@@ -643,12 +644,12 @@ module ActionController #:nodoc:
end
self.view_paths = []
-
+
# View load paths for controller.
def view_paths
@template.finder.view_paths
end
-
+
def view_paths=(value)
@template.finder.view_paths = value # Mutex needed
end
@@ -662,7 +663,7 @@ module ActionController #:nodoc:
def prepend_view_path(path)
@template.finder.prepend_view_path(path) # Mutex needed
end
-
+
# Adds a view_path to the end of the view_paths array.
# This change affects the current request only.
#
@@ -874,10 +875,10 @@ module ActionController #:nodoc:
elsif action_name = options[:action]
template = default_template_name(action_name.to_s)
if options[:layout] && !template_exempt_from_layout?(template)
- render_with_a_layout(:file => template, :status => options[:status], :use_full_path => true, :layout => true)
+ render_with_a_layout(:file => template, :status => options[:status], :use_full_path => true, :layout => true)
else
render_with_no_layout(:file => template, :status => options[:status], :use_full_path => true)
- end
+ end
elsif xml = options[:xml]
response.content_type ||= Mime::XML
@@ -895,12 +896,12 @@ module ActionController #:nodoc:
if collection = options[:collection]
render_for_text(
- @template.send!(:render_partial_collection, partial, collection,
+ @template.send!(:render_partial_collection, partial, collection,
options[:spacer_template], options[:locals]), options[:status]
)
else
render_for_text(
- @template.send!(:render_partial, partial,
+ @template.send!(:render_partial, partial,
ActionView::Base::ObjectWrapper.new(options[:object]), options[:locals]), options[:status]
)
end
@@ -1024,7 +1025,7 @@ module ActionController #:nodoc:
# redirect_to articles_url
# redirect_to :back
#
- # The redirection happens as a "302 Moved" header unless otherwise specified.
+ # The redirection happens as a "302 Moved" header unless otherwise specified.
#
# Examples:
# redirect_to post_url(@post), :status=>:found
@@ -1035,17 +1036,17 @@ module ActionController #:nodoc:
# When using <tt>redirect_to :back</tt>, if there is no referrer,
# RedirectBackError will be raised. You may specify some fallback
# behavior for this case by rescuing RedirectBackError.
- def redirect_to(options = {}, response_status = {}) #:doc:
+ def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
- if options.is_a?(Hash) && options[:status]
- status = options.delete(:status)
- elsif response_status[:status]
- status = response_status[:status]
- else
- status = 302
+ if options.is_a?(Hash) && options[:status]
+ status = options.delete(:status)
+ elsif response_status[:status]
+ status = response_status[:status]
+ else
+ status = 302
end
-
+
case options
when %r{^\w+://.*}
raise DoubleRenderError if performed?
@@ -1119,7 +1120,7 @@ module ActionController #:nodoc:
response.body = text.is_a?(Proc) ? text : text.to_s
end
end
-
+
def initialize_template_class(response)
response.template = ActionView::Base.new(self.class.view_paths, {}, self)
response.template.extend self.class.master_helper_module
diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb
index 7b0551c664..1ef9e60a21 100644
--- a/actionpack/lib/action_controller/caching/actions.rb
+++ b/actionpack/lib/action_controller/caching/actions.rb
@@ -9,7 +9,7 @@ module ActionController #:nodoc:
# class ListsController < ApplicationController
# before_filter :authenticate, :except => :public
# caches_page :public
- # caches_action :show, :feed
+ # caches_action :index, :show, :feed
# end
#
# In this example, the public action doesn't require authentication, so it's possible to use the faster page caching method. But both the
@@ -27,15 +27,19 @@ module ActionController #:nodoc:
# You can set modify the default action cache path by passing a :cache_path option. This will be passed directly to ActionCachePath.path_for. This is handy
# for actions with multiple possible routes that should be cached differently. If a block is given, it is called with the current controller instance.
#
+ # And you can also use :if to pass a Proc that specifies when the action should be cached.
+ #
# class ListsController < ApplicationController
# before_filter :authenticate, :except => :public
# caches_page :public
+ # caches_action :index, :if => Proc.new { |c| !c.request.format.json? } # cache if is not a JSON request
# caches_action :show, :cache_path => { :project => 1 }
- # caches_action :show, :cache_path => Proc.new { |controller|
- # controller.params[:user_id] ?
+ # caches_action :feed, :cache_path => Proc.new { |controller|
+ # controller.params[:user_id] ?
# controller.send(:user_list_url, c.params[:user_id], c.params[:id]) :
# controller.send(:list_url, c.params[:id]) }
# end
+ #
module Actions
def self.included(base) #:nodoc:
base.extend(ClassMethods)
@@ -49,7 +53,8 @@ module ActionController #:nodoc:
# See ActionController::Caching::Actions for details.
def caches_action(*actions)
return unless cache_configured?
- around_filter(ActionCacheFilter.new(*actions))
+ options = actions.extract_options!
+ around_filter(ActionCacheFilter.new(:cache_path => options.delete(:cache_path)), {:only => actions}.merge(options))
end
end
@@ -67,16 +72,12 @@ module ActionController #:nodoc:
end
class ActionCacheFilter #:nodoc:
- def initialize(*actions, &block)
- @options = actions.extract_options!
- @actions = Set.new(actions)
+ def initialize(options, &block)
+ @options = options
end
def before(controller)
- return unless @actions.include?(controller.action_name.intern)
-
cache_path = ActionCachePath.new(controller, path_options_for(controller, @options))
-
if cache = controller.read_fragment(cache_path.path)
controller.rendered_action_cache = true
set_content_type!(controller, cache_path.extension)
@@ -88,7 +89,7 @@ module ActionController #:nodoc:
end
def after(controller)
- return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache || !caching_allowed(controller)
+ return if controller.rendered_action_cache || !caching_allowed(controller)
controller.write_fragment(controller.action_cache_path.path, controller.response.body)
end
@@ -105,16 +106,16 @@ module ActionController #:nodoc:
controller.request.get? && controller.response.headers['Status'].to_i == 200
end
end
-
+
class ActionCachePath
attr_reader :path, :extension
-
+
class << self
def path_for(controller, options)
new(controller, options).path
end
end
-
+
def initialize(controller, options = {})
@extension = extract_extension(controller.request.path)
path = controller.url_for(options).split('://').last
@@ -122,16 +123,16 @@ module ActionController #:nodoc:
add_extension!(path, @extension)
@path = URI.unescape(path)
end
-
+
private
def normalize!(path)
path << 'index' if path[-1] == ?/
end
-
+
def add_extension!(path, extension)
path << ".#{extension}" if extension
end
-
+
def extract_extension(file_path)
# Don't want just what comes after the last '.' to accommodate multi part extensions
# such as tar.gz.
@@ -140,4 +141,4 @@ module ActionController #:nodoc:
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb
index 3164e14f6f..61559e9ec7 100644
--- a/actionpack/lib/action_controller/caching/sweeping.rb
+++ b/actionpack/lib/action_controller/caching/sweeping.rb
@@ -28,7 +28,7 @@ module ActionController #:nodoc:
# class ListsController < ApplicationController
# caches_action :index, :show, :public, :feed
# cache_sweeper OpenBar::Sweeper, :only => [ :edit, :destroy, :share ]
- # end
+ # end
module Sweeping
def self.included(base) #:nodoc:
base.extend(ClassMethods)
@@ -40,7 +40,7 @@ module ActionController #:nodoc:
sweepers.each do |sweeper|
ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base)
- sweeper_instance = (sweeper.is_a?(Symbol) ? Object.const_get(Inflector.classify(sweeper)) : sweeper).instance
+ sweeper_instance = (sweeper.is_a?(Symbol) ? Object.const_get(sweeper.to_s.classify) : sweeper).instance
if sweeper_instance.is_a?(Sweeper)
around_filter(sweeper_instance, :only => configuration[:only])
@@ -94,4 +94,4 @@ module ActionController #:nodoc:
end
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_controller/cgi_ext/cookie.rb b/actionpack/lib/action_controller/cgi_ext/cookie.rb
index 3dd374f126..a244e2a39a 100644
--- a/actionpack/lib/action_controller/cgi_ext/cookie.rb
+++ b/actionpack/lib/action_controller/cgi_ext/cookie.rb
@@ -37,7 +37,7 @@ class CGI #:nodoc:
@path = nil
else
@name = name['name']
- @value = Array(name['value'])
+ @value = (name['value'].kind_of?(String) ? [name['value']] : Array(name['value'])).delete_if(&:blank?)
@domain = name['domain']
@expires = name['expires']
@secure = name['secure'] || false
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index 8c02f20521..f43e2ba06d 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -17,6 +17,10 @@ module Mime
# end
# end
class Type
+ @@html_types = Set.new [:html, :all]
+ @@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
+ cattr_reader :html_types, :unverifiable_types
+
# A simple helper class used in parsing the accept header
class AcceptItem #:nodoc:
attr_accessor :order, :name, :q
@@ -153,12 +157,21 @@ module Mime
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
end
end
-
+
+ # Returns true if ActionPack should check requests using this Mime Type for possible request forgery. See
+ # ActionController::RequestForgerProtection.
+ def verify_request?
+ !@@unverifiable_types.include?(to_sym)
+ end
+
+ def html?
+ @@html_types.include?(to_sym) || @string =~ /html/
+ end
+
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
- mime_type = $1.downcase.to_sym
- mime_type == @symbol || (mime_type == :html && @symbol == :all)
+ $1.downcase.to_sym == to_sym
else
super
end
diff --git a/actionpack/lib/action_controller/mime_types.rb b/actionpack/lib/action_controller/mime_types.rb
index 71706b4c41..01a266d3fe 100644
--- a/actionpack/lib/action_controller/mime_types.rb
+++ b/actionpack/lib/action_controller/mime_types.rb
@@ -17,4 +17,4 @@ Mime::Type.register "multipart/form-data", :multipart_form
Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
# http://www.ietf.org/rfc/rfc4627.txt
-Mime::Type.register "application/json", :json, %w( text/x-json )
+Mime::Type.register "application/json", :json, %w( text/x-json ) \ No newline at end of file
diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb
index 139e91ecf9..02c9d59d07 100644
--- a/actionpack/lib/action_controller/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/request_forgery_protection.rb
@@ -99,7 +99,7 @@ module ActionController #:nodoc:
end
def verifiable_request_format?
- request.format.html? || request.format.js?
+ request.content_type.nil? || request.content_type.verify_request?
end
# Sets the token value for the current session. Pass a <tt>:secret</tt> option
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb
index 5022c9a815..40ef4ea044 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/rescue.rb
@@ -199,10 +199,8 @@ module ActionController #:nodoc:
private
def perform_action_with_rescue #:nodoc:
perform_action_without_rescue
- rescue Exception => exception # errors from action performed
- return if rescue_action_with_handler(exception)
-
- rescue_action(exception)
+ rescue Exception => exception
+ rescue_action_with_handler(exception) || rescue_action(exception)
end
def rescues_path(template_name)
diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_controller/session/cookie_store.rb
index 560491f996..ada1862c3e 100644
--- a/actionpack/lib/action_controller/session/cookie_store.rb
+++ b/actionpack/lib/action_controller/session/cookie_store.rb
@@ -130,17 +130,20 @@ class CGI::Session::CookieStore
# Marshal a session hash into safe cookie data. Include an integrity hash.
def marshal(session)
data = ActiveSupport::Base64.encode64(Marshal.dump(session)).chop
- CGI.escape "#{data}--#{generate_digest(data)}"
+ "#{data}--#{generate_digest(data)}"
end
# Unmarshal cookie data to a hash and verify its integrity.
def unmarshal(cookie)
if cookie
- data, digest = CGI.unescape(cookie).split('--')
- unless digest == generate_digest(data)
+ data, digest = cookie.split('--')
+
+ # Do two checks to transparently support old double-escaped data.
+ unless digest == generate_digest(data) || digest == generate_digest(data = CGI.unescape(data))
delete
raise TamperedWithCookie
end
+
Marshal.load(ActiveSupport::Base64.decode64(data))
end
end
diff --git a/actionpack/lib/action_pack.rb b/actionpack/lib/action_pack.rb
index 006c83dbc8..c7fd3092e7 100644
--- a/actionpack/lib/action_pack.rb
+++ b/actionpack/lib/action_pack.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2004-2007 David Heinemeier Hansson
+# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/actionpack/lib/action_pack/version.rb b/actionpack/lib/action_pack/version.rb
index 7aa6a5db96..70fc1ced8c 100644
--- a/actionpack/lib/action_pack/version.rb
+++ b/actionpack/lib/action_pack/version.rb
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
- TINY = 2
+ TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index 609334d52d..5f4126e4e9 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2004-2007 David Heinemeier Hansson
+# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/actionpack/lib/action_view/helpers/javascripts/controls.js b/actionpack/lib/action_view/helpers/javascripts/controls.js
index fbc4418b83..5aaf0bb2b7 100644
--- a/actionpack/lib/action_view/helpers/javascripts/controls.js
+++ b/actionpack/lib/action_view/helpers/javascripts/controls.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:
diff --git a/actionpack/lib/action_view/helpers/javascripts/dragdrop.js b/actionpack/lib/action_view/helpers/javascripts/dragdrop.js
index ccf4a1e45c..bf5cfea66c 100644
--- a/actionpack/lib/action_view/helpers/javascripts/dragdrop.js
+++ b/actionpack/lib/action_view/helpers/javascripts/dragdrop.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
diff --git a/actionpack/lib/action_view/helpers/javascripts/effects.js b/actionpack/lib/action_view/helpers/javascripts/effects.js
index 65aed23957..f030b5dbe9 100644
--- a/actionpack/lib/action_view/helpers/javascripts/effects.js
+++ b/actionpack/lib/action_view/helpers/javascripts/effects.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 1b12aa8058..1a0e660d52 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -458,7 +458,7 @@ module ActionView
url_options = options[:url]
url_options = url_options.merge(:escape => false) if url_options.is_a?(Hash)
- function << "'#{url_for(url_options)}'"
+ function << "'#{escape_javascript(url_for(url_options))}'"
function << ", #{javascript_options})"
function = "#{options[:before]}; #{function}" if options[:before]
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index f8c3b67474..9d220c546a 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -3,19 +3,19 @@ require 'html/document'
module ActionView
module Helpers #:nodoc:
- # The TextHelper module provides a set of methods for filtering, formatting
- # and transforming strings, which can reduce the amount of inline Ruby code in
- # your views. These helper methods extend ActionView making them callable
+ # The TextHelper module provides a set of methods for filtering, formatting
+ # and transforming strings, which can reduce the amount of inline Ruby code in
+ # your views. These helper methods extend ActionView making them callable
# within your template files.
- module TextHelper
- # The preferred method of outputting text in your views is to use the
- # <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods
- # do not operate as expected in an eRuby code block. If you absolutely must
+ module TextHelper
+ # The preferred method of outputting text in your views is to use the
+ # <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods
+ # do not operate as expected in an eRuby code block. If you absolutely must
# output text within a non-output code block (i.e., <% %>), you can use the concat method.
#
# ==== Examples
- # <%
- # concat "hello", binding
+ # <%
+ # concat "hello", binding
# # is the equivalent of <%= "hello" %>
#
# if (logged_in == true):
@@ -30,15 +30,15 @@ module ActionView
end
if RUBY_VERSION < '1.9'
- # If +text+ is longer than +length+, +text+ will be truncated to the length of
+ # If +text+ is longer than +length+, +text+ will be truncated to the length of
# +length+ (defaults to 30) and the last characters will be replaced with the +truncate_string+
# (defaults to "...").
#
# ==== Examples
- # truncate("Once upon a time in a world far far away", 14)
+ # truncate("Once upon a time in a world far far away", 14)
# # => Once upon a...
#
- # truncate("Once upon a time in a world far far away")
+ # truncate("Once upon a time in a world far far away")
# # => Once upon a time in a world f...
#
# truncate("And they found that many people were sleeping better.", 25, "(clipped)")
@@ -63,20 +63,20 @@ module ActionView
end
# Highlights one or more +phrases+ everywhere in +text+ by inserting it into
- # a +highlighter+ string. The highlighter can be specialized by passing +highlighter+
+ # a +highlighter+ string. The highlighter can be specialized by passing +highlighter+
# as a single-quoted string with \1 where the phrase is to be inserted (defaults to
# '<strong class="highlight">\1</strong>')
#
# ==== Examples
- # highlight('You searched for: rails', 'rails')
+ # highlight('You searched for: rails', 'rails')
# # => You searched for: <strong class="highlight">rails</strong>
#
# highlight('You searched for: ruby, rails, dhh', 'actionpack')
- # # => You searched for: ruby, rails, dhh
+ # # => You searched for: ruby, rails, dhh
#
- # highlight('You searched for: rails', ['for', 'rails'], '<em>\1</em>')
+ # highlight('You searched for: rails', ['for', 'rails'], '<em>\1</em>')
# # => You searched <em>for</em>: <em>rails</em>
- #
+ #
# highlight('You searched for: rails', 'rails', "<a href='search?q=\1'>\1</a>")
# # => You searched for: <a href='search?q=rails>rails</a>
def highlight(text, phrases, highlighter = '<strong class="highlight">\1</strong>')
@@ -89,23 +89,23 @@ module ActionView
end
if RUBY_VERSION < '1.9'
- # Extracts an excerpt from +text+ that matches the first instance of +phrase+.
+ # Extracts an excerpt from +text+ that matches the first instance of +phrase+.
# The +radius+ expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
# defined in +radius+ (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
# then the +excerpt_string+ will be prepended/appended accordingly. The resulting string will be stripped in any case.
# If the +phrase+ isn't found, nil is returned.
#
# ==== Examples
- # excerpt('This is an example', 'an', 5)
+ # excerpt('This is an example', 'an', 5)
# # => "...s is an exam..."
#
- # excerpt('This is an example', 'is', 5)
+ # excerpt('This is an example', 'is', 5)
# # => "This is a..."
#
- # excerpt('This is an example', 'is')
+ # excerpt('This is an example', 'is')
# # => "This is an example"
#
- # excerpt('This next thing is an example', 'ex', 2)
+ # excerpt('This next thing is an example', 'ex', 2)
# # => "...next..."
#
# excerpt('This is also an example', 'an', 8, '<chop> ')
@@ -147,33 +147,24 @@ module ActionView
end
end
- # Attempts to pluralize the +singular+ word unless +count+ is 1. If +plural+
- # is supplied, it will use that when count is > 1, if the ActiveSupport Inflector
- # is loaded, it will use the Inflector to determine the plural form, otherwise
- # it will just add an 's' to the +singular+ word.
+ # Attempts to pluralize the +singular+ word unless +count+ is 1. If
+ # +plural+ is supplied, it will use that when count is > 1, otherwise
+ # it will use the Inflector to determine the plural form
#
# ==== Examples
- # pluralize(1, 'person')
+ # pluralize(1, 'person')
# # => 1 person
#
- # pluralize(2, 'person')
+ # pluralize(2, 'person')
# # => 2 people
#
- # pluralize(3, 'person', 'users')
+ # pluralize(3, 'person', 'users')
# # => 3 users
#
# pluralize(0, 'person')
# # => 0 people
def pluralize(count, singular, plural = nil)
- "#{count || 0} " + if count == 1 || count == '1'
- singular
- elsif plural
- plural
- elsif Object.const_defined?("Inflector")
- Inflector.pluralize(singular)
- else
- singular + "s"
- end
+ "#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
end
# Wraps the +text+ into lines no longer than +line_width+ width. This method
@@ -229,7 +220,7 @@ module ActionView
end
end
- # Returns the text with all the Textile codes turned into HTML tags,
+ # Returns the text with all the Textile codes turned into HTML tags,
# but without the bounding <p> tag that RedCloth adds.
#
# You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
@@ -273,25 +264,25 @@ module ActionView
# # => "<p>We like to <em>write</em> <code>code</code>, not just <em>read</em> it!</p>"
#
# markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.")
- # # => "<p>The <a href="http://daringfireball.net/projects/markdown/">Markdown website</a>
+ # # => "<p>The <a href="http://daringfireball.net/projects/markdown/">Markdown website</a>
# # has more information.</p>"
#
# markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
- # # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
+ # # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
def markdown(text)
text.blank? ? "" : BlueCloth.new(text).to_html
end
rescue LoadError
# We can't really help what's not there
end
-
+
# Returns +text+ transformed into HTML using simple formatting rules.
- # Two or more consecutive newlines(<tt>\n\n</tt>) are considered as a
+ # Two or more consecutive newlines(<tt>\n\n</tt>) are considered as a
# paragraph and wrapped in <tt><p></tt> tags. One newline (<tt>\n</tt>) is
# considered as a linebreak and a <tt><br /></tt> tag is appended. This
- # method does not remove the newlines from the +text+.
+ # method does not remove the newlines from the +text+.
#
- # You can pass any HTML attributes into <tt>html_options</tt>. These
+ # You can pass any HTML attributes into <tt>html_options</tt>. These
# will be added to all created paragraphs.
# ==== Examples
# my_text = "Here is some basic text...\n...with a line break."
@@ -316,19 +307,19 @@ module ActionView
text << "</p>"
end
- # Turns all URLs and e-mail addresses into clickable links. The +link+ parameter
+ # Turns all URLs and e-mail addresses into clickable links. The +link+ parameter
# will limit what should be linked. You can add HTML attributes to the links using
- # +href_options+. Options for +link+ are <tt>:all</tt> (default),
- # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
+ # +href_options+. Options for +link+ are <tt>:all</tt> (default),
+ # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
# e-mail address is yielded and the result is used as the link text.
#
# ==== Examples
- # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
+ # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
# # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
# # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
#
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :urls)
- # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
+ # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
# # or e-mail david@loudthinking.com"
#
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :email_addresses)
@@ -338,9 +329,9 @@ module ActionView
# auto_link(post_body, :all, :target => '_blank') do |text|
# truncate(text, 15)
# end
- # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
- #
+ #
def auto_link(text, link = :all, href_options = {}, &block)
return '' if text.blank?
case link
@@ -349,15 +340,15 @@ module ActionView
when :urls then auto_link_urls(text, href_options, &block)
end
end
-
+
# Creates a Cycle object whose _to_s_ method cycles through elements of an
- # array every time it is called. This can be used for example, to alternate
- # classes for table rows. You can use named cycles to allow nesting in loops.
- # Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
- # named cycle. You can manually reset a cycle by calling reset_cycle and passing the
+ # array every time it is called. This can be used for example, to alternate
+ # classes for table rows. You can use named cycles to allow nesting in loops.
+ # Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
+ # named cycle. You can manually reset a cycle by calling reset_cycle and passing the
# name of the cycle.
#
- # ==== Examples
+ # ==== Examples
# # Alternate CSS classes for even and odd numbers...
# @items = [1,2,3,4]
# <table>
@@ -370,8 +361,8 @@ module ActionView
#
#
# # Cycle CSS classes for rows, and text colors for values within each row
- # @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'},
- # {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
+ # @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'},
+ # {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
# {:first => 'June', :middle => 'Dae', :last => 'Jones'}]
# <% @items.each do |item| %>
# <tr class="<%= cycle("even", "odd", :name => "row_class") -%>">
@@ -401,8 +392,8 @@ module ActionView
end
return cycle.to_s
end
-
- # Resets a cycle so that it starts from the first element the next time
+
+ # Resets a cycle so that it starts from the first element the next time
# it is called. Pass in +name+ to reset a named cycle.
#
# ==== Example
@@ -428,12 +419,12 @@ module ActionView
class Cycle #:nodoc:
attr_reader :values
-
+
def initialize(first_value, *values)
@values = values.unshift(first_value)
reset
end
-
+
def reset
@index = 0
end
@@ -453,7 +444,7 @@ module ActionView
@_cycles = Hash.new unless defined?(@_cycles)
return @_cycles[name]
end
-
+
def set_cycle(name, cycle_object)
@_cycles = Hash.new unless defined?(@_cycles)
@_cycles[name] = cycle_object
@@ -462,13 +453,13 @@ module ActionView
AUTO_LINK_RE = %r{
( # leading text
<\w+.*?>| # leading HTML tag, or
- [^=!:'"/]| # leading punctuation, or
+ [^=!:'"/]| # leading punctuation, or
^ # beginning of line
)
(
(?:https?://)| # protocol spec, or
(?:www\.) # www.*
- )
+ )
(
[-\w]+ # subdomain or domain
(?:\.[-\w]+)* # remaining subdomains or domain
@@ -502,7 +493,7 @@ module ActionView
body = text.dup
text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
text = $1
-
+
if body.match(/<a\b[^>]*>(.*)(#{Regexp.escape(text)})(.*)<\/a>/)
text
else
diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb
index ddc1c68383..4aacb4a78a 100644
--- a/actionpack/test/controller/caching_test.rb
+++ b/actionpack/test/controller/caching_test.rb
@@ -6,6 +6,7 @@ CACHE_DIR = 'test_cache'
FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
ActionController::Base.page_cache_directory = FILE_STORE_PATH
ActionController::Base.cache_store = :file_store, FILE_STORE_PATH
+ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/' ]
class PageCachingTestController < ActionController::Base
caches_page :ok, :no_content, :if => Proc.new { |c| !c.request.format.json? }
@@ -128,7 +129,7 @@ class PageCachingTest < Test::Unit::TestCase
end
end
end
-
+
def test_page_caching_conditional_options
@request.env['HTTP_ACCEPT'] = 'application/json'
get :ok
@@ -151,12 +152,15 @@ end
class ActionCachingTestController < ActionController::Base
- caches_action :index, :redirected, :forbidden
+ caches_action :index, :redirected, :forbidden, :if => Proc.new { |c| !c.request.format.json? }
caches_action :show, :cache_path => 'http://test.host/custom/show'
caches_action :edit, :cache_path => Proc.new { |c| c.params[:id] ? "http://test.host/#{c.params[:id]};edit" : "http://test.host/edit" }
+ caches_action :with_layout
+
+ layout 'talk_from_action.erb'
def index
- @cache_this = Time.now.to_f.to_s
+ @cache_this = MockTime.now.to_f.to_s
render :text => @cache_this
end
@@ -169,14 +173,26 @@ class ActionCachingTestController < ActionController::Base
headers["Status"] = "403 Forbidden"
end
+ def with_layout
+ @cache_this = MockTime.now.to_f.to_s
+ render :text => @cache_this, :layout => true
+ end
+
alias_method :show, :index
alias_method :edit, :index
+ alias_method :destroy, :index
def expire
expire_action :controller => 'action_caching_test', :action => 'index'
render :nothing => true
end
+end
+class MockTime < Time
+ # Let Time spicy to assure that Time.now != Time.now
+ def to_f
+ super+rand
+ end
end
class ActionCachingMockController
@@ -223,6 +239,36 @@ class ActionCacheTest < Test::Unit::TestCase
assert_equal cached_time, @response.body
end
+ def test_simple_action_not_cached
+ get :destroy
+ cached_time = content_to_cache
+ assert_equal cached_time, @response.body
+ assert_cache_does_not_exist 'hostname.com/action_caching_test/destroy'
+ reset!
+
+ get :destroy
+ assert_not_equal cached_time, @response.body
+ end
+
+ def test_action_cache_with_layout
+ get :with_layout
+ cached_time = content_to_cache
+ assert_not_equal cached_time, @response.body
+ assert_cache_exists 'hostname.com/action_caching_test/with_layout'
+ reset!
+
+ get :with_layout
+ assert_not_equal cached_time, @response.body
+
+ assert_equal @response.body, read_fragment('hostname.com/action_caching_test/with_layout')
+ end
+
+ def test_action_cache_conditional_options
+ @request.env['HTTP_ACCEPT'] = 'application/json'
+ get :index
+ assert_cache_does_not_exist 'hostname.com/action_caching_test'
+ end
+
def test_action_cache_with_custom_cache_path
get :show
cached_time = content_to_cache
@@ -350,9 +396,22 @@ class ActionCacheTest < Test::Unit::TestCase
end
def assert_cache_exists(path)
- full_path = File.join(FILE_STORE_PATH, "views", path + '.cache')
+ full_path = cache_path(path)
assert File.exist?(full_path), "#{full_path.inspect} does not exist."
end
+
+ def assert_cache_does_not_exist(path)
+ full_path = cache_path(path)
+ assert !File.exist?(full_path), "#{full_path.inspect} should not exist."
+ end
+
+ def cache_path(path)
+ File.join(FILE_STORE_PATH, 'views', path + '.cache')
+ end
+
+ def read_fragment(path)
+ @controller.read_fragment(path)
+ end
end
class FragmentCachingTestController < ActionController::Base
@@ -516,7 +575,7 @@ class FunctionalFragmentCachingTest < Test::Unit::TestCase
def setup
ActionController::Base.perform_caching = true
@store = ActiveSupport::Cache::MemoryStore.new
- ActionController::Base.cache_store = @store
+ ActionController::Base.cache_store = @store
@controller = FunctionalCachingController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@@ -529,17 +588,17 @@ Hello
This bit's fragment cached
CACHED
assert_equal expected_body, @response.body
-
+
assert_equal "This bit's fragment cached", @store.read('views/test.host/functional_caching/fragment_cached')
end
-
+
def test_fragment_caching_in_partials
get :html_fragment_cached_with_partial
assert_response :success
assert_match /Fragment caching in a partial/, @response.body
assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/html_fragment_cached_with_partial')
end
-
+
def test_fragment_caching_in_rjs_partials
xhr :get, :js_fragment_cached_with_partial
assert_response :success
@@ -547,8 +606,3 @@ CACHED
assert_match "Fragment caching in a partial", @store.read('views/test.host/functional_caching/js_fragment_cached_with_partial')
end
end
-
-
-
-
-
diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb
index 42f3bd26a4..b45fbb17d3 100644
--- a/actionpack/test/controller/cookie_test.rb
+++ b/actionpack/test/controller/cookie_test.rb
@@ -82,6 +82,7 @@ class CookieTest < Test::Unit::TestCase
def test_expiring_cookie
get :logout
assert_equal [ CGI::Cookie::new("name" => "user_name", "value" => "", "expires" => Time.at(0)) ], @response.headers["cookie"]
+ assert_equal CGI::Cookie::new("name" => "user_name", "value" => "", "expires" => Time.at(0)).value, []
end
def test_cookiejar_accessor
@@ -137,4 +138,9 @@ class CookieTest < Test::Unit::TestCase
cookies = CGI::Cookie.parse('return_to=http://rubyonrails.org/search?term=api&scope=all&global=true')
assert_equal({"return_to" => ["http://rubyonrails.org/search?term=api&scope=all&global=true"]}, cookies)
end
+
+ def test_cookies_should_not_be_split_on_values_with_newlines
+ cookies = CGI::Cookie.new("name" => "val", "value" => "this\nis\na\ntest")
+ assert cookies.size == 1
+ end
end
diff --git a/actionpack/test/controller/filter_params_test.rb b/actionpack/test/controller/filter_params_test.rb
index 11adacb5e3..c4de10181d 100644
--- a/actionpack/test/controller/filter_params_test.rb
+++ b/actionpack/test/controller/filter_params_test.rb
@@ -7,14 +7,14 @@ class FilterParamTest < Test::Unit::TestCase
def setup
@controller = FilterParamController.new
end
-
+
def test_filter_parameters
assert FilterParamController.respond_to?(:filter_parameter_logging)
assert !@controller.respond_to?(:filter_parameters)
-
+
FilterParamController.filter_parameter_logging
assert @controller.respond_to?(:filter_parameters)
-
+
test_hashes = [[{},{},[]],
[{'foo'=>nil},{'foo'=>nil},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},[]],
@@ -24,11 +24,11 @@ class FilterParamTest < Test::Unit::TestCase
[{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'],
[{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'],
[{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana']]
-
+
test_hashes.each do |before_filter, after_filter, filter_words|
FilterParamController.filter_parameter_logging(*filter_words)
- assert_equal after_filter, @controller.filter_parameters(before_filter)
-
+ assert_equal after_filter, @controller.send!(:filter_parameters, before_filter)
+
filter_words.push('blah')
FilterParamController.filter_parameter_logging(*filter_words) do |key, value|
value.reverse! if key =~ /bargain/
@@ -37,7 +37,13 @@ class FilterParamTest < Test::Unit::TestCase
before_filter['barg'] = {'bargain'=>'gain', 'blah'=>'bar', 'bar'=>{'bargain'=>{'blah'=>'foo'}}}
after_filter['barg'] = {'bargain'=>'niag', 'blah'=>'[FILTERED]', 'bar'=>{'bargain'=>{'blah'=>'[FILTERED]'}}}
- assert_equal after_filter, @controller.filter_parameters(before_filter)
+ assert_equal after_filter, @controller.send!(:filter_parameters, before_filter)
end
end
+
+ def test_filter_parameters_is_protected
+ FilterParamController.filter_parameter_logging(:foo)
+ assert !FilterParamController.action_methods.include?('filter_parameters')
+ assert_raise(NoMethodError) { @controller.filter_parameters([{'password' => '[FILTERED]'}]) }
+ end
end
diff --git a/actionpack/test/controller/mime_type_test.rb b/actionpack/test/controller/mime_type_test.rb
index 03b0f8bad2..f16a3c68b4 100644
--- a/actionpack/test/controller/mime_type_test.rb
+++ b/actionpack/test/controller/mime_type_test.rb
@@ -52,16 +52,33 @@ class MimeTypeTest < Test::Unit::TestCase
end
def test_type_convenience_methods
- types = [:html, :xml, :png, :pdf, :yaml, :url_encoded_form]
+ # Don't test Mime::ALL, since it Mime::ALL#html? == true
+ types = Mime::SET.to_a.map(&:to_sym).uniq - [:all]
+
+ # 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.send("#{type}?"), "Mime::#{type.to_s.upcase} is not #{type}?"
- (types - [type]).each { |t| assert !mime.send("#{t}?"), "Mime::#{t.to_s.upcase} is #{t}?" }
+ assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?"
+ (types - [type]).each { |other_type| assert !mime.send("#{other_type}?"), "#{mime.inspect} is #{other_type}?" }
end
end
-
+
def test_mime_all_is_html
assert Mime::ALL.all?, "Mime::ALL is not all?"
assert Mime::ALL.html?, "Mime::ALL is not html?"
end
+
+ def test_verifiable_mime_types
+ unverified_types = Mime::Type.unverifiable_types
+ all_types = Mime::SET.to_a.map(&:to_sym)
+ all_types.uniq!
+ # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE
+ all_types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) }
+
+ unverified, verified = all_types.partition { |type| Mime::Type.unverifiable_types.include? type }
+ assert verified.all? { |type| Mime.const_get(type.to_s.upcase).verify_request? }, "Not all Mime Types are verified: #{verified.inspect}"
+ assert unverified.all? { |type| !Mime.const_get(type.to_s.upcase).verify_request? }, "Some Mime Types are verified: #{unverified.inspect}"
+ end
end
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index 7022713e30..f7adaa7d4e 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -101,19 +101,79 @@ module RequestForgeryProtectionTests
post :unsafe
assert_response :success
end
-
+
def test_should_not_allow_post_without_token
assert_raises(ActionController::InvalidAuthenticityToken) { post :index }
end
-
+
def test_should_not_allow_put_without_token
assert_raises(ActionController::InvalidAuthenticityToken) { put :index }
end
-
+
def test_should_not_allow_delete_without_token
assert_raises(ActionController::InvalidAuthenticityToken) { delete :index }
end
-
+
+ def test_should_not_allow_api_formatted_post_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ post :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_put_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ put :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_delete_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ delete :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_post_sent_as_url_encoded_form_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
+ post :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_put_sent_as_url_encoded_form_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
+ put :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_delete_sent_as_url_encoded_form_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
+ delete :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_post_sent_as_multipart_form_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
+ post :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_put_sent_as_multipart_form_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
+ put :index, :format => 'xml'
+ end
+ end
+
+ def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_token
+ assert_raises(ActionController::InvalidAuthenticityToken) do
+ @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
+ delete :index, :format => 'xml'
+ end
+ end
+
def test_should_not_allow_xhr_post_without_token
assert_raises(ActionController::InvalidAuthenticityToken) { xhr :post, :index }
end
@@ -142,16 +202,19 @@ module RequestForgeryProtectionTests
end
def test_should_allow_post_with_xml
+ @request.env['CONTENT_TYPE'] = Mime::XML.to_s
post :index, :format => 'xml'
assert_response :success
end
def test_should_allow_put_with_xml
+ @request.env['CONTENT_TYPE'] = Mime::XML.to_s
put :index, :format => 'xml'
assert_response :success
end
def test_should_allow_delete_with_xml
+ @request.env['CONTENT_TYPE'] = Mime::XML.to_s
delete :index, :format => 'xml'
assert_response :success
end
diff --git a/actionpack/test/controller/session/cookie_store_test.rb b/actionpack/test/controller/session/cookie_store_test.rb
index d308f2a31b..5adaeaf5c5 100755
--- a/actionpack/test/controller/session/cookie_store_test.rb
+++ b/actionpack/test/controller/session/cookie_store_test.rb
@@ -43,7 +43,9 @@ class CookieStoreTest < Test::Unit::TestCase
{ :empty => ['BAgw--0686dcaccc01040f4bd4f35fe160afe9bc04c330', {}],
:a_one => ['BAh7BiIGYWkG--5689059497d7f122a7119f171aef81dcfd807fec', { 'a' => 1 }],
:typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--9d20154623b9eeea05c62ab819be0e2483238759', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
- :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }] }
+ :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--bf9785a666d3c4ac09f7fe3353496b437546cfbf', { 'user_id' => 123, 'flash' => {} }],
+ :double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--bf9785a666d3c4ac09f7fe3353496b437546cfbf'), { 'user_id' => 123, 'flash' => {} }] }
+
end
def setup
@@ -101,6 +103,15 @@ class CookieStoreTest < Test::Unit::TestCase
end
end
+ def test_restores_double_encoded_cookies
+ set_cookie! cookie_value(:double_escaped)
+ new_session do |session|
+ session.dbman.restore
+ assert_equal session["user_id"], 123
+ assert_equal session["flash"], {}
+ end
+ end
+
def test_close_doesnt_write_cookie_if_data_is_blank
new_session do |session|
assert_no_cookies session
@@ -241,6 +252,7 @@ class CookieStoreWithMD5DigestTest < CookieStoreTest
{ :empty => ['BAgw--0415cc0be9579b14afc22ee2d341aa21', {}],
:a_one => ['BAh7BiIGYWkG--5a0ed962089cc6600ff44168a5d59bc8', { 'a' => 1 }],
:typical => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7BiILbm90aWNlIgxIZXkgbm93--f426763f6ef435b3738b493600db8d64', { 'user_id' => 123, 'flash' => { 'notice' => 'Hey now' }}],
- :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }] }
+ :flashed => ['BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA==--0af9156650dab044a53a91a4ddec2c51', { 'user_id' => 123, 'flash' => {} }],
+ :double_escaped => [CGI.escape('BAh7ByIMdXNlcl9pZGkBeyIKZmxhc2h7AA%3D%3D--0af9156650dab044a53a91a4ddec2c51'), { 'user_id' => 123, 'flash' => {} }] }
end
end
diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb
index a84d4e72af..9a1079b297 100644
--- a/actionpack/test/template/prototype_helper_test.rb
+++ b/actionpack/test/template/prototype_helper_test.rb
@@ -86,6 +86,11 @@ class PrototypeHelperTest < PrototypeHelperBaseTest
link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
end
+ def test_link_to_remote_url_quote_escaping
+ assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>),
+ link_to_remote("Remote", { :url => { :action => "whatnot's" } })
+ end
+
def test_periodically_call_remote
assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>),
periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb
index 25ecda687f..06e1fd1929 100644
--- a/actionpack/test/template/text_helper_test.rb
+++ b/actionpack/test/template/text_helper_test.rb
@@ -23,9 +23,9 @@ class TextHelperTest < ActionView::TestCase
text = "A\r\n \nB\n\n\r\n\t\nC\nD".freeze
assert_equal "<p>A\n<br /> \n<br />B</p>\n\n<p>\t\n<br />C\n<br />D</p>", simple_format(text)
-
+
assert_equal %q(<p class="test">This is a classy test</p>), simple_format("This is a classy test", :class => 'test')
- assert_equal %Q(<p class="test">para 1</p>\n\n<p class="test">para 2</p>), simple_format("para 1\n\npara 2", :class => 'test')
+ assert_equal %Q(<p class="test">para 1</p>\n\n<p class="test">para 2</p>), simple_format("para 1\n\npara 2", :class => 'test')
end
def test_truncate
@@ -41,7 +41,7 @@ class TextHelperTest < ActionView::TestCase
if RUBY_VERSION < '1.9.0'
def test_truncate_multibyte
with_kcode 'none' do
- assert_equal "\354\225\210\353\205\225\355...", truncate("\354\225\210\353\205\225\355\225\230\354\204\270\354\232\224", 10)
+ assert_equal "\354\225\210\353\205\225\355...", truncate("\354\225\210\353\205\225\355\225\230\354\204\270\354\232\224", 10)
end
with_kcode 'u' do
assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...",
@@ -73,7 +73,7 @@ class TextHelperTest < ActionView::TestCase
"This is a <b>beautiful</b> morning, but also a <b>beautiful</b> day",
highlight("This is a beautiful morning, but also a beautiful day", "beautiful", '<b>\1</b>')
)
-
+
assert_equal(
"This text is not changed because we supplied an empty phrase",
highlight("This text is not changed because we supplied an empty phrase", nil)
@@ -166,18 +166,9 @@ class TextHelperTest < ActionView::TestCase
assert_equal("2 counters", pluralize(2, "count", "counters"))
assert_equal("0 counters", pluralize(nil, "count", "counters"))
assert_equal("2 people", pluralize(2, "person"))
- assert_equal("10 buffaloes", pluralize(10, "buffalo"))
- end
-
- uses_mocha("should_just_add_s_for_pluralize_without_inflector_loaded") do
- def test_should_just_add_s_for_pluralize_without_inflector_loaded
- Object.expects(:const_defined?).with("Inflector").times(4).returns(false)
- assert_equal("1 count", pluralize(1, "count"))
- assert_equal("2 persons", pluralize(2, "person"))
- assert_equal("2 personss", pluralize("2", "persons"))
- assert_equal("2 counts", pluralize(2, "count"))
- assert_equal("10 buffalos", pluralize(10, "buffalo"))
- end
+ assert_equal("10 buffaloes", pluralize(10, "buffalo"))
+ assert_equal("1 berry", pluralize(1, "berry"))
+ assert_equal("12 berries", pluralize(12, "berry"))
end
def test_auto_link_parsing
@@ -298,7 +289,7 @@ class TextHelperTest < ActionView::TestCase
assert_equal("2", value.to_s)
assert_equal("3", value.to_s)
end
-
+
def test_cycle_class_with_no_arguments
assert_raise(ArgumentError) { value = Cycle.new() }
end
@@ -311,11 +302,11 @@ class TextHelperTest < ActionView::TestCase
assert_equal("2", cycle("one", 2, "3"))
assert_equal("3", cycle("one", 2, "3"))
end
-
+
def test_cycle_with_no_arguments
assert_raise(ArgumentError) { value = cycle() }
end
-
+
def test_cycle_resets_with_new_values
assert_equal("even", cycle("even", "odd"))
assert_equal("odd", cycle("even", "odd"))
@@ -325,7 +316,7 @@ class TextHelperTest < ActionView::TestCase
assert_equal("3", cycle(1, 2, 3))
assert_equal("1", cycle(1, 2, 3))
end
-
+
def test_named_cycles
assert_equal("1", cycle(1, 2, 3, :name => "numbers"))
assert_equal("red", cycle("red", "blue", :name => "colors"))
@@ -334,24 +325,24 @@ class TextHelperTest < ActionView::TestCase
assert_equal("3", cycle(1, 2, 3, :name => "numbers"))
assert_equal("red", cycle("red", "blue", :name => "colors"))
end
-
+
def test_default_named_cycle
assert_equal("1", cycle(1, 2, 3))
assert_equal("2", cycle(1, 2, 3, :name => "default"))
assert_equal("3", cycle(1, 2, 3))
end
-
+
def test_reset_cycle
assert_equal("1", cycle(1, 2, 3))
assert_equal("2", cycle(1, 2, 3))
reset_cycle
assert_equal("1", cycle(1, 2, 3))
end
-
+
def test_reset_unknown_cycle
reset_cycle("colors")
end
-
+
def test_recet_named_cycle
assert_equal("1", cycle(1, 2, 3, :name => "numbers"))
assert_equal("red", cycle("red", "blue", :name => "colors"))
@@ -361,7 +352,7 @@ class TextHelperTest < ActionView::TestCase
assert_equal("2", cycle(1, 2, 3, :name => "numbers"))
assert_equal("red", cycle("red", "blue", :name => "colors"))
end
-
+
def test_cycle_no_instance_variable_clashes
@cycles = %w{Specialized Fuji Giant}
assert_equal("red", cycle("red", "blue"))
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 4a130bf5c0..cd526a52a7 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,4 +1,4 @@
-*SVN*
+*2.1.0 RC1 (May 11th, 2008)*
* Ensure hm:t preloading honours reflection options. Resolves #137. [Frederick Cheung]
diff --git a/activerecord/MIT-LICENSE b/activerecord/MIT-LICENSE
index 5fee6e106d..93be57f683 100644
--- a/activerecord/MIT-LICENSE
+++ b/activerecord/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2007 David Heinemeier Hansson
+Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index d6033a9b85..043ab6d551 100755
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -171,7 +171,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
- s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
s.files.delete FIXTURES_ROOT + "/fixture_database.sqlite"
s.files.delete FIXTURES_ROOT + "/fixture_database_2.sqlite"
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 8b274120df..d4f7170305 100755
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2004-2007 David Heinemeier Hansson
+# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index fb5f1f8a8c..c17e35f5e0 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1451,9 +1451,6 @@ module ActiveRecord
join_dependency.joins_for_table_name(table)
}.flatten.compact.uniq
-
-
-
is_distinct = !options[:joins].blank? || include_eager_conditions?(options, tables_from_conditions) || include_eager_order?(options, tables_from_order)
sql = "SELECT "
if is_distinct
@@ -1500,26 +1497,28 @@ module ActiveRecord
order.scan(/([\.\w]+).?\./).flatten
end
+ def selects_tables(options)
+ select = options[:select]
+ return [] unless select && select.is_a?(String)
+ select.scan(/"?([\.\w]+)"?.?\./).flatten
+ end
+
# Checks if the conditions reference a table other than the current model table
- def include_eager_conditions?(options,tables = nil)
- tables = conditions_tables(options)
- return false unless tables.any?
- tables.any? do |condition_table_name|
- condition_table_name != table_name
- end
+ def include_eager_conditions?(options, tables = nil)
+ ((tables || conditions_tables(options)) - [table_name]).any?
end
# Checks if the query order references a table other than the current model's table.
- def include_eager_order?(options,tables = nil)
- tables = order_tables(options)
- return false unless tables.any?
- tables.any? do |order_table_name|
- order_table_name != table_name
- end
+ def include_eager_order?(options, tables = nil)
+ ((tables || order_tables(options)) - [table_name]).any?
+ end
+
+ def include_eager_select?(options)
+ (selects_tables(options) - [table_name]).any?
end
def references_eager_loaded_tables?(options)
- include_eager_order?(options) || include_eager_conditions?(options)
+ include_eager_order?(options) || include_eager_conditions?(options) || include_eager_select?(options)
end
def using_limitable_reflections?(reflections)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 7999eec55d..5351f55200 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -438,7 +438,11 @@ module ActiveRecord #:nodoc:
# adapters for, e.g., your development and test environments.
cattr_accessor :schema_format , :instance_writer => false
@@schema_format = :ruby
-
+
+ # Determine whether to store the full constant name including namespace when using STI
+ superclass_delegating_accessor :store_full_sti_class
+ self.store_full_sti_class = false
+
class << self # Class methods
# Find operates with four different retrieval approaches:
#
@@ -522,7 +526,7 @@ module ActiveRecord #:nodoc:
else find_from_ids(args, options)
end
end
-
+
# This is an alias for find(:first). You can pass in all the same arguments to this method as you can
# to find(:first)
def first(*args)
@@ -534,13 +538,13 @@ module ActiveRecord #:nodoc:
def last(*args)
find(:last, *args)
end
-
+
# This is an alias for find(:all). You can pass in all the same arguments to this method as you can
# to find(:all)
def all(*args)
find(:all, *args)
end
-
+
#
# Executes a custom sql query against your database and returns all the results. The results will
# be returned as an array with columns requested encapsulated as attributes of the model you call
@@ -587,10 +591,10 @@ module ActiveRecord #:nodoc:
def exists?(id_or_conditions)
connection.select_all(
construct_finder_sql(
- :select => "#{quoted_table_name}.#{primary_key}",
- :conditions => expand_id_conditions(id_or_conditions),
+ :select => "#{quoted_table_name}.#{primary_key}",
+ :conditions => expand_id_conditions(id_or_conditions),
:limit => 1
- ),
+ ),
"#{name} Exists"
).size > 0
end
@@ -616,7 +620,7 @@ module ActiveRecord #:nodoc:
# # Creating an Array of new objects using a block, where the block is executed for each object:
# User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
# u.is_admin = false
- # end
+ # end
def create(attributes = nil, &block)
if attributes.is_a?(Array)
attributes.collect { |attr| create(attr, &block) }
@@ -1023,9 +1027,9 @@ module ActiveRecord #:nodoc:
key = 'id'
case primary_key_prefix_type
when :table_name
- key = Inflector.foreign_key(base_name, false)
+ key = base_name.to_s.foreign_key(false)
when :table_name_with_underscore
- key = Inflector.foreign_key(base_name)
+ key = base_name.to_s.foreign_key
end
key
end
@@ -1298,7 +1302,7 @@ module ActiveRecord #:nodoc:
scoped_order = reverse_sql_order(scope(:find, :order))
scoped_methods.select { |s| s[:find].update(:order => scoped_order) }
end
-
+
find_initial(options.merge({ :order => order }))
end
@@ -1308,12 +1312,12 @@ module ActiveRecord #:nodoc:
s.gsub!(/\s(asc|ASC)$/, ' DESC')
elsif s.match(/\s(desc|DESC)$/)
s.gsub!(/\s(desc|DESC)$/, ' ASC')
- elsif !s.match(/\s(asc|ASC|desc|DESC)$/)
+ elsif !s.match(/\s(asc|ASC|desc|DESC)$/)
s.concat(' DESC')
end
}.join(',')
end
-
+
def find_every(options)
include_associations = merge_includes(scope(:find, :include), options[:include])
@@ -1557,8 +1561,8 @@ module ActiveRecord #:nodoc:
def type_condition
quoted_inheritance_column = connection.quote_column_name(inheritance_column)
- type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{name.demodulize}' ") do |condition, subclass|
- condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{subclass.name.demodulize}' "
+ type_condition = subclasses.inject("#{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? name : name.demodulize}' ") do |condition, subclass|
+ condition << "OR #{quoted_table_name}.#{quoted_inheritance_column} = '#{store_full_sti_class ? subclass.name : subclass.name.demodulize}' "
end
" (#{type_condition}) "
@@ -1566,8 +1570,8 @@ module ActiveRecord #:nodoc:
# Guesses the table name, but does not decorate it with prefix and suffix information.
def undecorated_table_name(class_name = base_class.name)
- table_name = Inflector.underscore(Inflector.demodulize(class_name))
- table_name = Inflector.pluralize(table_name) if pluralize_table_names
+ table_name = class_name.to_s.demodulize.underscore
+ table_name = table_name.pluralize if pluralize_table_names
table_name
end
@@ -1616,7 +1620,7 @@ module ActiveRecord #:nodoc:
self.class_eval %{
def self.#{method_id}(*args)
guard_protected_attributes = false
-
+
if args[0].is_a?(Hash)
guard_protected_attributes = true
attributes = args[0].with_indifferent_access
@@ -1629,7 +1633,7 @@ module ActiveRecord #:nodoc:
set_readonly_option!(options)
record = find_initial(options)
-
+
if record.nil?
record = self.new { |r| r.send(:attributes=, attributes, guard_protected_attributes) }
#{'yield(record) if block_given?'}
@@ -2129,14 +2133,14 @@ module ActiveRecord #:nodoc:
# We can't use alias_method here, because method 'id' optimizes itself on the fly.
(id = self.id) ? id.to_s : nil # Be sure to stringify the id for routes
end
-
+
# Returns a cache key that can be used to identify this record. Examples:
#
# Product.new.cache_key # => "products/new"
# Product.find(5).cache_key # => "products/5" (updated_at not available)
# Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
def cache_key
- case
+ case
when new_record?
"#{self.class.name.tableize}/new"
when self[:updated_at]
@@ -2170,7 +2174,7 @@ module ActiveRecord #:nodoc:
# Note: If your model specifies any validations then the method declaration dynamically
# changes to:
# save(perform_validation=true)
- # Calling save(false) saves the model without running validations.
+ # Calling save(false) saves the model without running validations.
# See ActiveRecord::Validations for more information.
def save
create_or_update
@@ -2342,7 +2346,7 @@ module ActiveRecord #:nodoc:
# Returns a hash of all the attributes with their names as keys and the values of the attributes as values.
- def attributes(options = nil)
+ def attributes
self.attribute_names.inject({}) do |attrs, name|
attrs[name] = read_attribute(name)
attrs
@@ -2492,7 +2496,7 @@ module ActiveRecord #:nodoc:
# Message class in that example.
def ensure_proper_type
unless self.class.descends_from_active_record?
- write_attribute(self.class.inheritance_column, Inflector.demodulize(self.class.name))
+ write_attribute(self.class.inheritance_column, store_full_sti_class ? self.class.name : self.class.name.demodulize)
end
end
diff --git a/activerecord/lib/active_record/dirty.rb b/activerecord/lib/active_record/dirty.rb
index c6d89e3a05..6034963811 100644
--- a/activerecord/lib/active_record/dirty.rb
+++ b/activerecord/lib/active_record/dirty.rb
@@ -69,19 +69,19 @@ module ActiveRecord
changed.inject({}) { |h, attr| h[attr] = attribute_change(attr); h }
end
-
- # Clear changed attributes after they are saved.
+ # Attempts to +save+ the record and clears changed attributes if successful.
def save_with_dirty(*args) #:nodoc:
- save_without_dirty(*args)
- ensure
- changed_attributes.clear
+ if status = save_without_dirty(*args)
+ changed_attributes.clear
+ end
+ status
end
- # Clear changed attributes after they are saved.
+ # Attempts to <tt>save!</tt> the record and clears changed attributes if successful.
def save_with_dirty!(*args) #:nodoc:
- save_without_dirty!(*args)
- ensure
+ status = save_without_dirty!(*args)
changed_attributes.clear
+ status
end
private
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 9367ea523d..ac06cdbe43 100755
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -197,20 +197,20 @@ end
# class FooTest < ActiveSupport::TestCase
# self.use_transactional_fixtures = true
# self.use_instantiated_fixtures = false
-#
+#
# fixtures :foos
-#
+#
# def test_godzilla
# assert !Foo.find(:all).empty?
# Foo.destroy_all
# assert Foo.find(:all).empty?
# end
-#
+#
# def test_godzilla_aftermath
# assert !Foo.find(:all).empty?
# end
# end
-#
+#
# If you preload your test database with all fixture data (probably in the Rakefile task) and use transactional fixtures,
# then you may omit all fixtures declarations in your test cases since all the data's already there and every case rolls back its changes.
#
@@ -730,7 +730,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
reader.each do |row|
data = {}
row.each_with_index { |cell, j| data[header[j].to_s.strip] = cell.to_s.strip }
- self["#{Inflector::underscore(@class_name)}_#{i+=1}"] = Fixture.new(data, model_class)
+ self["#{@class_name.to_s.underscore}_#{i+=1}"] = Fixture.new(data, model_class)
end
end
@@ -854,14 +854,14 @@ module Test #:nodoc:
require_dependency file_name
rescue LoadError => e
# Let's hope the developer has included it himself
-
+
# Let's warn in case this is a subdependency, otherwise
# subdependency error messages are totally cryptic
if ActiveRecord::Base.logger
ActiveRecord::Base.logger.warn("Unable to load #{file_name}, underlying cause #{e.message} \n\n #{e.backtrace.join("\n")}")
end
end
-
+
def require_fixture_classes(table_names = nil)
(table_names || fixture_table_names).each do |table_name|
file_name = table_name.to_s
diff --git a/activerecord/lib/active_record/version.rb b/activerecord/lib/active_record/version.rb
index a8ee7dbeb9..1463e84764 100644
--- a/activerecord/lib/active_record/version.rb
+++ b/activerecord/lib/active_record/version.rb
@@ -2,7 +2,7 @@ module ActiveRecord
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
- TINY = 2
+ TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/activerecord/test/cases/dirty_test.rb b/activerecord/test/cases/dirty_test.rb
index 7412e63872..1266eb5036 100644
--- a/activerecord/test/cases/dirty_test.rb
+++ b/activerecord/test/cases/dirty_test.rb
@@ -78,7 +78,7 @@ class DirtyTest < ActiveRecord::TestCase
end
def test_association_assignment_changes_foreign_key
- pirate = Pirate.create!
+ pirate = Pirate.create!(:catchphrase => 'jarl')
pirate.parrot = Parrot.create!
assert pirate.changed?
assert_equal %w(parrot_id), pirate.changed
@@ -115,6 +115,18 @@ class DirtyTest < ActiveRecord::TestCase
end
end
+ def test_changed_attributes_should_be_preserved_if_save_failure
+ pirate = Pirate.new
+ pirate.parrot_id = 1
+ assert !pirate.save
+ check_pirate_after_save_failure(pirate)
+
+ pirate = Pirate.new
+ pirate.parrot_id = 1
+ assert_raises(ActiveRecord::RecordInvalid) { pirate.save! }
+ check_pirate_after_save_failure(pirate)
+ end
+
private
def with_partial_updates(klass, on = true)
old = klass.partial_updates?
@@ -123,4 +135,11 @@ class DirtyTest < ActiveRecord::TestCase
ensure
klass.partial_updates = old
end
+
+ def check_pirate_after_save_failure(pirate)
+ assert pirate.changed?
+ assert pirate.parrot_id_changed?
+ assert_equal %w(parrot_id), pirate.changed
+ assert_nil pirate.parrot_id_was
+ end
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 2acfe9b387..5c0f0e2ef1 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -9,6 +9,7 @@ require 'models/developer'
require 'models/post'
require 'models/customer'
require 'models/job'
+require 'models/categorization'
class FinderTest < ActiveRecord::TestCase
fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :customers
@@ -859,12 +860,17 @@ class FinderTest < ActiveRecord::TestCase
end
def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
- assert_equal 2, Post.find(:all,:include=>{:authors=>:author_address},:order=>' author_addresses.id DESC ', :limit=>2).size
+ assert_equal 2, Post.find(:all, :include => { :authors => :author_address }, :order => ' author_addresses.id DESC ', :limit => 2).size
- assert_equal 3, Post.find(:all,:include=>{:author=>:author_address,:authors=>:author_address},
- :order=>' author_addresses_authors.id DESC ', :limit=>3).size
+ assert_equal 3, Post.find(:all, :include => { :author => :author_address, :authors => :author_address},
+ :order => ' author_addresses_authors.id DESC ', :limit => 3).size
end
+ def test_with_limiting_with_custom_select
+ posts = Post.find(:all, :include => :author, :select => ' posts.*, authors.id as "author_id"', :limit => 3)
+ assert_equal 3, posts.size
+ assert_equal [0, 1, 1], posts.map(&:author_id).sort
+ end
protected
def bind(statement, *vars)
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 2787b9a39d..aca7cfb367 100755
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -610,15 +610,17 @@ class ActiveSupportSubclassWithFixturesTest < ActiveRecord::TestCase
end
class FixtureLoadingTest < ActiveRecord::TestCase
- def test_logs_message_for_failed_dependency_load
- Test::Unit::TestCase.expects(:require_dependency).with(:does_not_exist).raises(LoadError)
- ActiveRecord::Base.logger.expects(:warn)
- Test::Unit::TestCase.try_to_load_dependency(:does_not_exist)
- end
+ uses_mocha 'reloading_fixtures_through_accessor_methods' do
+ def test_logs_message_for_failed_dependency_load
+ Test::Unit::TestCase.expects(:require_dependency).with(:does_not_exist).raises(LoadError)
+ ActiveRecord::Base.logger.expects(:warn)
+ Test::Unit::TestCase.try_to_load_dependency(:does_not_exist)
+ end
- def test_does_not_logs_message_for_successful_dependency_load
- Test::Unit::TestCase.expects(:require_dependency).with(:works_out_fine)
- ActiveRecord::Base.logger.expects(:warn).never
- Test::Unit::TestCase.try_to_load_dependency(:works_out_fine)
+ def test_does_not_logs_message_for_successful_dependency_load
+ Test::Unit::TestCase.expects(:require_dependency).with(:works_out_fine)
+ ActiveRecord::Base.logger.expects(:warn).never
+ Test::Unit::TestCase.try_to_load_dependency(:works_out_fine)
+ end
end
end
diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb
index c9eb83e371..27394924a1 100755
--- a/activerecord/test/cases/inheritance_test.rb
+++ b/activerecord/test/cases/inheritance_test.rb
@@ -5,6 +5,34 @@ require 'models/subscriber'
class InheritanceTest < ActiveRecord::TestCase
fixtures :companies, :projects, :subscribers, :accounts
+
+ def test_should_store_demodulized_class_name_with_store_full_sti_class_option_disabled
+ old = ActiveRecord::Base.store_full_sti_class
+ ActiveRecord::Base.store_full_sti_class = false
+ item = Namespaced::Company.new
+ assert_equal 'Company', item[:type]
+ ensure
+ ActiveRecord::Base.store_full_sti_class = old
+ end
+
+ def test_should_store_full_class_name_with_store_full_sti_class_option_enabled
+ old = ActiveRecord::Base.store_full_sti_class
+ ActiveRecord::Base.store_full_sti_class = true
+ item = Namespaced::Company.new
+ assert_equal 'Namespaced::Company', item[:type]
+ ensure
+ ActiveRecord::Base.store_full_sti_class = old
+ end
+
+ def test_different_namespace_subclass_should_load_correctly_with_store_full_sti_class_option
+ old = ActiveRecord::Base.store_full_sti_class
+ ActiveRecord::Base.store_full_sti_class = true
+ item = Namespaced::Company.create :name => "Wolverine 2"
+ assert_not_nil Company.find(item.id)
+ assert_not_nil Namespaced::Company.find(item.id)
+ ensure
+ ActiveRecord::Base.store_full_sti_class = old
+ end
def test_company_descends_from_active_record
assert_raise(NoMethodError) { ActiveRecord::Base.descends_from_active_record? }
diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb
index 3d76dfd398..f637490c59 100755
--- a/activerecord/test/models/company.rb
+++ b/activerecord/test/models/company.rb
@@ -15,6 +15,10 @@ class Company < AbstractCompany
end
end
+module Namespaced
+ class Company < ::Company
+ end
+end
class Firm < Company
has_many :clients, :order => "id", :dependent => :destroy, :counter_sql =>
diff --git a/activerecord/test/models/pirate.rb b/activerecord/test/models/pirate.rb
index bb4d02c10f..51c8183dee 100644
--- a/activerecord/test/models/pirate.rb
+++ b/activerecord/test/models/pirate.rb
@@ -4,4 +4,6 @@ class Pirate < ActiveRecord::Base
has_many :treasures, :as => :looter
has_many :treasure_estimates, :through => :treasures, :source => :price_estimates
+
+ validates_presence_of :catchphrase
end
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index 7becf4fc0c..9aa7d455a2 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -1,4 +1,4 @@
-*SVN*
+*2.1.0 RC1 (May 11th, 2008)*
* Fixed response logging to use length instead of the entire thing (seangeo) [#27]
diff --git a/activeresource/Rakefile b/activeresource/Rakefile
index 8af78ceb55..75fe52aea8 100644
--- a/activeresource/Rakefile
+++ b/activeresource/Rakefile
@@ -64,7 +64,7 @@ spec = Gem::Specification.new do |s|
s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
end
- s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
s.require_path = 'lib'
s.autorequire = 'active_resource'
diff --git a/activeresource/lib/active_resource/version.rb b/activeresource/lib/active_resource/version.rb
index 4f7de5e1a0..34fb05b703 100644
--- a/activeresource/lib/active_resource/version.rb
+++ b/activeresource/lib/active_resource/version.rb
@@ -2,7 +2,7 @@ module ActiveResource
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
- TINY = 2
+ TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 185aff9088..e8821060f9 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,4 +1,4 @@
-*SVN*
+*2.1.0 RC1 (May 11th, 2008)*
* Remove unused JSON::RESERVED_WORDS, JSON.valid_identifier? and JSON.reserved_word? methods. Resolves #164. [Cheah Chu Yeow]
diff --git a/activesupport/MIT-LICENSE b/activesupport/MIT-LICENSE
index dbe78035ba..2ba4e17035 100644
--- a/activesupport/MIT-LICENSE
+++ b/activesupport/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2005-2007 David Heinemeier Hansson
+Copyright (c) 2005-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 4d2f873a8d..e4cb145c98 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -39,6 +39,7 @@ require 'active_support/cache'
require 'active_support/dependencies'
require 'active_support/deprecation'
+require 'active_support/ordered_hash'
require 'active_support/ordered_options'
require 'active_support/option_merger'
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
index 371d074d34..8724a492bf 100644
--- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -128,7 +128,7 @@ class Class # :nodoc:
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
else
new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
- memo.update(key => (value.dup rescue value))
+ memo.update(key => value.duplicable? ? value.dup : value)
end
end
diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb
index 7613652c71..6aa379b550 100644
--- a/activesupport/lib/active_support/deprecation.rb
+++ b/activesupport/lib/active_support/deprecation.rb
@@ -176,19 +176,6 @@ module ActiveSupport
end
end
- class DeprecatedInstanceVariable < Delegator #:nodoc:
- def initialize(value, method)
- super(value)
- @method = method
- @value = value
- end
-
- def __getobj__
- ActiveSupport::Deprecation.warn("Instance variable @#{@method} is deprecated! Call instance method #{@method} instead.")
- @value
- end
- end
-
end
end
diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb
new file mode 100644
index 0000000000..6993621ef9
--- /dev/null
+++ b/activesupport/lib/active_support/ordered_hash.rb
@@ -0,0 +1,43 @@
+# OrderedHash is namespaced to prevent conflicts with other implementations
+module ActiveSupport
+ # Hash is ordered in Ruby 1.9!
+ if RUBY_VERSION >= '1.9'
+ OrderedHash = ::Hash
+ else
+ class OrderedHash < Array #:nodoc:
+ def []=(key, value)
+ if pair = assoc(key)
+ pair.pop
+ pair << value
+ else
+ self << [key, value]
+ end
+ end
+
+ def [](key)
+ pair = assoc(key)
+ pair ? pair.last : nil
+ end
+
+ def delete(key)
+ pair = assoc(key)
+ pair ? array_index = index(pair) : nil
+ array_index ? delete_at(array_index).last : nil
+ end
+
+ def keys
+ collect { |key, value| key }
+ end
+
+ def values
+ collect { |key, value| value }
+ end
+
+ def to_hash
+ returning({}) do |hash|
+ each { |array| hash[array[0]] = array[1] }
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb
index 3172f62f0d..306376e9ae 100644
--- a/activesupport/lib/active_support/ordered_options.rb
+++ b/activesupport/lib/active_support/ordered_options.rb
@@ -1,47 +1,3 @@
-# OrderedHash is namespaced to prevent conflicts with other implementations
-module ActiveSupport
- # Hash is ordered in Ruby 1.9!
- if RUBY_VERSION >= '1.9'
- OrderedHash = ::Hash
- else
- class OrderedHash < Array #:nodoc:
- def []=(key, value)
- if pair = assoc(key)
- pair.pop
- pair << value
- else
- self << [key, value]
- end
- end
-
- def [](key)
- pair = assoc(key)
- pair ? pair.last : nil
- end
-
- def delete(key)
- pair = assoc(key)
- pair ? array_index = index(pair) : nil
- array_index ? delete_at(array_index).last : nil
- end
-
- def keys
- collect { |key, value| key }
- end
-
- def values
- collect { |key, value| value }
- end
-
- def to_hash
- returning({}) do |hash|
- each { |array| hash[array[0]] = array[1] }
- end
- end
- end
- end
-end
-
class OrderedOptions < ActiveSupport::OrderedHash #:nodoc:
def []=(key, value)
super(key.to_sym, value)
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 21ddcaad48..48606dbcff 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -78,7 +78,7 @@ module ActiveSupport
def to_json(options = nil)
if ActiveSupport.use_standard_json_time_format
- utc.xmlschema.inspect
+ xmlschema.inspect
else
%("#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)}")
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 0fa99135e2..f522b64108 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -325,6 +325,9 @@ class TimeZone
ZONES.sort!
ZONES.freeze
ZONES_MAP.freeze
+
+ US_ZONES = ZONES.find_all { |z| z.name =~ /US|Arizona|Indiana|Hawaii|Alaska/ }
+ US_ZONES.freeze
end
class << self
@@ -361,14 +364,10 @@ class TimeZone
end
end
- # A regular expression that matches the names of all time zones in
- # the USA.
- US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/.freeze
-
# A convenience method for returning a collection of TimeZone objects
# for time zones in the USA.
def us_zones
- all.find_all { |z| z.name =~ US_ZONES }
+ US_ZONES
end
end
end
diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb
index 83fbaec62c..f3d141cf72 100644
--- a/activesupport/lib/active_support/version.rb
+++ b/activesupport/lib/active_support/version.rb
@@ -2,7 +2,7 @@ module ActiveSupport
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
- TINY = 2
+ TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb
index 64fcb4af09..70c393dd46 100644
--- a/activesupport/test/core_ext/time_with_zone_test.rb
+++ b/activesupport/test/core_ext/time_with_zone_test.rb
@@ -70,7 +70,7 @@ class TimeWithZoneTest < Test::Unit::TestCase
def test_to_json_with_use_standard_json_time_format_config_set_to_true
old, ActiveSupport.use_standard_json_time_format = ActiveSupport.use_standard_json_time_format, true
- assert_equal "\"2000-01-01T00:00:00Z\"", @twz.to_json
+ assert_equal "\"1999-12-31T19:00:00-05:00\"", @twz.to_json
ensure
ActiveSupport.use_standard_json_time_format = old
end
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index 11357e250f..ebfa405947 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -149,13 +149,3 @@ class DeprecationTest < Test::Unit::TestCase
assert_nil @last_message
end
end
-
-class DeprecatedIvarTest < Test::Unit::TestCase
-
- def test_deprecated_ivar
- @action = ActiveSupport::Deprecation::DeprecatedInstanceVariable.new("fubar", :foobar)
-
- assert_deprecated(/Instance variable @foobar is deprecated! Call instance method foobar instead/) { assert_equal "fubar", @action }
- end
-
-end
diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb
new file mode 100644
index 0000000000..14be48724e
--- /dev/null
+++ b/activesupport/test/ordered_hash_test.rb
@@ -0,0 +1,45 @@
+require 'abstract_unit'
+
+class OrderedHashTest < Test::Unit::TestCase
+ def setup
+ @keys = %w( blue green red pink orange )
+ @values = %w( 000099 009900 aa0000 cc0066 cc6633 )
+ @ordered_hash = ActiveSupport::OrderedHash.new
+
+ @keys.each_with_index do |key, index|
+ @ordered_hash[key] = @values[index]
+ end
+ end
+
+ def test_order
+ assert_equal @keys, @ordered_hash.keys
+ assert_equal @values, @ordered_hash.values
+ end
+
+ def test_access
+ assert @keys.zip(@values).all? { |k, v| @ordered_hash[k] == v }
+ end
+
+ def test_assignment
+ key, value = 'purple', '5422a8'
+
+ @ordered_hash[key] = value
+ assert_equal @keys.length + 1, @ordered_hash.length
+ assert_equal key, @ordered_hash.keys.last
+ assert_equal value, @ordered_hash.values.last
+ assert_equal value, @ordered_hash[key]
+ end
+
+ def test_delete
+ key, value = 'white', 'ffffff'
+ bad_key = 'black'
+
+ @ordered_hash[key] = value
+ assert_equal @keys.length + 1, @ordered_hash.length
+
+ assert_equal value, @ordered_hash.delete(key)
+ assert_equal @keys.length, @ordered_hash.length
+
+ assert_nil @ordered_hash.delete(bad_key)
+ end
+end
diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb
index 3d537a0ae4..fb7a58d0b0 100644
--- a/activesupport/test/ordered_options_test.rb
+++ b/activesupport/test/ordered_options_test.rb
@@ -1,49 +1,5 @@
require 'abstract_unit'
-class OrderedHashTest < Test::Unit::TestCase
- def setup
- @keys = %w( blue green red pink orange )
- @values = %w( 000099 009900 aa0000 cc0066 cc6633 )
- @ordered_hash = ActiveSupport::OrderedHash.new
-
- @keys.each_with_index do |key, index|
- @ordered_hash[key] = @values[index]
- end
- end
-
- def test_order
- assert_equal @keys, @ordered_hash.keys
- assert_equal @values, @ordered_hash.values
- end
-
- def test_access
- assert @keys.zip(@values).all? { |k, v| @ordered_hash[k] == v }
- end
-
- def test_assignment
- key, value = 'purple', '5422a8'
-
- @ordered_hash[key] = value
- assert_equal @keys.length + 1, @ordered_hash.length
- assert_equal key, @ordered_hash.keys.last
- assert_equal value, @ordered_hash.values.last
- assert_equal value, @ordered_hash[key]
- end
-
- def test_delete
- key, value = 'white', 'ffffff'
- bad_key = 'black'
-
- @ordered_hash[key] = value
- assert_equal @keys.length + 1, @ordered_hash.length
-
- assert_equal value, @ordered_hash.delete(key)
- assert_equal @keys.length, @ordered_hash.length
-
- assert_nil @ordered_hash.delete(bad_key)
- end
-end
-
class OrderedOptionsTest < Test::Unit::TestCase
def test_usage
a = OrderedOptions.new
diff --git a/pushgems.rb b/pushgems.rb
index 6a1f1ffe8f..784aa5de68 100755
--- a/pushgems.rb
+++ b/pushgems.rb
@@ -1,7 +1,7 @@
#!/usr/bin/env ruby
unless ARGV.first == "no_build"
- build_number = build_number = `svn log -q -rhead http://dev.rubyonrails.org/svn/rails`.scan(/r([0-9]*)/).first.first.to_i
+ build_number = Time.now.strftime("%Y%m%d%H%M%S").to_i
end
%w( activeresource actionmailer actionpack activerecord railties activesupport ).each do |pkg|
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 2ca1965d97..11d2926f31 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,4 +1,4 @@
-*SVN*
+*2.1.0 RC1 (May 11th, 2008)*
* script/dbconsole fires up the command-line database client. #102 [Steve Purcell]
diff --git a/railties/MIT-LICENSE b/railties/MIT-LICENSE
index 5fee6e106d..93be57f683 100644
--- a/railties/MIT-LICENSE
+++ b/railties/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2007 David Heinemeier Hansson
+Copyright (c) 2004-2008 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/railties/Rakefile b/railties/Rakefile
index 4eaa1bef63..45ba394299 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -303,12 +303,12 @@ spec = Gem::Specification.new do |s|
on top of either MySQL, PostgreSQL, SQLite, DB2, SQL Server, or Oracle with eRuby- or Builder-based templates.
EOF
- s.add_dependency('rake', '>= 0.7.2')
- s.add_dependency('activesupport', '= 2.0.2' + PKG_BUILD)
- s.add_dependency('activerecord', '= 2.0.2' + PKG_BUILD)
- s.add_dependency('actionpack', '= 2.0.2' + PKG_BUILD)
- s.add_dependency('actionmailer', '= 2.0.2' + PKG_BUILD)
- s.add_dependency('activeresource', '= 2.0.2' + PKG_BUILD)
+ s.add_dependency('rake', '>= 0.8.1')
+ s.add_dependency('activesupport', '= 2.0.991' + PKG_BUILD)
+ s.add_dependency('activerecord', '= 2.0.991' + PKG_BUILD)
+ s.add_dependency('actionpack', '= 2.0.991' + PKG_BUILD)
+ s.add_dependency('actionmailer', '= 2.0.991' + PKG_BUILD)
+ s.add_dependency('activeresource', '= 2.0.991' + PKG_BUILD)
s.rdoc_options << '--exclude' << '.'
s.has_rdoc = false
diff --git a/railties/configs/initializers/new_rails_defaults.rb b/railties/configs/initializers/new_rails_defaults.rb
index 3a617e3ae3..b8f0e2cac2 100644
--- a/railties/configs/initializers/new_rails_defaults.rb
+++ b/railties/configs/initializers/new_rails_defaults.rb
@@ -7,6 +7,9 @@ ActiveRecord::Base.partial_updates = true
# Include ActiveRecord class name as root for JSON serialized output.
ActiveRecord::Base.include_root_in_json = true
+# Store the full class name (including module namespace) in STI type column
+ActiveRecord::Base.store_full_sti_class = true
+
# Use ISO 8601 format for JSON serialized times and dates
ActiveSupport.use_standard_json_time_format = true
diff --git a/railties/html/javascripts/controls.js b/railties/html/javascripts/controls.js
index fbc4418b83..5aaf0bb2b7 100644
--- a/railties/html/javascripts/controls.js
+++ b/railties/html/javascripts/controls.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan)
// (c) 2005-2007 Jon Tirsen (http://www.tirsen.com)
// Contributors:
diff --git a/railties/html/javascripts/dragdrop.js b/railties/html/javascripts/dragdrop.js
index ccf4a1e45c..bf5cfea66c 100644
--- a/railties/html/javascripts/dragdrop.js
+++ b/railties/html/javascripts/dragdrop.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// (c) 2005-2007 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
//
// script.aculo.us is freely distributable under the terms of an MIT-style license.
diff --git a/railties/html/javascripts/effects.js b/railties/html/javascripts/effects.js
index 65aed23957..f030b5dbe9 100644
--- a/railties/html/javascripts/effects.js
+++ b/railties/html/javascripts/effects.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
// Justin Palmer (http://encytemedia.com/)
// Mark Pilgrim (http://diveintomark.org/)
diff --git a/railties/lib/commands/dbconsole.rb b/railties/lib/commands/dbconsole.rb
index 28c3a3e41f..3e5010c688 100644
--- a/railties/lib/commands/dbconsole.rb
+++ b/railties/lib/commands/dbconsole.rb
@@ -1,3 +1,4 @@
+require 'erb'
require 'yaml'
require 'optparse'
@@ -8,7 +9,7 @@ OptionParser.new do |opt|
end
env = ARGV.first || ENV['RAILS_ENV'] || 'development'
-unless config = YAML.load_file(RAILS_ROOT + "/config/database.yml")[env]
+unless config = YAML::load(ERB.new(IO.read(RAILS_ROOT + "/config/database.yml")).result)[env]
abort "No database is configured for the environment '#{env}'"
end
diff --git a/railties/lib/dispatcher.rb b/railties/lib/dispatcher.rb
index 9db424f14b..0bad45d9d8 100644
--- a/railties/lib/dispatcher.rb
+++ b/railties/lib/dispatcher.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2004-2007 David Heinemeier Hansson
+# Copyright (c) 2004-2008 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/railties/lib/rails/plugin/locator.rb b/railties/lib/rails/plugin/locator.rb
index fd7de4ee28..f06a51a572 100644
--- a/railties/lib/rails/plugin/locator.rb
+++ b/railties/lib/rails/plugin/locator.rb
@@ -78,11 +78,12 @@ module Rails
# a <tt>rails/init.rb</tt> file.
class GemLocator < Locator
def plugins
- specs = initializer.configuration.gems.map(&:specification)
- specs + Gem.loaded_specs.values.select do |spec|
+ specs = initializer.configuration.gems.map(&:specification)
+ specs += Gem.loaded_specs.values.select do |spec|
spec.loaded_from && # prune stubs
File.exist?(File.join(spec.full_gem_path, "rails", "init.rb"))
end
+ specs.compact!
require "rubygems/dependency_list"
diff --git a/railties/lib/rails/version.rb b/railties/lib/rails/version.rb
index da90645738..fea63beea9 100644
--- a/railties/lib/rails/version.rb
+++ b/railties/lib/rails/version.rb
@@ -2,7 +2,7 @@ module Rails
module VERSION #:nodoc:
MAJOR = 2
MINOR = 0
- TINY = 2
+ TINY = 991
STRING = [MAJOR, MINOR, TINY].join('.')
end
diff --git a/railties/lib/rails_generator/commands.rb b/railties/lib/rails_generator/commands.rb
index 440bab276c..03b7d354a6 100644
--- a/railties/lib/rails_generator/commands.rb
+++ b/railties/lib/rails_generator/commands.rb
@@ -154,28 +154,35 @@ HELP
# Ruby or Rails. In the future, expand to check other namespaces
# such as the rest of the user's app.
def class_collisions(*class_names)
+
+ # Initialize some check varibles
+ last_class = Object
+ current_class = nil
+ name = nil
+
class_names.flatten.each do |class_name|
# Convert to string to allow symbol arguments.
class_name = class_name.to_s
# Skip empty strings.
- next if class_name.strip.empty?
+ class_name.strip.empty? ? next : current_class = class_name
# Split the class from its module nesting.
nesting = class_name.split('::')
name = nesting.pop
# Extract the last Module in the nesting.
- last = nesting.inject(Object) { |last, nest|
- break unless last.const_defined?(nest)
- last.const_get(nest)
+ last = nesting.inject(last_class) { |last, nest|
+ break unless last_class.const_defined?(nest)
+ last_class = last_class.const_get(nest)
}
- # If the last Module exists, check whether the given
- # class exists and raise a collision if so.
- if last and last.const_defined?(name.camelize)
- raise_class_collision(class_name)
- end
+ end
+ # If the last Module exists, check whether the given
+ # class exists and raise a collision if so.
+
+ if last_class and last_class.const_defined?(name.camelize)
+ raise_class_collision(current_class)
end
end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb b/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
index 864a0bc528..e2902bf4b9 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails_generator/generators/components/scaffold/scaffold_generator.rb
@@ -34,7 +34,7 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
m.class_collisions(controller_class_path, "#{controller_class_name}Controller", "#{controller_class_name}Helper")
m.class_collisions(class_path, "#{class_name}")
- # Controller, helper, views, and test directories.
+ # Controller, helper, views, test and stylesheets directories.
m.directory(File.join('app/models', class_path))
m.directory(File.join('app/controllers', controller_class_path))
m.directory(File.join('app/helpers', controller_class_path))
@@ -42,6 +42,7 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
m.directory(File.join('app/views/layouts', controller_class_path))
m.directory(File.join('test/functional', controller_class_path))
m.directory(File.join('test/unit', class_path))
+ m.directory(File.join('public/stylesheets', class_path))
for action in scaffold_views
m.template(
diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake
index 63f71448f8..f40f8463f7 100644
--- a/railties/lib/tasks/databases.rake
+++ b/railties/lib/tasks/databases.rake
@@ -45,7 +45,7 @@ namespace :db do
when 'postgresql'
@encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
begin
- ActiveRecord::Base.establish_connection(config.merge('database' => 'template1'))
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
ActiveRecord::Base.establish_connection(config)
rescue
@@ -368,7 +368,7 @@ def drop_database(config)
when /^sqlite/
FileUtils.rm(File.join(RAILS_ROOT, config['database']))
when 'postgresql'
- ActiveRecord::Base.establish_connection(config.merge('database' => 'template1'))
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
ActiveRecord::Base.connection.drop_database config['database']
end
end
diff --git a/railties/test/generators/generator_test_helper.rb b/railties/test/generators/generator_test_helper.rb
index 190bc91d52..c99df6e2d3 100644
--- a/railties/test/generators/generator_test_helper.rb
+++ b/railties/test/generators/generator_test_helper.rb
@@ -13,7 +13,7 @@ module ActiveRecord
module ConnectionAdapters
class Column
attr_reader :name, :default, :type, :limit, :null, :sql_type, :precision, :scale
-
+
def initialize(name, default, sql_type = nil)
@name = name
@default = default
@@ -59,16 +59,16 @@ require 'rails_generator'
class GeneratorTestCase < Test::Unit::TestCase
include FileUtils
-
+
def setup
ActiveRecord::Base.pluralize_table_names = true
-
+
mkdir_p "#{RAILS_ROOT}/app/views/layouts"
mkdir_p "#{RAILS_ROOT}/config"
mkdir_p "#{RAILS_ROOT}/db"
mkdir_p "#{RAILS_ROOT}/test/fixtures"
mkdir_p "#{RAILS_ROOT}/public/stylesheets"
-
+
File.open("#{RAILS_ROOT}/config/routes.rb", 'w') do |f|
f << "ActionController::Routing::Routes.draw do |map|\n\nend"
end
@@ -85,7 +85,7 @@ class GeneratorTestCase < Test::Unit::TestCase
def test_truth
# don't complain, test/unit
end
-
+
# Instantiates the Generator
def build_generator(name, params)
Rails::Generator::Base.instance(name, params)
@@ -171,9 +171,16 @@ class GeneratorTestCase < Test::Unit::TestCase
# asserts that the given class source file was generated.
# It takes a path without the <tt>.rb</tt> part and an optional super class.
# the contents of the class source file is passed to a block.
- def assert_generated_class(path, parent=nil)
- path =~ /\/?(\d+_)?(\w+)$/
- class_name = $2.camelize
+ def assert_generated_class(path, parent = nil)
+ # FIXME: Sucky way to detect namespaced classes
+ if path.split('/').size > 3
+ path =~ /\/?(\d+_)?(\w+)\/(\w+)$/
+ class_name = "#{$2.camelize}::#{$3.camelize}"
+ else
+ path =~ /\/?(\d+_)?(\w+)$/
+ class_name = $2.camelize
+ end
+
assert_generated_file("#{path}.rb") do |body|
assert_match /class #{class_name}#{parent.nil? ? '':" < #{parent}"}/, body, "the file '#{path}.rb' should be a class"
yield body if block_given?
@@ -184,8 +191,15 @@ class GeneratorTestCase < Test::Unit::TestCase
# It takes a path without the <tt>.rb</tt> part.
# the contents of the class source file is passed to a block.
def assert_generated_module(path)
- path =~ /\/?(\w+)$/
- module_name = $1.camelize
+ # FIXME: Sucky way to detect namespaced modules
+ if path.split('/').size > 3
+ path =~ /\/?(\w+)\/(\w+)$/
+ module_name = "#{$1.camelize}::#{$2.camelize}"
+ else
+ path =~ /\/?(\w+)$/
+ module_name = $1.camelize
+ end
+
assert_generated_file("#{path}.rb") do |body|
assert_match /module #{module_name}/, body, "the file '#{path}.rb' should be a module"
yield body if block_given?
diff --git a/railties/test/generators/rails_controller_generator_test.rb b/railties/test/generators/rails_controller_generator_test.rb
new file mode 100644
index 0000000000..0090d21b85
--- /dev/null
+++ b/railties/test/generators/rails_controller_generator_test.rb
@@ -0,0 +1,20 @@
+require 'generators/generator_test_helper'
+
+class RailsControllerGeneratorTest < GeneratorTestCase
+
+ def test_controller_generates_controller
+ run_generator('controller', %w(products))
+
+ assert_generated_controller_for :products
+ assert_generated_functional_test_for :products
+ assert_generated_helper_for :products
+ end
+
+ def test_controller_generates_namespaced_controller
+ run_generator('controller', %w(admin::products))
+
+ assert_generated_controller_for "admin::products"
+ assert_generated_functional_test_for "admin::products"
+ assert_generated_helper_for "admin::products"
+ end
+end