aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrick <rick@spacemonkey.local>2008-05-05 23:19:21 -0700
committerrick <rick@spacemonkey.local>2008-05-05 23:19:21 -0700
commit0052938ac5b8894b27fdb9f27b1ed39f0a9ea176 (patch)
treef714643a4043d9fb73b39ec2a114d18f5deeffdd
parenteacb5cf0cab6447db78085c8bda6c94dd329ce6b (diff)
parent3cffe92ff066c2b35eef409547db93652c5cccfc (diff)
downloadrails-0052938ac5b8894b27fdb9f27b1ed39f0a9ea176.tar.gz
rails-0052938ac5b8894b27fdb9f27b1ed39f0a9ea176.tar.bz2
rails-0052938ac5b8894b27fdb9f27b1ed39f0a9ea176.zip
Merge commit 'core/master'
-rw-r--r--actionmailer/lib/action_mailer/base.rb12
-rw-r--r--actionpack/CHANGELOG4
-rw-r--r--actionpack/lib/action_controller/assertions/selector_assertions.rb5
-rwxr-xr-xactionpack/lib/action_controller/base.rb24
-rw-r--r--actionpack/lib/action_controller/cookies.rb50
-rw-r--r--actionpack/lib/action_controller/filters.rb9
-rw-r--r--actionpack/lib/action_controller/helpers.rb12
-rw-r--r--actionpack/lib/action_controller/mime_type.rb9
-rw-r--r--actionpack/lib/action_controller/polymorphic_routes.rb2
-rwxr-xr-xactionpack/lib/action_controller/request.rb18
-rw-r--r--actionpack/lib/action_controller/request_forgery_protection.rb3
-rw-r--r--actionpack/lib/action_controller/rescue.rb38
-rw-r--r--actionpack/lib/action_controller/resources.rb14
-rw-r--r--actionpack/lib/action_controller/routing.rb94
-rw-r--r--actionpack/lib/action_controller/routing/builder.rb4
-rw-r--r--actionpack/lib/action_controller/routing/optimisations.rb25
-rw-r--r--actionpack/lib/action_controller/routing/route.rb4
-rw-r--r--actionpack/lib/action_controller/routing/route_set.rb12
-rw-r--r--actionpack/lib/action_controller/session/cookie_store.rb26
-rw-r--r--actionpack/lib/action_controller/session_management.rb8
-rw-r--r--actionpack/lib/action_controller/streaming.rb24
-rw-r--r--actionpack/lib/action_controller/test_case.rb23
-rw-r--r--actionpack/lib/action_controller/test_process.rb64
-rw-r--r--actionpack/lib/action_controller/url_rewriter.rb17
-rw-r--r--actionpack/lib/action_view/base.rb20
-rw-r--r--actionpack/lib/action_view/helpers/active_record_helper.rb124
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/benchmark_helper.rb8
-rwxr-xr-xactionpack/lib/action_view/helpers/date_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb22
-rw-r--r--actionpack/lib/action_view/helpers/form_options_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb5
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb20
-rw-r--r--actionpack/lib/action_view/helpers/sanitize_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/scriptaculous_helper.rb4
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb16
-rw-r--r--actionpack/lib/action_view/partial_template.rb10
-rw-r--r--actionpack/lib/action_view/partials.rb6
-rw-r--r--actionpack/lib/action_view/template.rb12
-rw-r--r--actionpack/lib/action_view/template_finder.rb7
-rw-r--r--actionpack/lib/action_view/template_handlers/builder.rb2
-rw-r--r--actionpack/lib/action_view/template_handlers/compilable.rb2
-rw-r--r--actionpack/lib/action_view/template_handlers/erb.rb2
-rw-r--r--actionpack/lib/action_view/template_handlers/rjs.rb2
-rw-r--r--actionpack/test/activerecord/render_partial_with_record_identification_test.rb31
-rw-r--r--actionpack/test/controller/assert_select_test.rb15
-rw-r--r--actionpack/test/controller/base_test.rb34
-rw-r--r--actionpack/test/controller/mime_type_test.rb7
-rw-r--r--actionpack/test/controller/render_test.rb20
-rw-r--r--actionpack/test/controller/routing_test.rb10
-rw-r--r--actionpack/test/controller/session/mem_cache_store_test.rb5
-rw-r--r--actionpack/test/fixtures/company.rb1
-rw-r--r--actionpack/test/fixtures/db_definitions/sqlite.sql6
-rw-r--r--actionpack/test/fixtures/mascot.rb3
-rw-r--r--actionpack/test/fixtures/mascots.yml4
-rw-r--r--actionpack/test/fixtures/mascots/_mascot.html.erb1
-rw-r--r--actionpack/test/fixtures/reply.rb1
-rw-r--r--actionpack/test/fixtures/shared.html.erb1
-rw-r--r--actionpack/test/fixtures/test/_raise.html.erb1
-rw-r--r--actionpack/test/template/benchmark_helper_test.rb26
-rw-r--r--actionpack/test/template/form_helper_test.rb144
-rw-r--r--actionpack/test/template/template_finder_test.rb5
-rw-r--r--actionpack/test/template/template_object_test.rb5
-rw-r--r--activemodel/lib/active_model/validations.rb20
-rw-r--r--activemodel/lib/active_model/validations/acceptance.rb26
-rw-r--r--activemodel/lib/active_model/validations/associated.rb14
-rw-r--r--activemodel/lib/active_model/validations/confirmation.rb16
-rw-r--r--activemodel/lib/active_model/validations/exclusion.rb16
-rw-r--r--activemodel/lib/active_model/validations/format.rb20
-rw-r--r--activemodel/lib/active_model/validations/inclusion.rb16
-rw-r--r--activemodel/lib/active_model/validations/length.rb43
-rw-r--r--activemodel/lib/active_model/validations/numericality.rb32
-rw-r--r--activemodel/lib/active_model/validations/presence.rb26
-rw-r--r--activemodel/lib/active_model/validations/uniqueness.rb18
-rw-r--r--activerecord/CHANGELOG19
-rwxr-xr-xactiverecord/README22
-rw-r--r--activerecord/RUNNING_UNIT_TESTS5
-rwxr-xr-xactiverecord/Rakefile2
-rw-r--r--activerecord/lib/active_record/association_preload.rb42
-rw-r--r--activerecord/lib/active_record/associations/association_proxy.rb10
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb4
-rwxr-xr-xactiverecord/lib/active_record/base.rb96
-rw-r--r--activerecord/lib/active_record/calculations.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb194
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb84
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/mysql_adapter.rb20
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb8
-rw-r--r--activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb9
-rwxr-xr-xactiverecord/lib/active_record/fixtures.rb6
-rw-r--r--activerecord/lib/active_record/locking/optimistic.rb2
-rw-r--r--activerecord/lib/active_record/locking/pessimistic.rb4
-rw-r--r--activerecord/lib/active_record/migration.rb8
-rw-r--r--activerecord/lib/active_record/named_scope.rb1
-rw-r--r--activerecord/lib/active_record/reflection.rb15
-rw-r--r--activerecord/lib/active_record/serialization.rb10
-rw-r--r--activerecord/lib/active_record/serializers/json_serializer.rb8
-rw-r--r--activerecord/lib/active_record/serializers/xml_serializer.rb30
-rwxr-xr-xactiverecord/lib/active_record/validations.rb221
-rw-r--r--activerecord/test/cases/associations/eager_test.rb49
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb12
-rwxr-xr-xactiverecord/test/cases/base_test.rb25
-rwxr-xr-xactiverecord/test/cases/fixtures_test.rb4
-rw-r--r--activerecord/test/cases/locking_test.rb9
-rw-r--r--activerecord/test/cases/migration_test.rb208
-rw-r--r--activerecord/test/cases/named_scope_test.rb28
-rwxr-xr-xactiverecord/test/cases/validations_test.rb16
-rw-r--r--activerecord/test/fixtures/jobs.yml7
-rw-r--r--activerecord/test/fixtures/references.yml17
-rw-r--r--activerecord/test/fixtures/subscriptions.yml12
-rw-r--r--activerecord/test/models/job.rb5
-rw-r--r--activerecord/test/models/person.rb5
-rw-r--r--activerecord/test/models/reference.rb4
-rwxr-xr-xactiverecord/test/models/reply.rb2
-rw-r--r--activerecord/test/models/subscriber.rb2
-rw-r--r--activerecord/test/models/subscription.rb4
-rwxr-xr-xactiverecord/test/models/topic.rb1
-rw-r--r--activerecord/test/schema/postgresql_specific_schema.rb2
-rw-r--r--activerecord/test/schema/schema.rb17
-rw-r--r--activeresource/CHANGELOG2
-rw-r--r--activeresource/lib/active_resource/base.rb11
-rw-r--r--activeresource/lib/active_resource/connection.rb6
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support/cache.rb19
-rw-r--r--activesupport/lib/active_support/cache/file_store.rb4
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb33
-rw-r--r--activesupport/lib/active_support/cache/memory_store.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb51
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute_accessors.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date_time/calculations.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb21
-rw-r--r--activesupport/lib/active_support/core_ext/hash/reverse_merge.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/kernel/daemonizing.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb12
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/process.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/process/daemon.rb25
-rw-r--r--activesupport/lib/active_support/core_ext/range/include_range.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/range/overlaps.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb10
-rw-r--r--activesupport/lib/active_support/dependencies.rb31
-rw-r--r--activesupport/lib/active_support/inflector.rb27
-rw-r--r--activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb4
-rw-r--r--activesupport/lib/active_support/ordered_options.rb6
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb13
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb439
-rw-r--r--activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb8
-rw-r--r--activesupport/lib/active_support/whiny_nil.rb6
-rw-r--r--activesupport/test/inflector_test.rb10
-rw-r--r--activesupport/test/ordered_options_test.rb13
-rw-r--r--railties/CHANGELOG2
-rw-r--r--railties/lib/commands/servers/mongrel.rb16
-rw-r--r--railties/lib/initializer.rb32
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb4
-rw-r--r--railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb4
-rw-r--r--railties/lib/tasks/databases.rake4
-rw-r--r--railties/test/fixtures/lib/generators/missing_class/templates/.gitignore (renamed from railties/test/fixtures/lib/generators/missing_class/templates/.empty)0
-rw-r--r--railties/test/fixtures/lib/generators/missing_generator/templates/.gitignore (renamed from railties/test/fixtures/lib/generators/missing_generator/templates/.empty)0
-rw-r--r--railties/test/fixtures/lib/generators/missing_templates/.gitignore (renamed from railties/test/fixtures/lib/generators/missing_templates/.empty)0
-rw-r--r--railties/test/fixtures/plugins/alternate/a/lib/.gitignore (renamed from railties/test/fixtures/plugins/alternate/a/lib/.empty)0
-rw-r--r--railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.gitignore (renamed from railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.empty)0
-rw-r--r--railties/test/fixtures/plugins/default/empty/.gitignore (renamed from railties/test/fixtures/plugins/default/empty/.empty)0
163 files changed, 2333 insertions, 1150 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 3dfe828b06..48e877a182 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -198,31 +198,31 @@ module ActionMailer #:nodoc:
#
# These options are specified on the class level, like <tt>ActionMailer::Base.template_root = "/my/templates"</tt>
#
- # * <tt>template_root</tt> - template root determines the base from which template references will be made.
+ # * <tt>template_root</tt> - Determines the base from which template references will be made.
#
# * <tt>logger</tt> - the logger is used for generating information on the mailing run if available.
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
#
- # * <tt>smtp_settings</tt> - Allows detailed configuration for :smtp delivery method:
+ # * <tt>smtp_settings</tt> - Allows detailed configuration for <tt>:smtp</tt> delivery method:
# * <tt>:address</tt> Allows you to use a remote mail server. Just change it from its default "localhost" setting.
# * <tt>:port</tt> On the off chance that your mail server doesn't run on port 25, you can change it.
# * <tt>:domain</tt> If you need to specify a HELO domain, you can do it here.
# * <tt>:user_name</tt> If your mail server requires authentication, set the username in this setting.
# * <tt>:password</tt> If your mail server requires authentication, set the password in this setting.
# * <tt>:authentication</tt> If your mail server requires authentication, you need to specify the authentication type here.
- # This is a symbol and one of :plain, :login, :cram_md5
+ # This is a symbol and one of <tt>:plain</tt>, <tt>:login</tt>, <tt>:cram_md5</tt>
#
- # * <tt>sendmail_settings</tt> - Allows you to override options for the :sendmail delivery method
+ # * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method
# * <tt>:location</tt> The location of the sendmail executable, defaults to "/usr/sbin/sendmail"
# * <tt>:arguments</tt> The command line arguments
# * <tt>raise_delivery_errors</tt> - whether or not errors should be raised if the email fails to be delivered.
#
- # * <tt>delivery_method</tt> - Defines a delivery method. Possible values are :smtp (default), :sendmail, and :test.
+ # * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default), <tt>:sendmail</tt>, and <tt>:test</tt>.
#
# * <tt>perform_deliveries</tt> - Determines whether deliver_* methods are actually carried out. By default they are,
# but this can be turned off to help functional testing.
#
- # * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful
+ # * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with <tt>delivery_method :test</tt>. Most useful
# for unit and functional testing.
#
# * <tt>default_charset</tt> - The default charset used for the body and to encode the subject. Defaults to UTF-8. You can also
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index 5a2122b64b..54030047ba 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,9 @@
*SVN*
+* Fixed that TextHelper#text_field would corrypt when raw HTML was used as the value (mchenryc, Kevin Glowacz) [#80]
+
+* Added ActionController::TestCase#rescue_action_in_public! to control whether the action under test should use the regular rescue_action path instead of simply raising the exception inline (great for error testing) [DHH]
+
* Reduce number of instance variables being copied from controller to view. [Pratik]
* select_datetime and select_time default to Time.zone.now when config.time_zone is set [Geoff Buesing]
diff --git a/actionpack/lib/action_controller/assertions/selector_assertions.rb b/actionpack/lib/action_controller/assertions/selector_assertions.rb
index 573405c0f9..272b8f6841 100644
--- a/actionpack/lib/action_controller/assertions/selector_assertions.rb
+++ b/actionpack/lib/action_controller/assertions/selector_assertions.rb
@@ -263,12 +263,15 @@ module ActionController
if match_with = equals[:text]
matches.delete_if do |match|
text = ""
+ text.force_encoding(match_with.encoding) if text.respond_to?(:force_encoding)
stack = match.children.reverse
while node = stack.pop
if node.tag?
stack.concat node.children.reverse
else
- text << node.content
+ content = node.content
+ content.force_encoding(match_with.encoding) if content.respond_to?(:force_encoding)
+ text << content
end
end
text.strip! unless NO_STRIP.include?(match.name)
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 0c0d0ec4ac..6b5914c4dd 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -277,9 +277,10 @@ module ActionController #:nodoc:
@@debug_routes = true
cattr_accessor :debug_routes
- # Controls whether the application is thread-safe, so multi-threaded servers like WEBrick know whether to apply a mutex
- # around the performance of each action. Action Pack and Active Record are by default thread-safe, but many applications
- # may not be. Turned off by default.
+ # Indicates to Mongrel or Webrick whether to allow concurrent action
+ # processing. Your controller actions and any other code they call must
+ # also behave well when called from concurrent threads. Turned off by
+ # default.
@@allow_concurrency = false
cattr_accessor :allow_concurrency
@@ -331,7 +332,8 @@ module ActionController #:nodoc:
@@resources_path_names = { :new => 'new', :edit => 'edit' }
cattr_accessor :resources_path_names
- # Sets the token parameter name for RequestForgery. Calling #protect_from_forgery sets it to :authenticity_token by default
+ # Sets the token parameter name for RequestForgery. Calling +protect_from_forgery+
+ # sets it to <tt>:authenticity_token</tt> by default.
cattr_accessor :request_forgery_protection_token
# Indicates whether or not optimise the generated named
@@ -530,9 +532,9 @@ module ActionController #:nodoc:
# Returns a URL that has been rewritten according to the options hash and the defined Routes.
# (For doing a complete redirect, use redirect_to).
- #  
+ #
# <tt>url_for</tt> is used to:
- #  
+ #
# All keys given to url_for are forwarded to the Route module, save for the following:
# * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path. For example,
# <tt>url_for :controller => 'posts', :action => 'show', :id => 10, :anchor => 'comments'</tt>
@@ -543,8 +545,8 @@ module ActionController #:nodoc:
# * <tt>:host</tt> -- overrides the default (current) host if provided.
# * <tt>:protocol</tt> -- overrides the default (current) protocol if provided.
# * <tt>:port</tt> -- optionally specify the port to connect to.
- # * <tt>:user</tt> -- Inline HTTP authentication (only plucked out if :password is also present).
- # * <tt>:password</tt> -- Inline HTTP authentication (only plucked out if :user is also present).
+ # * <tt>:user</tt> -- Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present).
+ # * <tt>:password</tt> -- Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present).
# * <tt>:skip_relative_url_root</tt> -- if true, the url is not constructed using the relative_url_root of the request so the path
# will include the web server relative installation directory.
#
@@ -597,7 +599,7 @@ module ActionController #:nodoc:
# url_for :controller => 'posts', :action => nil
#
# If you explicitly want to create a URL that's almost the same as the current URL, you can do so using the
- # :overwrite_params options. Say for your posts you have different views for showing and printing them.
+ # <tt>:overwrite_params</tt> options. Say for your posts you have different views for showing and printing them.
# Then, in the show view, you get the URL for the print view like this
#
# url_for :overwrite_params => { :action => 'print' }
@@ -768,7 +770,7 @@ module ActionController #:nodoc:
# # placed in "app/views/layouts/special.r(html|xml)"
# render :text => "Hi there!", :layout => "special"
#
- # The :text option can also accept a Proc object, which can be used to manually control the page generation. This should
+ # The <tt>:text</tt> option can also accept a Proc object, which can be used to manually control the page generation. This should
# generally be avoided, as it violates the separation between code and content, and because almost everything that can be
# done with this method can also be done more cleanly using one of the other rendering methods, most notably templates.
#
@@ -822,7 +824,7 @@ module ActionController #:nodoc:
#
# === Rendering with status and location headers
#
- # All renders take the :status and :location options and turn them into headers. They can even be used together:
+ # All renders take the <tt>:status</tt> and <tt>:location</tt> options and turn them into headers. They can even be used together:
#
# render :xml => post.to_xml, :status => :created, :location => post_url(post)
def render(options = nil, extra_options = {}, &block) #:doc:
diff --git a/actionpack/lib/action_controller/cookies.rb b/actionpack/lib/action_controller/cookies.rb
index 19847c6957..a4cddbcea2 100644
--- a/actionpack/lib/action_controller/cookies.rb
+++ b/actionpack/lib/action_controller/cookies.rb
@@ -1,31 +1,38 @@
module ActionController #:nodoc:
- # Cookies are read and written through ActionController#cookies. The cookies being read are what were received along with the request,
- # the cookies being written are what will be sent out with the response. Cookies are read by value (so you won't get the cookie object
- # itself back -- just the value it holds). Examples for writing:
+ # Cookies are read and written through ActionController#cookies.
#
- # cookies[:user_name] = "david" # => Will set a simple session cookie
+ # The cookies being read are the ones received along with the request, the cookies
+ # being written will be sent out with the response. Reading a cookie does not get
+ # the cookie object itself back, just the value it holds.
+ #
+ # Examples for writing:
+ #
+ # # Sets a simple session cookie.
+ # cookies[:user_name] = "david"
+ #
+ # # Sets a cookie that expires in 1 hour.
# cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now }
- # # => Will set a cookie that expires in 1 hour
#
# Examples for reading:
#
# cookies[:user_name] # => "david"
- # cookies.size # => 2
+ # cookies.size # => 2
#
# Example for deleting:
#
# cookies.delete :user_name
#
- # All the option symbols for setting cookies are:
+ # The option symbols for setting cookies are:
#
- # * <tt>value</tt> - the cookie's value or list of values (as an array).
- # * <tt>path</tt> - the path for which this cookie applies. Defaults to the root of the application.
- # * <tt>domain</tt> - the domain for which this cookie applies.
- # * <tt>expires</tt> - the time at which this cookie expires, as a +Time+ object.
- # * <tt>secure</tt> - whether this cookie is a secure cookie or not (default to false).
- # Secure cookies are only transmitted to HTTPS servers.
- # * <tt>http_only</tt> - whether this cookie is accessible via scripting or only HTTP (defaults to false).
-
+ # * <tt>:value</tt> - The cookie's value or list of values (as an array).
+ # * <tt>:path</tt> - The path for which this cookie applies. Defaults to the root
+ # of the application.
+ # * <tt>:domain</tt> - The domain for which this cookie applies.
+ # * <tt>:expires</tt> - The time at which this cookie expires, as a Time object.
+ # * <tt>:secure</tt> - Whether this cookie is a only transmitted to HTTPS servers.
+ # Default is +false+.
+ # * <tt>:http_only</tt> - Whether this cookie is accessible via scripting or
+ # only HTTP. Defaults to +false+.
module Cookies
def self.included(base)
base.helper_method :cookies
@@ -45,8 +52,7 @@ module ActionController #:nodoc:
update(@cookies)
end
- # Returns the value of the cookie by +name+ -- or nil if no such cookie exists. You set new cookies using cookies[]=
- # (for simple name/value cookies without options).
+ # Returns the value of the cookie by +name+, or +nil+ if no such cookie exists.
def [](name)
cookie = @cookies[name.to_s]
if cookie && cookie.respond_to?(:value)
@@ -54,6 +60,8 @@ module ActionController #:nodoc:
end
end
+ # Sets the cookie named +name+. The second argument may be the very cookie
+ # value, or a hash of options as documented above.
def []=(name, options)
if options.is_a?(Hash)
options = options.inject({}) { |options, pair| options[pair.first.to_s] = pair.last; options }
@@ -66,14 +74,18 @@ module ActionController #:nodoc:
end
# Removes the cookie on the client machine by setting the value to an empty string
- # and setting its expiration date into the past. Like []=, you can pass in an options
- # hash to delete cookies with extra data such as a +path+.
+ # and setting its expiration date into the past. Like <tt>[]=</tt>, you can pass in
+ # an options hash to delete cookies with extra data such as a <tt>:path</tt>.
def delete(name, options = {})
options.stringify_keys!
set_cookie(options.merge("name" => name.to_s, "value" => "", "expires" => Time.at(0)))
end
private
+ # Builds a CGI::Cookie object and adds the cookie to the response headers.
+ #
+ # The path of the cookie defaults to "/" if there's none in +options+, and
+ # everything is passed to the CGI::Cookie constructor.
def set_cookie(options) #:doc:
options["path"] = "/" unless options["path"]
cookie = CGI::Cookie.new(options)
diff --git a/actionpack/lib/action_controller/filters.rb b/actionpack/lib/action_controller/filters.rb
index 8c97787741..6d0c83eb40 100644
--- a/actionpack/lib/action_controller/filters.rb
+++ b/actionpack/lib/action_controller/filters.rb
@@ -126,8 +126,8 @@ module ActionController #:nodoc:
# end
#
# To use a filter object with around_filter, pass an object responding
- # to :filter or both :before and :after. With a filter method, yield to
- # the block as above:
+ # to <tt>:filter</tt> or both <tt>:before</tt> and <tt>:after</tt>. With a
+ # filter method, yield to the block as above:
#
# around_filter BenchmarkingFilter
#
@@ -191,8 +191,9 @@ module ActionController #:nodoc:
# == Filter conditions
#
# Filters may be limited to specific actions by declaring the actions to
- # include or exclude. Both options accept single actions (:only => :index)
- # or arrays of actions (:except => [:foo, :bar]).
+ # include or exclude. Both options accept single actions
+ # (<tt>:only => :index</tt>) or arrays of actions
+ # (<tt>:except => [:foo, :bar]</tt>).
#
# class Journal < ActionController::Base
# # Require authentication for edit and delete.
diff --git a/actionpack/lib/action_controller/helpers.rb b/actionpack/lib/action_controller/helpers.rb
index 9188f94f37..a8bead4d34 100644
--- a/actionpack/lib/action_controller/helpers.rb
+++ b/actionpack/lib/action_controller/helpers.rb
@@ -143,11 +143,19 @@ module ActionController #:nodoc:
# Declare a controller method as a helper. For example, the following
# makes the +current_user+ controller method available to the view:
# class ApplicationController < ActionController::Base
- # helper_method :current_user
+ # helper_method :current_user, :logged_in?
+ #
# def current_user
- # @current_user ||= User.find(session[:user])
+ # @current_user ||= User.find_by_id(session[:user])
# end
+ #
+ # def logged_in?
+ # current_user != nil
+ # end
# end
+ #
+ # In a view:
+ # <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
def helper_method(*methods)
methods.flatten.each do |method|
master_helper_module.module_eval <<-end_eval
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index 16e3ffc9c1..8c02f20521 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -71,8 +71,11 @@ module Mime
# keep track of creation order to keep the subsequent sort stable
list = []
accept_header.split(/,/).each_with_index do |header, index|
- params = header.split(/;\s*q=/)
- list << AcceptItem.new(index, *params) unless params.empty?
+ params, q = header.split(/;\s*q=/)
+ if params
+ params.strip!
+ list << AcceptItem.new(index, params, q) unless params.empty?
+ end
end
list.sort!
@@ -145,7 +148,7 @@ module Mime
end
def ==(mime_type)
- return false unless mime_type
+ return false if mime_type.blank?
(@synonyms + [ self ]).any? do |synonym|
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
end
diff --git a/actionpack/lib/action_controller/polymorphic_routes.rb b/actionpack/lib/action_controller/polymorphic_routes.rb
index 2cc2ec7723..aa0e05dbd7 100644
--- a/actionpack/lib/action_controller/polymorphic_routes.rb
+++ b/actionpack/lib/action_controller/polymorphic_routes.rb
@@ -19,7 +19,7 @@ module ActionController
# * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
# <tt>url_for(@article)</tt>;
# * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
- # <tt>form_for(@article)</tt> without having to specify :url parameter for the form
+ # <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
# action;
# * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
# <tt>redirect_to(post)</tt> in your controllers;
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index 823271d13f..d5ecbd9d29 100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
@@ -15,7 +15,7 @@ module ActionController
# such as { 'RAILS_ENV' => 'production' }.
attr_reader :env
- # The true HTTP request method as a lowercase symbol, such as :get.
+ # The true HTTP request method as a lowercase symbol, such as <tt>:get</tt>.
# UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.
def request_method
@request_method ||= begin
@@ -28,35 +28,35 @@ module ActionController
end
end
- # The HTTP request method as a lowercase symbol, such as :get.
- # Note, HEAD is returned as :get since the two are functionally
+ # The HTTP request method as a lowercase symbol, such as <tt>:get</tt>.
+ # Note, HEAD is returned as <tt>:get</tt> since the two are functionally
# equivalent from the application's perspective.
def method
request_method == :head ? :get : request_method
end
- # Is this a GET (or HEAD) request? Equivalent to request.method == :get
+ # Is this a GET (or HEAD) request? Equivalent to <tt>request.method == :get</tt>.
def get?
method == :get
end
- # Is this a POST request? Equivalent to request.method == :post
+ # Is this a POST request? Equivalent to <tt>request.method == :post</tt>.
def post?
request_method == :post
end
- # Is this a PUT request? Equivalent to request.method == :put
+ # Is this a PUT request? Equivalent to <tt>request.method == :put</tt>.
def put?
request_method == :put
end
- # Is this a DELETE request? Equivalent to request.method == :delete
+ # Is this a DELETE request? Equivalent to <tt>request.method == :delete</tt>.
def delete?
request_method == :delete
end
- # Is this a HEAD request? request.method sees HEAD as :get, so check the
- # HTTP method directly.
+ # Is this a HEAD request? <tt>request.method</tt> sees HEAD as <tt>:get</tt>,
+ # so check the HTTP method directly.
def head?
request_method == :head
end
diff --git a/actionpack/lib/action_controller/request_forgery_protection.rb b/actionpack/lib/action_controller/request_forgery_protection.rb
index beb987f7ca..7e6961d25f 100644
--- a/actionpack/lib/action_controller/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/request_forgery_protection.rb
@@ -102,7 +102,8 @@ module ActionController #:nodoc:
request.format.html? || request.format.js?
end
- # Sets the token value for the current session. Pass a :secret option in #protect_from_forgery to add a custom salt to the hash.
+ # Sets the token value for the current session. Pass a <tt>:secret</tt> option
+ # in +protect_from_forgery+ to add a custom salt to the hash.
def form_authenticity_token
@form_authenticity_token ||= if request_forgery_protection_options[:secret]
authenticity_token_from_session_id
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb
index d4d561bdb7..5022c9a815 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/rescue.rb
@@ -58,33 +58,35 @@ module ActionController #:nodoc:
# Rescue exceptions raised in controller actions.
#
# <tt>rescue_from</tt> receives a series of exception classes or class
- # names, and a trailing :with option with the name of a method or a Proc
- # object to be called to handle them. Alternatively a block can be given.
+ # names, and a trailing <tt>:with</tt> option with the name of a method
+ # or a Proc object to be called to handle them. Alternatively a block can
+ # be given.
#
# Handlers that take one argument will be called with the exception, so
# that the exception can be inspected when dealing with it.
#
# Handlers are inherited. They are searched from right to left, from
# bottom to top, and up the hierarchy. The handler of the first class for
- # which exception.is_a?(klass) holds true is the one invoked, if any.
+ # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if
+ # any.
#
- # class ApplicationController < ActionController::Base
- # rescue_from User::NotAuthorized, :with => :deny_access # self defined exception
- # rescue_from ActiveRecord::RecordInvalid, :with => :show_errors
+ # class ApplicationController < ActionController::Base
+ # rescue_from User::NotAuthorized, :with => :deny_access # self defined exception
+ # rescue_from ActiveRecord::RecordInvalid, :with => :show_errors
#
- # rescue_from 'MyAppError::Base' do |exception|
- # render :xml => exception, :status => 500
- # end
- #
- # protected
- # def deny_access
- # ...
+ # rescue_from 'MyAppError::Base' do |exception|
+ # render :xml => exception, :status => 500
# end
#
- # def show_errors(exception)
- # exception.record.new_record? ? ...
- # end
- # end
+ # protected
+ # def deny_access
+ # ...
+ # end
+ #
+ # def show_errors(exception)
+ # exception.record.new_record? ? ...
+ # end
+ # end
def rescue_from(*klasses, &block)
options = klasses.extract_options!
unless options.has_key?(:with)
@@ -165,7 +167,7 @@ module ActionController #:nodoc:
# method if you wish to redefine the meaning of a local request to
# include remote IP addresses or other criteria.
def local_request? #:doc:
- request.remote_addr == LOCALHOST and request.remote_ip == LOCALHOST
+ request.remote_addr == LOCALHOST && request.remote_ip == LOCALHOST
end
# Render detailed diagnostics for unhandled exceptions rescued from
diff --git a/actionpack/lib/action_controller/resources.rb b/actionpack/lib/action_controller/resources.rb
index d3cedfdac7..0f0fa27d74 100644
--- a/actionpack/lib/action_controller/resources.rb
+++ b/actionpack/lib/action_controller/resources.rb
@@ -240,12 +240,12 @@ module ActionController
# * <tt>:collection</tt> - add named routes for other actions that operate on the collection.
# Takes a hash of <tt>#{action} => #{method}</tt>, where method is <tt>:get</tt>/<tt>:post</tt>/<tt>:put</tt>/<tt>:delete</tt>
# or <tt>:any</tt> if the method does not matter. These routes map to a URL like /messages/rss, with a route of rss_messages_url.
- # * <tt>:member</tt> - same as :collection, but for actions that operate on a specific member.
- # * <tt>:new</tt> - same as :collection, but for actions that operate on the new resource action.
+ # * <tt>:member</tt> - same as <tt>:collection</tt>, but for actions that operate on a specific member.
+ # * <tt>:new</tt> - same as <tt>:collection</tt>, but for actions that operate on the new resource action.
# * <tt>:controller</tt> - specify the controller name for the routes.
# * <tt>:singular</tt> - specify the singular name used in the member routes.
# * <tt>:requirements</tt> - set custom routing parameter requirements.
- # * <tt>:conditions</tt> - specify custom routing recognition conditions. Resources sets the :method value for the method-specific routes.
+ # * <tt>:conditions</tt> - specify custom routing recognition conditions. Resources sets the <tt>:method</tt> value for the method-specific routes.
# * <tt>:as</tt> - specify a different resource name to use in the URL path. For example:
# # products_path == '/productos'
# map.resources :products, :as => 'productos' do |product|
@@ -254,7 +254,7 @@ module ActionController
# end
#
# * <tt>:has_one</tt> - specify nested resources, this is a shorthand for mapping singleton resources beneath the current.
- # * <tt>:has_many</tt> - same has :has_one, but for plural resources.
+ # * <tt>:has_many</tt> - same has <tt>:has_one</tt>, but for plural resources.
#
# You may directly specify the routing association with has_one and has_many like:
#
@@ -288,7 +288,7 @@ module ActionController
# article.resources :comments
# end
#
- # The comment resources work the same, but must now include a value for :article_id.
+ # The comment resources work the same, but must now include a value for <tt>:article_id</tt>.
#
# article_comments_url(@article)
# article_comment_url(@article, @comment)
@@ -302,7 +302,7 @@ module ActionController
# map.resources :tags, :path_prefix => '/books/:book_id', :name_prefix => 'book_'
# map.resources :tags, :path_prefix => '/toys/:toy_id', :name_prefix => 'toy_'
#
- # You may also use :name_prefix to override the generic named routes in a nested resource:
+ # You may also use <tt>:name_prefix</tt> to override the generic named routes in a nested resource:
#
# map.resources :articles do |article|
# article.resources :comments, :name_prefix => nil
@@ -364,7 +364,7 @@ module ActionController
#
# See map.resources for general conventions. These are the main differences:
# * A singular name is given to map.resource. The default controller name is still taken from the plural name.
- # * To specify a custom plural name, use the :plural option. There is no :singular option.
+ # * To specify a custom plural name, use the <tt>:plural</tt> option. There is no <tt>:singular</tt> option.
# * No default index route is created for the singleton resource controller.
# * When nesting singleton resources, only the singular name is used as the path prefix (example: 'account/messages/1')
#
diff --git a/actionpack/lib/action_controller/routing.rb b/actionpack/lib/action_controller/routing.rb
index fa5a347db9..0bffe21431 100644
--- a/actionpack/lib/action_controller/routing.rb
+++ b/actionpack/lib/action_controller/routing.rb
@@ -23,7 +23,8 @@ module ActionController
# map.connect ':controller/:action/:id'
#
# This route states that it expects requests to consist of a
- # :controller followed by an :action that in turn is fed some :id.
+ # <tt>:controller</tt> followed by an <tt>:action</tt> that in turn is fed
+ # some <tt>:id</tt>.
#
# Suppose you get an incoming request for <tt>/blog/edit/22</tt>, you'll end up
# with:
@@ -36,11 +37,11 @@ module ActionController
# Think of creating routes as drawing a map for your requests. The map tells
# them where to go based on some predefined pattern:
#
- # ActionController::Routing::Routes.draw do |map|
- # Pattern 1 tells some request to go to one place
- # Pattern 2 tell them to go to another
- # ...
- # end
+ # ActionController::Routing::Routes.draw do |map|
+ # Pattern 1 tells some request to go to one place
+ # Pattern 2 tell them to go to another
+ # ...
+ # end
#
# The following symbols are special:
#
@@ -59,12 +60,12 @@ module ActionController
# Within blocks, the empty pattern is at the highest priority.
# In practice this works out nicely:
#
- # ActionController::Routing::Routes.draw do |map|
- # map.with_options :controller => 'blog' do |blog|
- # blog.show '', :action => 'list'
- # end
- # map.connect ':controller/:action/:view'
- # end
+ # ActionController::Routing::Routes.draw do |map|
+ # map.with_options :controller => 'blog' do |blog|
+ # blog.show '', :action => 'list'
+ # end
+ # map.connect ':controller/:action/:view'
+ # end
#
# In this case, invoking blog controller (with an URL like '/blog/')
# without parameters will activate the 'list' action by default.
@@ -75,9 +76,10 @@ module ActionController
# Hash at the end of your mapping to set any default parameters.
#
# Example:
- # ActionController::Routing:Routes.draw do |map|
- # map.connect ':controller/:action/:id', :controller => 'blog'
- # end
+ #
+ # ActionController::Routing:Routes.draw do |map|
+ # map.connect ':controller/:action/:id', :controller => 'blog'
+ # end
#
# This sets up +blog+ as the default controller if no other is specified.
# This means visiting '/' would invoke the blog controller.
@@ -93,6 +95,7 @@ module ActionController
# for the full URL and +name_of_route_path+ for the URI path.
#
# Example:
+ #
# # In routes.rb
# map.login 'login', :controller => 'accounts', :action => 'login'
#
@@ -138,22 +141,23 @@ module ActionController
#
# Routes can generate pretty URLs. For example:
#
- # map.connect 'articles/:year/:month/:day',
- # :controller => 'articles',
- # :action => 'find_by_date',
- # :year => /\d{4}/,
- # :month => /\d{1,2}/,
- # :day => /\d{1,2}/
+ # map.connect 'articles/:year/:month/:day',
+ # :controller => 'articles',
+ # :action => 'find_by_date',
+ # :year => /\d{4}/,
+ # :month => /\d{1,2}/,
+ # :day => /\d{1,2}/
+ #
+ # Using the route above, the URL "http://localhost:3000/articles/2005/11/06"
+ # maps to
#
- # # Using the route above, the url below maps to:
- # # params = {:year => '2005', :month => '11', :day => '06'}
- # # http://localhost:3000/articles/2005/11/06
+ # params = {:year => '2005', :month => '11', :day => '06'}
#
# == Regular Expressions and parameters
# You can specify a regular expression to define a format for a parameter.
#
- # map.geocode 'geocode/:postalcode', :controller => 'geocode',
- # :action => 'show', :postalcode => /\d{5}(-\d{4})?/
+ # map.geocode 'geocode/:postalcode', :controller => 'geocode',
+ # :action => 'show', :postalcode => /\d{5}(-\d{4})?/
#
# or, more formally:
#
@@ -182,7 +186,7 @@ module ActionController
#
# Specifying <tt>*[string]</tt> as part of a rule like:
#
- # map.connect '*path' , :controller => 'blog' , :action => 'unrecognized?'
+ # map.connect '*path' , :controller => 'blog' , :action => 'unrecognized?'
#
# will glob all remaining parts of the route that were not recognized earlier. This idiom
# must appear at the end of the path. The globbed values are in <tt>params[:path]</tt> in
@@ -210,7 +214,7 @@ module ActionController
#
# You can reload routes if you feel you must:
#
- # ActionController::Routing::Routes.reload
+ # ActionController::Routing::Routes.reload
#
# This will clear all named routes and reload routes.rb if the file has been modified from
# last load. To absolutely force reloading, use +reload!+.
@@ -221,19 +225,19 @@ module ActionController
#
# === +assert_routing+
#
- # def test_movie_route_properly_splits
- # opts = {:controller => "plugin", :action => "checkout", :id => "2"}
- # assert_routing "plugin/checkout/2", opts
- # end
+ # def test_movie_route_properly_splits
+ # opts = {:controller => "plugin", :action => "checkout", :id => "2"}
+ # assert_routing "plugin/checkout/2", opts
+ # end
#
# +assert_routing+ lets you test whether or not the route properly resolves into options.
#
# === +assert_recognizes+
#
- # def test_route_has_options
- # opts = {:controller => "plugin", :action => "show", :id => "12"}
- # assert_recognizes opts, "/plugins/show/12"
- # end
+ # def test_route_has_options
+ # opts = {:controller => "plugin", :action => "show", :id => "12"}
+ # assert_recognizes opts, "/plugins/show/12"
+ # end
#
# Note the subtle difference between the two: +assert_routing+ tests that
# a URL fits options while +assert_recognizes+ tests that a URL
@@ -241,16 +245,16 @@ module ActionController
#
# In tests you can simply pass the URL or named route to +get+ or +post+.
#
- # def send_to_jail
- # get '/jail'
- # assert_response :success
- # assert_template "jail/front"
- # end
+ # def send_to_jail
+ # get '/jail'
+ # assert_response :success
+ # assert_template "jail/front"
+ # end
#
- # def goes_to_login
- # get login_url
- # #...
- # end
+ # def goes_to_login
+ # get login_url
+ # #...
+ # end
#
# == View a list of all your routes
#
diff --git a/actionpack/lib/action_controller/routing/builder.rb b/actionpack/lib/action_controller/routing/builder.rb
index 50064055f4..b1a98d1a51 100644
--- a/actionpack/lib/action_controller/routing/builder.rb
+++ b/actionpack/lib/action_controller/routing/builder.rb
@@ -124,7 +124,7 @@ module ActionController
route_requirements
end
- # Assign default options, such as 'index' as a default for :action. This
+ # Assign default options, such as 'index' as a default for <tt>:action</tt>. This
# method must be run *after* user supplied requirements and defaults have
# been applied to the segments.
def assign_default_route_options(segments)
@@ -187,7 +187,7 @@ module ActionController
end
# Routes cannot use the current string interpolation method
- # if there are user-supplied :requirements as the interpolation
+ # if there are user-supplied <tt>:requirements</tt> as the interpolation
# code won't raise RoutingErrors when generating
if options.key?(:requirements) || route.requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION
route.optimise = false
diff --git a/actionpack/lib/action_controller/routing/optimisations.rb b/actionpack/lib/action_controller/routing/optimisations.rb
index ba4aeb4e82..3e3a2225f0 100644
--- a/actionpack/lib/action_controller/routing/optimisations.rb
+++ b/actionpack/lib/action_controller/routing/optimisations.rb
@@ -1,11 +1,11 @@
module ActionController
module Routing
# Much of the slow performance from routes comes from the
- # complexity of expiry, :requirements matching, defaults providing
+ # complexity of expiry, <tt>:requirements</tt> matching, defaults providing
# and figuring out which url pattern to use. With named routes
# we can avoid the expense of finding the right route. So if
# they've provided the right number of arguments, and have no
- # :requirements, we can just build up a string and return it.
+ # <tt>:requirements</tt>, we can just build up a string and return it.
#
# To support building optimisations for other common cases, the
# generation code is separated into several classes
@@ -41,28 +41,29 @@ module ActionController
end
end
- # Temporarily disabled :url optimisation pending proper solution to
+ # Temporarily disabled <tt>:url</tt> optimisation pending proper solution to
# Issues around request.host etc.
def applicable?
true
end
end
- # Given a route:
- # map.person '/people/:id'
+ # Given a route
#
- # If the user calls person_url(@person), we can simply
+ # map.person '/people/:id'
+ #
+ # If the user calls <tt>person_url(@person)</tt>, we can simply
# return a string like "/people/#{@person.to_param}"
- # rather than triggering the expensive logic in url_for
+ # rather than triggering the expensive logic in +url_for+.
class PositionalArguments < Optimiser
def guard_condition
number_of_arguments = route.segment_keys.size
# if they're using foo_url(:id=>2) it's one
# argument, but we don't want to generate /foos/id2
if number_of_arguments == 1
- "defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)"
+ "(!defined?(default_url_options) || default_url_options(nil).blank?) && defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)"
else
- "defined?(request) && request && args.size == #{number_of_arguments}"
+ "(!defined?(default_url_options) || default_url_options(nil).blank?) && defined?(request) && request && args.size == #{number_of_arguments}"
end
end
@@ -77,7 +78,7 @@ module ActionController
elements << '#{request.relative_url_root if request.relative_url_root}'
- # The last entry in route.segments appears to # *always* be a
+ # The last entry in <tt>route.segments</tt> appears to *always* be a
# 'divider segment' for '/' but we have assertions to ensure that
# we don't include the trailing slashes, so skip them.
(route.segments.size == 1 ? route.segments : route.segments[0..-2]).each do |segment|
@@ -97,7 +98,7 @@ module ActionController
# argument
class PositionalArgumentsWithAdditionalParams < PositionalArguments
def guard_condition
- "defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)"
+ "(!defined?(default_url_options) || default_url_options(nil).blank?) && defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)"
end
# This case uses almost the same code as positional arguments,
@@ -106,7 +107,7 @@ module ActionController
super.insert(-2, '?#{args.last.to_query}')
end
- # To avoid generating http://localhost/?host=foo.example.com we
+ # To avoid generating "http://localhost/?host=foo.example.com" we
# can't use this optimisation on routes without any segments
def applicable?
super && route.segment_keys.size > 0
diff --git a/actionpack/lib/action_controller/routing/route.rb b/actionpack/lib/action_controller/routing/route.rb
index a83a599e35..a0d108ba03 100644
--- a/actionpack/lib/action_controller/routing/route.rb
+++ b/actionpack/lib/action_controller/routing/route.rb
@@ -139,8 +139,8 @@ module ActionController
# those that were not used to generate a particular route. The extra
# keys also do not include those recalled from the prior request, nor
# do they include any keys that were implied in the route (like a
- # :controller that is required, but not explicitly used in the text of
- # the route.)
+ # <tt>:controller</tt> that is required, but not explicitly used in the
+ # text of the route.)
def extra_keys(hash, recall={})
(hash || {}).keys.map { |k| k.to_sym } - (recall || {}).keys - significant_keys
end
diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb
index 6ba1a5c3ea..5bc13cf268 100644
--- a/actionpack/lib/action_controller/routing/route_set.rb
+++ b/actionpack/lib/action_controller/routing/route_set.rb
@@ -189,7 +189,7 @@ module ActionController
end
end
- attr_accessor :routes, :named_routes
+ attr_accessor :routes, :named_routes, :configuration_file
def initialize
self.routes = []
@@ -238,8 +238,8 @@ module ActionController
alias reload! load!
def reload
- if @routes_last_modified && defined?(RAILS_ROOT)
- mtime = File.stat("#{RAILS_ROOT}/config/routes.rb").mtime
+ if @routes_last_modified && configuration_file
+ mtime = File.stat(configuration_file).mtime
# if it hasn't been changed, then just return
return if mtime == @routes_last_modified
# if it has changed then record the new time and fall to the load! below
@@ -249,9 +249,9 @@ module ActionController
end
def load_routes!
- if defined?(RAILS_ROOT) && defined?(::ActionController::Routing::Routes) && self == ::ActionController::Routing::Routes
- load File.join("#{RAILS_ROOT}/config/routes.rb")
- @routes_last_modified = File.stat("#{RAILS_ROOT}/config/routes.rb").mtime
+ if configuration_file
+ load configuration_file
+ @routes_last_modified = File.stat(configuration_file).mtime
else
add_route ":controller/:action/:id"
end
diff --git a/actionpack/lib/action_controller/session/cookie_store.rb b/actionpack/lib/action_controller/session/cookie_store.rb
index 5e5ef1bfb0..560491f996 100644
--- a/actionpack/lib/action_controller/session/cookie_store.rb
+++ b/actionpack/lib/action_controller/session/cookie_store.rb
@@ -14,27 +14,27 @@ require 'openssl' # to generate the HMAC message digest
# TamperedWithCookie is raised if the data integrity check fails.
#
# A message digest is included with the cookie to ensure data integrity:
-# a user cannot alter his user_id without knowing the secret key included in
+# a user cannot alter his +user_id+ without knowing the secret key included in
# the hash. New apps are generated with a pregenerated secret in
# config/environment.rb. Set your own for old apps you're upgrading.
#
# Session options:
-# :secret An application-wide key string or block returning a string
-# called per generated digest. The block is called with the
-# CGI::Session instance as an argument. It's important that the
-# secret is not vulnerable to a dictionary attack. Therefore,
-# you should choose a secret consisting of random numbers and
-# letters and more than 30 characters.
#
-# Example: :secret => '449fe2e7daee471bffae2fd8dc02313d'
-# :secret => Proc.new { User.current_user.secret_key }
+# * <tt>:secret</tt>: An application-wide key string or block returning a string
+# called per generated digest. The block is called with the CGI::Session
+# instance as an argument. It's important that the secret is not vulnerable to
+# a dictionary attack. Therefore, you should choose a secret consisting of
+# random numbers and letters and more than 30 characters. Examples:
#
-# :digest The message digest algorithm used to verify session integrity
-# defaults to 'SHA1' but may be any digest provided by OpenSSL,
-# such as 'MD5', 'RIPEMD160', 'SHA256', etc.
+# :secret => '449fe2e7daee471bffae2fd8dc02313d'
+# :secret => Proc.new { User.current_user.secret_key }
+#
+# * <tt>:digest</tt>: The message digest algorithm used to verify session
+# integrity defaults to 'SHA1' but may be any digest provided by OpenSSL,
+# such as 'MD5', 'RIPEMD160', 'SHA256', etc.
#
# To generate a secret key for an existing application, run
-# `rake secret` and set the key in config/environment.rb
+# `rake secret` and set the key in config/environment.rb.
#
# Note that changing digest or secret invalidates all existing sessions!
class CGI::Session::CookieStore
diff --git a/actionpack/lib/action_controller/session_management.rb b/actionpack/lib/action_controller/session_management.rb
index fabb6e7f60..8680104420 100644
--- a/actionpack/lib/action_controller/session_management.rb
+++ b/actionpack/lib/action_controller/session_management.rb
@@ -16,9 +16,11 @@ module ActionController #:nodoc:
end
module ClassMethods
- # Set the session store to be used for keeping the session data between requests. By default, sessions are stored
- # in browser cookies (:cookie_store), but you can also specify one of the other included stores
- # (:active_record_store, :p_store, drb_store, :mem_cache_store, or :memory_store) or your own custom class.
+ # Set the session store to be used for keeping the session data between requests.
+ # By default, sessions are stored in browser cookies (<tt>:cookie_store</tt>),
+ # but you can also specify one of the other included stores (<tt>:active_record_store</tt>,
+ # <tt>:p_store</tt>, <tt>:drb_store</tt>, <tt>:mem_cache_store</tt>, or
+ # <tt>:memory_store</tt>) or your own custom class.
def session_store=(store)
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] =
store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store
diff --git a/actionpack/lib/action_controller/streaming.rb b/actionpack/lib/action_controller/streaming.rb
index b8e7ba2ac9..186e0e5531 100644
--- a/actionpack/lib/action_controller/streaming.rb
+++ b/actionpack/lib/action_controller/streaming.rb
@@ -17,24 +17,24 @@ module ActionController #:nodoc:
# it feasible to send even large files.
#
# Be careful to sanitize the path parameter if it coming from a web
- # page. send_file(params[:path]) allows a malicious user to
+ # page. <tt>send_file(params[:path])</tt> allows a malicious user to
# download any file on your server.
#
# Options:
# * <tt>:filename</tt> - suggests a filename for the browser to use.
- # Defaults to File.basename(path).
+ # Defaults to <tt>File.basename(path)</tt>.
# * <tt>:type</tt> - specifies an HTTP content type.
# Defaults to 'application/octet-stream'.
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
# Valid values are 'inline' and 'attachment' (default).
- # * <tt>:stream</tt> - whether to send the file to the user agent as it is read (true)
- # or to read the entire file before sending (false). Defaults to true.
+ # * <tt>:stream</tt> - whether to send the file to the user agent as it is read (+true+)
+ # or to read the entire file before sending (+false+). Defaults to +true+.
# * <tt>:buffer_size</tt> - specifies size (in bytes) of the buffer used to stream the file.
# Defaults to 4096.
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
- # * <tt>:url_based_filename</tt> - set to true if you want the browser guess the filename from
+ # * <tt>:url_based_filename</tt> - set to +true+ if you want the browser guess the filename from
# the URL, which is necessary for i18n filenames on certain browsers
- # (setting :filename overrides this option).
+ # (setting <tt>:filename</tt> overrides this option).
#
# The default Content-Type and Content-Disposition headers are
# set to download arbitrary binary files in as many browsers as
@@ -42,17 +42,20 @@ module ActionController #:nodoc:
# a variety of quirks (especially when downloading over SSL).
#
# Simple download:
+ #
# send_file '/path/to.zip'
#
# Show a JPEG in the browser:
+ #
# send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
#
# Show a 404 page in the browser:
+ #
# send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
#
# Read about the other Content-* HTTP headers if you'd like to
- # provide the user with more information (such as Content-Description).
- # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11
+ # provide the user with more information (such as Content-Description) in
+ # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11.
#
# Also be aware that the document may be cached by proxies and browsers.
# The Pragma and Cache-Control headers declare how the file may be cached
@@ -95,7 +98,7 @@ module ActionController #:nodoc:
# and specify whether to show data inline or download as an attachment.
#
# Options:
- # * <tt>:filename</tt> - Suggests a filename for the browser to use.
+ # * <tt>:filename</tt> - suggests a filename for the browser to use.
# * <tt>:type</tt> - specifies an HTTP content type.
# Defaults to 'application/octet-stream'.
# * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
@@ -103,12 +106,15 @@ module ActionController #:nodoc:
# * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
#
# Generic data download:
+ #
# send_data buffer
#
# Download a dynamically-generated tarball:
+ #
# send_data generate_tgz('dir'), :filename => 'dir.tgz'
#
# Display an image Active Record in the browser:
+ #
# send_data image.data, :type => image.content_type, :disposition => 'inline'
#
# See +send_file+ for more information on HTTP Content-* headers and caching.
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 06b12a524f..77c6f26eac 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -16,9 +16,23 @@ module ActionController
end
class TestCase < ActiveSupport::TestCase
+ # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
+ # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
+ # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
+ # than 0.0.0.0.
+ #
+ # The exception is stored in the exception accessor for further inspection.
module RaiseActionExceptions
+ attr_accessor :exception
+
def rescue_action(e)
- raise e
+ self.exception = e
+
+ if request.remote_addr == "0.0.0.0"
+ raise(e)
+ else
+ super(e)
+ end
end
end
@@ -60,5 +74,10 @@ module ActionController
@controller.request = @request = TestRequest.new
@response = TestResponse.new
end
+
+ # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
+ def rescue_action_in_public!
+ @request.remote_addr = '208.77.188.166' # example.com
+ end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb
index f8af3ccaf2..dcb6cdf4ca 100644
--- a/actionpack/lib/action_controller/test_process.rb
+++ b/actionpack/lib/action_controller/test_process.rb
@@ -155,12 +155,12 @@ module ActionController #:nodoc:
# A refactoring of TestResponse to allow the same behavior to be applied
# to the "real" CgiResponse class in integration tests.
module TestResponseBehavior #:nodoc:
- # the response code of the request
+ # The response code of the request
def response_code
headers['Status'][0,3].to_i rescue 0
end
- # returns a String to ensure compatibility with Net::HTTPResponse
+ # Returns a String to ensure compatibility with Net::HTTPResponse
def code
headers['Status'].to_s.split(' ')[0]
end
@@ -169,34 +169,34 @@ module ActionController #:nodoc:
headers['Status'].to_s.split(' ',2)[1]
end
- # was the response successful?
+ # Was the response successful?
def success?
response_code == 200
end
- # was the URL not found?
+ # Was the URL not found?
def missing?
response_code == 404
end
- # were we redirected?
+ # Were we redirected?
def redirect?
(300..399).include?(response_code)
end
- # was there a server-side error?
+ # Was there a server-side error?
def error?
(500..599).include?(response_code)
end
alias_method :server_error?, :error?
- # returns the redirection location or nil
+ # Returns the redirection location or nil
def redirect_url
headers['Location']
end
- # does the redirect location match this regexp pattern?
+ # Does the redirect location match this regexp pattern?
def redirect_url_match?( pattern )
return false if redirect_url.nil?
p = Regexp.new(pattern) if pattern.class == String
@@ -205,7 +205,7 @@ module ActionController #:nodoc:
p.match(redirect_url) != nil
end
- # returns the template path of the file which was used to
+ # Returns the template path of the file which was used to
# render this response (or nil)
def rendered_file(with_controller=false)
unless template.first_render.nil?
@@ -217,50 +217,49 @@ module ActionController #:nodoc:
end
end
- # was this template rendered by a file?
+ # Was this template rendered by a file?
def rendered_with_file?
!rendered_file.nil?
end
- # a shortcut to the flash (or an empty hash if no flash.. hey! that rhymes!)
+ # A shortcut to the flash. Returns an empyt hash if no session flash exists.
def flash
session['flash'] || {}
end
- # do we have a flash?
+ # Do we have a flash?
def has_flash?
!session['flash'].empty?
end
- # do we have a flash that has contents?
+ # Do we have a flash that has contents?
def has_flash_with_contents?
!flash.empty?
end
- # does the specified flash object exist?
+ # Does the specified flash object exist?
def has_flash_object?(name=nil)
!flash[name].nil?
end
- # does the specified object exist in the session?
+ # Does the specified object exist in the session?
def has_session_object?(name=nil)
!session[name].nil?
end
- # a shortcut to the template.assigns
+ # A shortcut to the template.assigns
def template_objects
template.assigns || {}
end
- # does the specified template object exist?
+ # Does the specified template object exist?
def has_template_object?(name=nil)
!template_objects[name].nil?
end
# Returns the response cookies, converted to a Hash of (name => CGI::Cookie) pairs
- # Example:
#
- # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value
+ # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value
def cookies
headers['cookie'].inject({}) { |hash, cookie| hash[cookie.name] = cookie; hash }
end
@@ -465,10 +464,13 @@ module ActionController #:nodoc:
return super
end
- # Shortcut for ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type). Example:
+ # Shortcut for <tt>ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type)</tt>:
+ #
# post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
#
- # To upload binary files on Windows, pass :binary as the last parameter. This will not affect other platforms.
+ # To upload binary files on Windows, pass <tt>:binary</tt> as the last parameter.
+ # This will not affect other platforms:
+ #
# post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
def fixture_file_upload(path, mime_type = nil, binary = false)
ActionController::TestUploadedFile.new(
@@ -483,17 +485,17 @@ module ActionController #:nodoc:
# with a new RouteSet instance.
#
# The new instance is yielded to the passed block. Typically the block
- # will create some routes using map.draw { map.connect ... }:
+ # will create some routes using <tt>map.draw { map.connect ... }</tt>:
#
- # with_routing do |set|
- # set.draw do |map|
- # map.connect ':controller/:action/:id'
- # assert_equal(
- # ['/content/10/show', {}],
- # map.generate(:controller => 'content', :id => 10, :action => 'show')
- # end
- # end
- # end
+ # with_routing do |set|
+ # set.draw do |map|
+ # map.connect ':controller/:action/:id'
+ # assert_equal(
+ # ['/content/10/show', {}],
+ # map.generate(:controller => 'content', :id => 10, :action => 'show')
+ # end
+ # end
+ # end
#
def with_routing
real_routes = ActionController::Routing::Routes
diff --git a/actionpack/lib/action_controller/url_rewriter.rb b/actionpack/lib/action_controller/url_rewriter.rb
index 6f7e0cea09..b143806818 100644
--- a/actionpack/lib/action_controller/url_rewriter.rb
+++ b/actionpack/lib/action_controller/url_rewriter.rb
@@ -15,8 +15,8 @@ module ActionController
# In addition to providing +url_for+, named routes are also accessible after
# including UrlWriter.
module UrlWriter
- # The default options for urls written by this writer. Typically a :host pair
- # is provided.
+ # The default options for urls written by this writer. Typically a <tt>:host</tt>
+ # pair is provided.
mattr_accessor :default_url_options
self.default_url_options = {}
@@ -29,16 +29,19 @@ module ActionController
# Generate a url based on the options provided, default_url_options and the
# routes defined in routes.rb. The following options are supported:
#
- # * <tt>:only_path</tt> If true, the relative url is returned. Defaults to false.
+ # * <tt>:only_path</tt> If true, the relative url is returned. Defaults to +false+.
# * <tt>:protocol</tt> The protocol to connect to. Defaults to 'http'.
- # * <tt>:host</tt> Specifies the host the link should be targetted at. If <tt>:only_path</tt> is false, this option must be
- # provided either explicitly, or via default_url_options.
+ # * <tt>:host</tt> Specifies the host the link should be targetted at.
+ # If <tt>:only_path</tt> is false, this option must be
+ # provided either explicitly, or via +default_url_options+.
# * <tt>:port</tt> Optionally specify the port to connect to.
# * <tt>:anchor</tt> An anchor name to be appended to the path.
- # * <tt>:skip_relative_url_root</tt> If true, the url is not constructed using the relative_url_root set in <tt>ActionController::AbstractRequest.relative_url_root</tt>.
+ # * <tt>:skip_relative_url_root</tt> If true, the url is not constructed using the
+ # +relative_url_root+ set in ActionController::AbstractRequest.relative_url_root.
# * <tt>:trailing_slash</tt> If true, adds a trailing slash, as in "/archive/2009/"
#
- # Any other key(:controller, :action, etc...) given to <tt>url_for</tt> is forwarded to the Routes module.
+ # Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
+ # +url_for+ is forwarded to the Routes module.
#
# Examples:
#
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 4ed20fec89..a6da81de07 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -242,18 +242,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
END_ERROR
end
- template = Template.new(self, template_path, use_full_path, local_assigns)
-
- begin
- render_template(template)
- rescue Exception => e
- if TemplateError === e
- e.sub_template_of(template.filename)
- raise e
- else
- raise TemplateError.new(template, @assigns, e)
- end
- end
+ Template.new(self, template_path, use_full_path, local_assigns).render_template
end
# Renders the template present at <tt>template_path</tt> (relative to the view_paths array).
@@ -290,7 +279,7 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
end
def render_template(template) #:nodoc:
- template.render
+ template.render_template
end
# Returns true is the file may be rendered implicitly.
@@ -298,9 +287,10 @@ If you are rendering a subtemplate, you must now use controller-like partial syn
template_path.split('/').last[0,1] != '_'
end
- # symbolized version of the :format parameter of the request, or :html by default.
+ # Returns a symbolized version of the <tt>:format</tt> parameter of the request,
+ # or <tt>:html</tt> by default.
#
- # EXCEPTION: If the :format parameter is not set, the Accept header will be examined for
+ # EXCEPTION: If the <tt>:format</tt> parameter is not set, the Accept header will be examined for
# whether it contains the JavaScript mime type as its first priority. If that's the case,
# it will be used. This ensures that Ajax applications can use the same URL to support both
# JavaScript and non-JavaScript users.
diff --git a/actionpack/lib/action_view/helpers/active_record_helper.rb b/actionpack/lib/action_view/helpers/active_record_helper.rb
index 7569cc381d..f3f204cc97 100644
--- a/actionpack/lib/action_view/helpers/active_record_helper.rb
+++ b/actionpack/lib/action_view/helpers/active_record_helper.rb
@@ -8,47 +8,55 @@ module ActionView
end
module Helpers
- # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the form
+ # The Active Record Helper makes it easier to create forms for records kept in instance variables. The most far-reaching is the +form+
# method that creates a complete form for all the basic content types of the record (not associations or aggregations, though). This
# is a great way of making the record quickly available for editing, but likely to prove lackluster for a complicated real-world form.
- # In that case, it's better to use the input method and the specialized form methods in link:classes/ActionView/Helpers/FormHelper.html
+ # In that case, it's better to use the +input+ method and the specialized +form+ methods in link:classes/ActionView/Helpers/FormHelper.html
module ActiveRecordHelper
- # Returns a default input tag for the type of object returned by the method. For example, let's say you have a model
- # that has an attribute +title+ of type VARCHAR column, and this instance holds "Hello World":
- # input("post", "title") =>
- # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
+ # Returns a default input tag for the type of object returned by the method. For example, if <tt>@post</tt>
+ # has an attribute +title+ mapped to a +VARCHAR+ column that holds "Hello World":
+ #
+ # input("post", "title")
+ # # => <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
def input(record_name, method, options = {})
InstanceTag.new(record_name, method, self).to_tag(options)
end
- # Returns an entire form with all needed input tags for a specified Active Record object. For example, let's say you
- # have a table model <tt>Post</tt> with attributes named <tt>title</tt> of type <tt>VARCHAR</tt> and <tt>body</tt> of type <tt>TEXT</tt>:
+ # Returns an entire form with all needed input tags for a specified Active Record object. For example, if <tt>@post</tt>
+ # has attributes named +title+ of type +VARCHAR+ and +body+ of type +TEXT+ then
+ #
# form("post")
- # That line would yield a form like the following:
- # <form action='/post/create' method='post'>
- # <p>
- # <label for="post_title">Title</label><br />
- # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
- # </p>
- # <p>
- # <label for="post_body">Body</label><br />
- # <textarea cols="40" id="post_body" name="post[body]" rows="20">
- # </textarea>
- # </p>
- # <input type='submit' value='Create' />
- # </form>
+ #
+ # would yield a form like the following (modulus formatting):
+ #
+ # <form action='/posts/create' method='post'>
+ # <p>
+ # <label for="post_title">Title</label><br />
+ # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />
+ # </p>
+ # <p>
+ # <label for="post_body">Body</label><br />
+ # <textarea cols="40" id="post_body" name="post[body]" rows="20"></textarea>
+ # </p>
+ # <input name="commit" type="submit" value="Create" />
+ # </form>
#
# It's possible to specialize the form builder by using a different action name and by supplying another
- # block renderer. For example, let's say you have a model <tt>Entry</tt> with an attribute <tt>message</tt> of type <tt>VARCHAR</tt>:
+ # block renderer. For example, if <tt>@entry</tt> has an attribute +message+ of type +VARCHAR+ then
+ #
+ # form("entry",
+ # :action => "sign",
+ # :input_block => Proc.new { |record, column|
+ # "#{column.human_name}: #{input(record, column.name)}<br />"
+ # })
#
- # form("entry", :action => "sign", :input_block =>
- # Proc.new { |record, column| "#{column.human_name}: #{input(record, column.name)}<br />" }) =>
+ # would yield a form like the following (modulus formatting):
#
- # <form action='/post/sign' method='post'>
- # Message:
- # <input id="post_title" name="post[title]" size="30" type="text" value="Hello World" /><br />
- # <input type='submit' value='Sign' />
- # </form>
+ # <form action="/entries/sign" method="post">
+ # Message:
+ # <input id="entry_message" name="entry[message]" size="30" type="text" /><br />
+ # <input name="commit" type="submit" value="Sign" />
+ # </form>
#
# It's also possible to add additional content to the form by giving it a block, such as:
#
@@ -59,11 +67,11 @@ module ActionView
#
# The following options are available:
#
- # * <tt>action</tt> - the action used when submitting the form (default: create if a new record, otherwise update)
- # * <tt>input_block</tt> - specialize the output using a different block, see above
- # * <tt>method</tt> - the method used when submitting the form (default: post)
- # * <tt>multipart</tt> - whether to change the enctype of the form to multipart/form-date, used when uploading a file (default: false)
- # * <tt>submit_value</tt> - the text of the submit button (default: Create if a new record, otherwise Update)
+ # * <tt>:action</tt> - The action used when submitting the form (default: +create+ if a new record, otherwise +update+).
+ # * <tt>:input_block</tt> - Specialize the output using a different block, see above.
+ # * <tt>:method</tt> - The method used when submitting the form (default: +post+).
+ # * <tt>:multipart</tt> - Whether to change the enctype of the form to "multipart/form-data", used when uploading a file (default: +false+).
+ # * <tt>:submit_value</tt> - The text of the submit button (default: "Create" if a new record, otherwise "Update").
def form(record_name, options = {})
record = instance_variable_get("@#{record_name}")
@@ -84,17 +92,16 @@ module ActionView
# Returns a string containing the error message attached to the +method+ on the +object+ if one exists.
# This error message is wrapped in a <tt>DIV</tt> tag, which can be extended to include a +prepend_text+ and/or +append_text+
# (to properly explain the error), and a +css_class+ to style it accordingly. +object+ should either be the name of an instance variable or
- # the actual object. As an example, let's say you have a model
- # +post+ that has an error message on the +title+ attribute:
+ # the actual object. As an example, let's say you have a model <tt>@post</tt> that has an error message on the +title+ attribute:
#
- # <%= error_message_on "post", "title" %> =>
- # <div class="formError">can't be empty</div>
+ # <%= error_message_on "post", "title" %>
+ # # => <div class="formError">can't be empty</div>
#
- # <%= error_message_on @post, "title" %> =>
- # <div class="formError">can't be empty</div>
+ # <%= error_message_on @post, "title" %>
+ # # => <div class="formError">can't be empty</div>
#
- # <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %> =>
- # <div class="inputError">Title simply can't be empty (or it won't work).</div>
+ # <%= error_message_on "post", "title", "Title simply ", " (or it won't work).", "inputError" %>
+ # # => <div class="inputError">Title simply can't be empty (or it won't work).</div>
def error_message_on(object, method, prepend_text = "", append_text = "", css_class = "formError")
if (obj = (object.respond_to?(:errors) ? object : instance_variable_get("@#{object}"))) &&
(errors = obj.errors.on(method))
@@ -110,30 +117,37 @@ module ActionView
#
# This <tt>DIV</tt> can be tailored by the following options:
#
- # * <tt>header_tag</tt> - Used for the header of the error div (default: h2)
- # * <tt>id</tt> - The id of the error div (default: errorExplanation)
- # * <tt>class</tt> - The class of the error div (default: errorExplanation)
- # * <tt>object</tt> - The object (or array of objects) for which to display errors, if you need to escape the instance variable convention
- # * <tt>object_name</tt> - The object name to use in the header, or any text that you prefer. If <tt>object_name</tt> is not set, the name of the first object will be used.
- # * <tt>header_message</tt> - The message in the header of the error div. Pass +nil+ or an empty string to avoid the header message altogether. (default: X errors prohibited this object from being saved)
- # * <tt>message</tt> - The explanation message after the header message and before the error list. Pass +nil+ or an empty string to avoid the explanation message altogether. (default: There were problems with the following fields:)
+ # * <tt>:header_tag</tt> - Used for the header of the error div (default: "h2").
+ # * <tt>:id</tt> - The id of the error div (default: "errorExplanation").
+ # * <tt>:class</tt> - The class of the error div (default: "errorExplanation").
+ # * <tt>:object</tt> - The object (or array of objects) for which to display errors,
+ # if you need to escape the instance variable convention.
+ # * <tt>:object_name</tt> - The object name to use in the header, or any text that you prefer.
+ # If <tt>:object_name</tt> is not set, the name of the first object will be used.
+ # * <tt>:header_message</tt> - The message in the header of the error div. Pass +nil+
+ # or an empty string to avoid the header message altogether. (Default: "X errors
+ # prohibited this object from being saved").
+ # * <tt>:message</tt> - The explanation message after the header message and before
+ # the error list. Pass +nil+ or an empty string to avoid the explanation message
+ # altogether. (Default: "There were problems with the following fields:").
#
- # To specify the display for one object, you simply provide its name as a parameter. For example, for the +User+ model:
+ # To specify the display for one object, you simply provide its name as a parameter.
+ # For example, for the <tt>@user</tt> model:
#
# error_messages_for 'user'
#
- # To specify more than one object, you simply list them; optionally, you can add an extra +object_name+ parameter, which
- # will be the name used in the header message.
+ # To specify more than one object, you simply list them; optionally, you can add an extra <tt>:object_name</tt> parameter, which
+ # will be the name used in the header message:
#
# error_messages_for 'user_common', 'user', :object_name => 'user'
#
- # If the objects cannot be located as instance variables, you can add an extra +object+ paremeter which gives the actual
- # object (or array of objects to use)
+ # If the objects cannot be located as instance variables, you can add an extra <tt>:object</tt> paremeter which gives the actual
+ # object (or array of objects to use):
#
# error_messages_for 'user', :object => @question.user
#
# NOTE: This is a pre-packaged presentation of the errors with embedded strings and a certain HTML structure. If what
- # you need is significantly different from the default presentation, it makes plenty of sense to access the object.errors
+ # you need is significantly different from the default presentation, it makes plenty of sense to access the <tt>object.errors</tt>
# instance yourself and set it up. View the source of this method to see how easy it is.
def error_messages_for(*params)
options = params.extract_options!.symbolize_keys
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 0cce96b184..dfc7e2b3ed 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -164,7 +164,7 @@ module ActionView
# current page or you can pass the full path relative to your document
# root. To include the Prototype and Scriptaculous javascript libraries in
# your application, pass <tt>:defaults</tt> as the source. When using
- # :defaults, if an <tt>application.js</tt> file exists in your public
+ # <tt>:defaults</tt>, if an application.js file exists in your public
# javascripts directory, it will be included as well. You can modify the
# html attributes of the script tag by passing a hash as the last argument.
#
@@ -332,7 +332,7 @@ module ActionView
# <link href="/stylesheets/random.styles" media="screen" rel="stylesheet" type="text/css" />
# <link href="/css/stylish.css" media="screen" rel="stylesheet" type="text/css" />
#
- # You can also include all styles in the stylesheet directory using :all as the source:
+ # You can also include all styles in the stylesheet directory using <tt>:all</tt> as the source:
#
# stylesheet_link_tag :all # =>
# <link href="/stylesheets/style1.css" media="screen" rel="stylesheet" type="text/css" />
diff --git a/actionpack/lib/action_view/helpers/benchmark_helper.rb b/actionpack/lib/action_view/helpers/benchmark_helper.rb
index fefa28f4d7..743d1d40ec 100644
--- a/actionpack/lib/action_view/helpers/benchmark_helper.rb
+++ b/actionpack/lib/action_view/helpers/benchmark_helper.rb
@@ -21,11 +21,13 @@ module ActionView
# You may give an optional logger level as the second argument
# (:debug, :info, :warn, :error); the default value is :info.
def benchmark(message = "Benchmarking", level = :info)
- if @logger
+ if controller.logger
real = Benchmark.realtime { yield }
- @logger.send level, "#{message} (#{'%.5f' % real})"
+ controller.logger.send(level, "#{message} (#{'%.5f' % real})")
+ else
+ yield
end
end
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb
index 9f7790d0f9..cbd390421a 100755
--- a/actionpack/lib/action_view/helpers/date_helper.rb
+++ b/actionpack/lib/action_view/helpers/date_helper.rb
@@ -104,17 +104,17 @@ module ActionView
# Returns a set of select tags (one for year, month, and day) pre-selected for accessing a specified date-based attribute (identified by
# +method+) on an object assigned to the template (identified by +object+). It's possible to tailor the selects through the +options+ hash,
- # which accepts all the keys that each of the individual select builders do (like :use_month_numbers for select_month) as well as a range of
+ # which accepts all the keys that each of the individual select builders do (like <tt>:use_month_numbers</tt> for select_month) as well as a range of
# discard options. The discard options are <tt>:discard_year</tt>, <tt>:discard_month</tt> and <tt>:discard_day</tt>. Set to true, they'll
# drop the respective select. Discarding the month select will also automatically discard the day select. It's also possible to explicitly
# set the order of the tags using the <tt>:order</tt> option with an array of symbols <tt>:year</tt>, <tt>:month</tt> and <tt>:day</tt> in
# the desired order. Symbols may be omitted and the respective select is not included.
#
- # Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of :year, :month, :day, :hour, :minute, and :second.
+ # Pass the <tt>:default</tt> option to set the default date. Use a Time object or a Hash of <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:minute</tt>, and <tt>:second</tt>.
#
- # Passing :disabled => true as part of the +options+ will make elements inaccessible for change.
+ # Passing <tt>:disabled => true</tt> as part of the +options+ will make elements inaccessible for change.
#
- # If anything is passed in the html_options hash it will be applied to every select tag in the set.
+ # If anything is passed in the +html_options+ hash it will be applied to every select tag in the set.
#
# NOTE: Discarded selects will default to 1. So if no month select is available, January will be assumed.
#
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 0e77a7e067..63c5fd57aa 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -1,6 +1,7 @@
require 'cgi'
require 'action_view/helpers/date_helper'
require 'action_view/helpers/tag_helper'
+require 'action_view/helpers/form_tag_helper'
module ActionView
module Helpers
@@ -51,7 +52,7 @@ module ActionView
#
# If the object name contains square brackets the id for the object will be inserted. For example:
#
- # <%= text_field "person[]", "name" %>
+ # <%= text_field "person[]", "name" %>
#
# ...will generate the following ERb.
#
@@ -91,7 +92,7 @@ module ActionView
#
# Even further, the form_for method allows you to more easily escape the instance variable convention. So while the stand-alone
# approach would require <tt>text_field :person, :name, :object => person</tt>
- # to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with
+ # to work with local variables instead of instance ones, the form_for calls remain the same. You simply declare once with
# <tt>:person, person</tt> and all subsequent field calls save <tt>:person</tt> and <tt>:object => person</tt>.
#
# Also note that form_for doesn't create an exclusive scope. It's still possible to use both the stand-alone FormHelper methods
@@ -107,7 +108,7 @@ module ActionView
# Note: This also works for the methods in FormOptionHelper and DateHelper that are designed to work with an object as base,
# like FormOptionHelper#collection_select and DateHelper#datetime_select.
#
- # HTML attributes for the form tag can be given as :html => {...}. For example:
+ # HTML attributes for the form tag can be given as <tt>:html => {...}</tt>. For example:
#
# <% form_for :person, @person, :html => {:id => 'person_form'} do |f| %>
# ...
@@ -149,7 +150,7 @@ module ActionView
# ...
# <% end %>
#
- # And for namespaced routes, like admin_post_url:
+ # And for namespaced routes, like admin_post_url:
#
# <% form_for([:admin, @post]) do |f| %>
# ...
@@ -337,7 +338,7 @@ module ActionView
# hash with +options+. These options will be tagged onto the HTML as an HTML element attribute as in the example
# shown.
#
- # ==== Examples
+ # ==== Examples
# hidden_field(:signup, :pass_confirm)
# # => <input type="hidden" id="signup_pass_confirm" name="signup[pass_confirm]" value="#{@signup.pass_confirm}" />
#
@@ -404,7 +405,7 @@ module ActionView
# is set to 0 which is convenient for boolean values. Since HTTP standards say that unchecked checkboxes don't post anything,
# we add a hidden value with the same name as the checkbox as a work around.
#
- # ==== Examples
+ # ==== Examples
# # Let's say that @post.validated? is 1:
# check_box("post", "validated")
# # => <input type="checkbox" id="post_validated" name="post[validated]" value="1" />
@@ -445,7 +446,7 @@ module ActionView
end
class InstanceTag #:nodoc:
- include Helpers::TagHelper
+ include Helpers::TagHelper, Helpers::FormTagHelper
attr_reader :method_name, :object_name
@@ -467,11 +468,13 @@ module ActionView
end
def to_label_tag(text = nil, options = {})
+ options = options.stringify_keys
name_and_id = options.dup
add_default_name_and_id(name_and_id)
- options["for"] = name_and_id["id"]
+ options.delete("index")
+ options["for"] ||= name_and_id["id"]
content = (text.blank? ? nil : text.to_s) || method_name.humanize
- content_tag("label", content, options)
+ label_tag(name_and_id["id"], content, options)
end
def to_input_field_tag(field_type, options = {})
@@ -483,6 +486,7 @@ module ActionView
end
options["type"] = field_type
options["value"] ||= value_before_type_cast(object) unless field_type == "file"
+ options["value"] &&= html_escape(options["value"])
add_default_name_and_id(options)
tag("input", options)
end
diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb
index 5b026245da..bf65fe5574 100644
--- a/actionpack/lib/action_view/helpers/form_options_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_options_helper.rb
@@ -93,8 +93,8 @@ module ActionView
# This allows the user to submit a form page more than once with the expected results of creating multiple records.
# In addition, this allows a single partial to be used to generate form inputs for both edit and create forms.
#
- # By default, post.person_id is the selected option. Specify :selected => value to use a different selection
- # or :selected => nil to leave all options unselected.
+ # By default, <tt>post.person_id</tt> is the selected option. Specify <tt>:selected => value</tt> to use a different selection
+ # or <tt>:selected => nil</tt> to leave all options unselected.
def select(object, method, choices, options = {}, html_options = {})
InstanceTag.new(object, method, self, nil, options.delete(:object)).to_select_tag(choices, options, html_options)
end
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index 0544ed3ded..f37b428b80 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -341,8 +341,9 @@ module ActionView
# submit_tag nil, :class => "form_submit"
# # => <input class="form_submit" name="commit" type="submit" />
#
- # submit_tag "Edit", :disable_with => "Editing...", :class => 'edit-button'
- # # => <input class="edit-button" disable_with="Editing..." name="commit" type="submit" value="Edit" />
+ # submit_tag "Edit", :disable_with => "Editing...", :class => "edit-button"
+ # # => <input class="edit-button" onclick="this.disabled=true;this.value='Editing...';this.form.submit();"
+ # # name="commit" type="submit" value="Edit" />
def submit_tag(value = "Save changes", options = {})
options.stringify_keys!
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 81938ac8e3..908728c0e6 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -255,10 +255,10 @@ module ActionView
link_to_function(name, remote_function(options), html_options || options.delete(:html))
end
- # Periodically calls the specified url (<tt>options[:url]</tt>) every
+ # Periodically calls the specified url (<tt>options[:url]</tt>) every
# <tt>options[:frequency]</tt> seconds (default is 10). Usually used to
- # update a specified div (<tt>options[:update]</tt>) with the results
- # of the remote call. The options for specifying the target with :url
+ # update a specified div (<tt>options[:update]</tt>) with the results
+ # of the remote call. The options for specifying the target with <tt>:url</tt>
# and defining callbacks is the same as link_to_remote.
# Examples:
# # Call get_averages and put its results in 'avg' every 10 seconds
@@ -291,11 +291,11 @@ module ActionView
# though it's using JavaScript to serialize the form elements, the form
# submission will work just like a regular submission as viewed by the
# receiving side (all elements available in <tt>params</tt>). The options for
- # specifying the target with :url and defining callbacks is the same as
- # link_to_remote.
+ # specifying the target with <tt>:url</tt> and defining callbacks is the same as
+ # +link_to_remote+.
#
# A "fall-through" target for browsers that doesn't do JavaScript can be
- # specified with the :action/:method options on :html.
+ # specified with the <tt>:action</tt>/<tt>:method</tt> options on <tt>:html</tt>.
#
# Example:
# # Generates:
@@ -304,11 +304,11 @@ module ActionView
# form_remote_tag :html => { :action =>
# url_for(:controller => "some", :action => "place") }
#
- # The Hash passed to the :html key is equivalent to the options (2nd)
+ # The Hash passed to the <tt>:html</tt> key is equivalent to the options (2nd)
# argument in the FormTagHelper.form_tag method.
#
# By default the fall-through action is the same as the one specified in
- # the :url (and the default method is :post).
+ # the <tt>:url</tt> (and the default method is <tt>:post</tt>).
#
# form_remote_tag also takes a block, like form_tag:
# # Generates:
@@ -422,8 +422,8 @@ module ActionView
end
# Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function
- # that form_remote_tag can call in :complete to evaluate a multiple
- # update return document using update_element_function calls.
+ # that +form_remote_tag+ can call in <tt>:complete</tt> to evaluate a multiple
+ # update return document using +update_element_function+ calls.
def evaluate_remote_response
"eval(request.responseText)"
end
diff --git a/actionpack/lib/action_view/helpers/sanitize_helper.rb b/actionpack/lib/action_view/helpers/sanitize_helper.rb
index 47fbe3a27a..3129ff414e 100644
--- a/actionpack/lib/action_view/helpers/sanitize_helper.rb
+++ b/actionpack/lib/action_view/helpers/sanitize_helper.rb
@@ -10,7 +10,7 @@ module ActionView
base.extend(ClassMethods)
end
- # This #sanitize helper will html encode all tags and strip all attributes that aren't specifically allowed.
+ # This +sanitize+ helper will html encode all tags and strip all attributes that aren't specifically allowed.
# It also strips href/src tags with invalid protocols, like javascript: especially. It does its best to counter any
# tricks that hackers may use, like throwing in unicode/ascii/hex values to get past the javascript: filters. Check out
# the extensive test suite.
@@ -18,7 +18,7 @@ module ActionView
# <%= sanitize @article.body %>
#
# You can add or remove tags/attributes if you want to customize it a bit. See ActionView::Base for full docs on the
- # available options. You can add tags/attributes for single uses of #sanitize by passing either the :attributes or :tags options:
+ # available options. You can add tags/attributes for single uses of +sanitize+ by passing either the <tt>:attributes</tt> or <tt>:tags</tt> options:
#
# Normal Use
#
diff --git a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb
index 60e285b722..12b4cfd3f8 100644
--- a/actionpack/lib/action_view/helpers/scriptaculous_helper.rb
+++ b/actionpack/lib/action_view/helpers/scriptaculous_helper.rb
@@ -35,8 +35,8 @@ module ActionView
# This would fade the element that was dropped on the drop receiving
# element.
#
- # For toggling visual effects, you can use :toggle_appear, :toggle_slide, and
- # :toggle_blind which will alternate between appear/fade, slidedown/slideup, and
+ # For toggling visual effects, you can use <tt>:toggle_appear</tt>, <tt>:toggle_slide</tt>, and
+ # <tt>:toggle_blind</tt> which will alternate between appear/fade, slidedown/slideup, and
# blinddown/blindup respectively.
#
# You can change the behaviour with various options, see
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 4a951f2c88..6d27494213 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -16,7 +16,7 @@ module ActionView
# instead of the fully qualified URL like http://example.com/controller/action.
#
# When called from a view, url_for returns an HTML escaped url. If you
- # need an unescaped url, pass :escape => false in the +options+.
+ # need an unescaped url, pass <tt>:escape => false</tt> in the +options+.
#
# ==== Options
# * <tt>:anchor</tt> -- specifies the anchor name to be appended to the path.
@@ -25,8 +25,8 @@ module ActionView
# is currently not recommended since it breaks caching.
# * <tt>:host</tt> -- overrides the default (current) host if provided
# * <tt>:protocol</tt> -- overrides the default (current) protocol if provided
- # * <tt>:user</tt> -- Inline HTTP authentication (only plucked out if :password is also present)
- # * <tt>:password</tt> -- Inline HTTP authentication (only plucked out if :user is also present)
+ # * <tt>:user</tt> -- Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present)
+ # * <tt>:password</tt> -- Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present)
# * <tt>:escape</tt> -- Determines whether the returned URL will be HTML escaped or not (<tt>true</tt> by default)
#
# ==== Relying on named routes
@@ -102,21 +102,21 @@ module ActionView
# create an HTML form and immediately submit the form for processing using
# the HTTP verb specified. Useful for having links perform a POST operation
# in dangerous actions like deleting a record (which search bots can follow
- # while spidering your site). Supported verbs are :post, :delete and :put.
+ # while spidering your site). Supported verbs are <tt>:post</tt>, <tt>:delete</tt> and <tt>:put</tt>.
# Note that if the user has JavaScript disabled, the request will fall back
# to using GET. If you are relying on the POST behavior, you should check
# for it in your controller's action by using the request object's methods
- # for post?, delete? or put?.
+ # for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
# * The +html_options+ will accept a hash of html attributes for the link tag.
#
# Note that if the user has JavaScript disabled, the request will fall back
- # to using GET. If :href=>'#' is used and the user has JavaScript disabled
+ # to using GET. If <tt>:href => '#'</tt> is used and the user has JavaScript disabled
# clicking the link will have no effect. If you are relying on the POST
# behavior, your should check for it in your controller's action by using the
- # request object's methods for post?, delete? or put?.
+ # request object's methods for <tt>post?</tt>, <tt>delete?</tt> or <tt>put?</tt>.
#
# You can mix and match the +html_options+ with the exception of
- # :popup and :method which will raise an ActionView::ActionViewError
+ # <tt>:popup</tt> and <tt>:method</tt> which will raise an ActionView::ActionViewError
# exception.
#
# ==== Examples
diff --git a/actionpack/lib/action_view/partial_template.rb b/actionpack/lib/action_view/partial_template.rb
index 7d9c59a41c..1fb3aaee02 100644
--- a/actionpack/lib/action_view/partial_template.rb
+++ b/actionpack/lib/action_view/partial_template.rb
@@ -24,10 +24,12 @@ module ActionView #:nodoc:
def render_member(object)
@locals[@counter_name] += 1
@locals[:object] = @locals[@variable_name] = object
- returning render do
- @locals.delete(@variable_name)
- @locals.delete(:object)
- end
+
+ template = render_template
+ @locals.delete(@variable_name)
+ @locals.delete(:object)
+
+ template
end
def counter=(num)
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb
index 37b717d848..a708ecb3fb 100644
--- a/actionpack/lib/action_view/partials.rb
+++ b/actionpack/lib/action_view/partials.rb
@@ -100,18 +100,18 @@ module ActionView
# Title: <%= chief.name %>
# </div>
#
- # As you can see, the :locals hash is shared between both the partial and its layout.
+ # As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
module Partials
private
def render_partial(partial_path, object_assigns = nil, local_assigns = {}) #:nodoc:
case partial_path
when String, Symbol, NilClass
# Render the template
- ActionView::PartialTemplate.new(self, partial_path, object_assigns, local_assigns).render
+ ActionView::PartialTemplate.new(self, partial_path, object_assigns, local_assigns).render_template
when ActionView::Helpers::FormBuilder
builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
render_partial(builder_partial_path, object_assigns, (local_assigns || {}).merge(builder_partial_path.to_sym => partial_path))
- when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Associations::HasManyThroughAssociation
+ when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope
if partial_path.any?
collection = partial_path
render_partial_collection(nil, collection, nil, local_assigns)
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index bc3d8d5e52..2cda3d94b5 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -17,6 +17,18 @@ module ActionView #:nodoc:
@locals = locals || {}
@handler = self.class.handler_class_for_extension(@extension).new(@view)
end
+
+ def render_template
+ render
+ rescue Exception => e
+ raise e unless filename
+ if TemplateError === e
+ e.sub_template_of(filename)
+ raise e
+ else
+ raise TemplateError.new(self, @view.assigns, e)
+ end
+ end
def render
prepare!
diff --git a/actionpack/lib/action_view/template_finder.rb b/actionpack/lib/action_view/template_finder.rb
index aaf34de538..83b7e27c09 100644
--- a/actionpack/lib/action_view/template_finder.rb
+++ b/actionpack/lib/action_view/template_finder.rb
@@ -24,7 +24,12 @@ module ActionView #:nodoc:
view_paths.flatten.compact.each do |dir|
next if @@processed_view_paths.has_key?(dir)
@@processed_view_paths[dir] = []
- Dir.glob("#{dir}/**/*/**").each do |file|
+
+ #
+ # Dir.glob("#{dir}/**/*/**") reads all the directories in view path and templates inside those directories
+ # Dir.glob("#{dir}/**") reads templates residing at top level of view path
+ #
+ (Dir.glob("#{dir}/**/*/**") | Dir.glob("#{dir}/**")).each do |file|
unless File.directory?(file)
@@processed_view_paths[dir] << file.split(dir).last.sub(/^\//, '')
diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template_handlers/builder.rb
index cff9e6beb8..f76d89777a 100644
--- a/actionpack/lib/action_view/template_handlers/builder.rb
+++ b/actionpack/lib/action_view/template_handlers/builder.rb
@@ -13,7 +13,7 @@ module ActionView
content_type_handler = (@view.send!(:controller).respond_to?(:response) ? "controller.response" : "controller")
"#{content_type_handler}.content_type ||= Mime::XML\n" +
"xml = ::Builder::XmlMarkup.new(:indent => 2)\n" +
- template +
+ template.source +
"\nxml.target!\n"
end
diff --git a/actionpack/lib/action_view/template_handlers/compilable.rb b/actionpack/lib/action_view/template_handlers/compilable.rb
index 35c74f6c51..25bd0fea7f 100644
--- a/actionpack/lib/action_view/template_handlers/compilable.rb
+++ b/actionpack/lib/action_view/template_handlers/compilable.rb
@@ -95,7 +95,7 @@ module ActionView
# Method to create the source code for a given template.
def create_template_source(template, render_symbol)
- body = compile(template.source)
+ body = compile(template)
self.template_args[render_symbol] ||= {}
locals_keys = self.template_args[render_symbol].keys | template.locals.keys
diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template_handlers/erb.rb
index f30cf0203c..15a9064461 100644
--- a/actionpack/lib/action_view/template_handlers/erb.rb
+++ b/actionpack/lib/action_view/template_handlers/erb.rb
@@ -43,7 +43,7 @@ module ActionView
include Compilable
def compile(template)
- ::ERB.new(template, nil, @view.erb_trim_mode).src
+ ::ERB.new(template.source, nil, @view.erb_trim_mode).src
end
def cache_fragment(block, name = {}, options = nil) #:nodoc:
diff --git a/actionpack/lib/action_view/template_handlers/rjs.rb b/actionpack/lib/action_view/template_handlers/rjs.rb
index e0f95205de..5854e33fed 100644
--- a/actionpack/lib/action_view/template_handlers/rjs.rb
+++ b/actionpack/lib/action_view/template_handlers/rjs.rb
@@ -9,7 +9,7 @@ module ActionView
def compile(template)
"controller.response.content_type ||= Mime::JS\n" +
- "update_page do |page|\n#{template}\nend"
+ "update_page do |page|\n#{template.source}\nend"
end
def cache_fragment(block, name = {}, options = nil) #:nodoc:
diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
index 773018d445..32b26206c3 100644
--- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
+++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
@@ -1,7 +1,7 @@
require 'active_record_unit'
class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
- fixtures :developers, :projects, :developers_projects, :topics, :replies
+ fixtures :developers, :projects, :developers_projects, :topics, :replies, :companies, :mascots
class RenderPartialWithRecordIdentificationController < ActionController::Base
def render_with_has_many_and_belongs_to_association
@@ -14,11 +14,20 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
render :partial => @topic.replies
end
+ def render_with_named_scope
+ render :partial => Reply.base
+ end
+
def render_with_has_many_through_association
@developer = Developer.find(:first)
render :partial => @developer.topics
end
+ def render_with_has_one_association
+ @company = Company.find(1)
+ render :partial => @company.mascot
+ end
+
def render_with_belongs_to_association
@reply = Reply.find(1)
render :partial => @reply.topic
@@ -53,16 +62,9 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
assert_template 'replies/_reply'
end
- def test_rendering_partial_with_has_many_association
- get :render_with_has_many_through_association
- assert_template 'topics/_topic'
- end
-
- def test_rendering_partial_with_belongs_to_association
- topic = Reply.find(1).topic
- get :render_with_belongs_to_association
- assert_template 'topics/_topic'
- assert_equal topic.title, @response.body
+ def test_rendering_partial_with_named_scope
+ get :render_with_named_scope
+ assert_template 'replies/_reply'
end
def test_render_with_record
@@ -74,4 +76,11 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
get :render_with_record_collection
assert_template 'developers/_developer'
end
+
+ def test_rendering_partial_with_has_one_association
+ mascot = Company.find(1).mascot
+ get :render_with_has_one_association
+ assert_template 'mascots/_mascot'
+ assert_equal mascot.name, @response.body
+ end
end
diff --git a/actionpack/test/controller/assert_select_test.rb b/actionpack/test/controller/assert_select_test.rb
index c8ad56cbc0..5af579f3e3 100644
--- a/actionpack/test/controller/assert_select_test.rb
+++ b/actionpack/test/controller/assert_select_test.rb
@@ -345,10 +345,17 @@ class AssertSelectTest < Test::Unit::TestCase
page.replace "test", "<div id=\"1\">\343\203\201\343\202\261\343\203\203\343\203\210</div>"
end
assert_select_rjs do
- assert_select "#1", :text => "\343\203\201\343\202\261\343\203\203\343\203\210"
- assert_select "#1", "\343\203\201\343\202\261\343\203\203\343\203\210"
- assert_select "#1", Regexp.new("\343\203\201..\343\203\210",0,'U')
- assert_raises(AssertionFailedError) { assert_select "#1", Regexp.new("\343\203\201.\343\203\210",0,'U') }
+ str = "#1"
+ assert_select str, :text => "\343\203\201\343\202\261\343\203\203\343\203\210"
+ assert_select str, "\343\203\201\343\202\261\343\203\203\343\203\210"
+ if str.respond_to?(:force_encoding)
+ str.force_encoding(Encoding::UTF_8)
+ assert_select str, /\343\203\201..\343\203\210/u
+ assert_raises(AssertionFailedError) { assert_select str, /\343\203\201.\343\203\210/u }
+ else
+ assert_select str, Regexp.new("\343\203\201..\343\203\210",0,'U')
+ assert_raises(AssertionFailedError) { assert_select str, Regexp.new("\343\203\201.\343\203\210",0,'U') }
+ end
end
end
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index 1a8bd6dfe9..8416754c1e 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -48,6 +48,15 @@ protected
end
+class DefaultUrlOptionsController < ActionController::Base
+ def default_url_options_action
+ end
+
+ def default_url_options(options)
+ { :host => 'www.override.com', :action => 'new', :bacon => 'chunky' }
+ end
+end
+
class ControllerClassTests < Test::Unit::TestCase
def test_controller_path
assert_equal 'empty', EmptyController.controller_path
@@ -134,3 +143,28 @@ class PerformActionTest < Test::Unit::TestCase
assert_response 404
end
end
+
+class DefaultUrlOptionsTest < Test::Unit::TestCase
+ def setup
+ @controller = DefaultUrlOptionsController.new
+
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+
+ @request.host = 'www.example.com'
+ end
+
+ def test_default_url_options_are_used_if_set
+ ActionController::Routing::Routes.draw do |map|
+ map.default_url_options 'default_url_options', :controller => 'default_url_options'
+ map.connect ':controller/:action/:id'
+ end
+
+ get :default_url_options_action # Make a dummy request so that the controller is initialized properly.
+
+ assert_equal 'http://www.override.com/default_url_options/new?bacon=chunky', @controller.url_for(:controller => 'default_url_options')
+ assert_equal 'http://www.override.com/default_url_options?bacon=chunky', @controller.send(:default_url_options_url)
+ ensure
+ ActionController::Routing::Routes.load!
+ end
+end \ No newline at end of file
diff --git a/actionpack/test/controller/mime_type_test.rb b/actionpack/test/controller/mime_type_test.rb
index 991ac04f62..03b0f8bad2 100644
--- a/actionpack/test/controller/mime_type_test.rb
+++ b/actionpack/test/controller/mime_type_test.rb
@@ -28,6 +28,13 @@ class MimeTypeTest < Test::Unit::TestCase
expect = [Mime::HTML, Mime::XML, "image/*", Mime::TEXT, Mime::ALL]
assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s }
end
+
+ # Accept header send with user HTTP_USER_AGENT: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)
+ def test_parse_crappy_broken_acceptlines2
+ accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, , pronto/1.00.00, sslvpn/1.00.00.00, */*"
+ expect = ['image/gif', 'image/x-xbitmap', 'image/jpeg','image/pjpeg', 'application/x-shockwave-flash', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/msword', 'pronto/1.00.00', 'sslvpn/1.00.00.00', Mime::ALL ]
+ assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s }
+ end
def test_custom_type
Mime::Type.register("image/gif", :gif)
diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb
index 7491f16a84..066fa6acd4 100644
--- a/actionpack/test/controller/render_test.rb
+++ b/actionpack/test/controller/render_test.rb
@@ -23,6 +23,14 @@ class TestController < ActionController::Base
def render_hello_world_with_forward_slash
render :template => "/test/hello_world"
end
+
+ def render_template_in_top_directory
+ render :template => 'shared'
+ end
+
+ def render_template_in_top_directory_with_slash
+ render :template => '/shared'
+ end
def render_hello_world_from_variable
@person = "david"
@@ -243,6 +251,18 @@ class RenderTest < Test::Unit::TestCase
get :render_hello_world_with_forward_slash
assert_template "test/hello_world"
end
+
+ def test_render_in_top_directory
+ get :render_template_in_top_directory
+ assert_template "shared"
+ assert_equal "Elastica", @response.body
+ end
+
+ def test_render_in_top_directory_with_slash
+ get :render_template_in_top_directory_with_slash
+ assert_template "shared"
+ assert_equal "Elastica", @response.body
+ end
def test_render_from_variable
get :render_hello_world_from_variable
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index 5756c05e2e..640afd58f8 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -2341,11 +2341,13 @@ uses_mocha 'route loading' do
def setup
routes.instance_variable_set '@routes_last_modified', nil
silence_warnings { Object.const_set :RAILS_ROOT, '.' }
+ ActionController::Routing::Routes.configuration_file = File.join(RAILS_ROOT, 'config', 'routes.rb')
@stat = stub_everything
end
def teardown
+ ActionController::Routing::Routes.configuration_file = nil
Object.send :remove_const, :RAILS_ROOT
end
@@ -2386,6 +2388,14 @@ uses_mocha 'route loading' do
Inflector.inflections { |inflect| inflect.uncountable('equipment') }
end
+
+ def test_load_with_configuration
+ routes.configuration_file = "foobarbaz"
+ File.expects(:stat).returns(@stat)
+ routes.expects(:load).with("foobarbaz")
+
+ routes.reload
+ end
private
def routes
diff --git a/actionpack/test/controller/session/mem_cache_store_test.rb b/actionpack/test/controller/session/mem_cache_store_test.rb
index df48e6d9c5..a7d48431f8 100644
--- a/actionpack/test/controller/session/mem_cache_store_test.rb
+++ b/actionpack/test/controller/session/mem_cache_store_test.rb
@@ -62,9 +62,8 @@ class MemCacheStoreTest < Test::Unit::TestCase
assert_equal d, s.cache.get(session_key)[:test]
assert_equal d, s[:test]
end
- end
-
-
+ end
+
def test_deletion
new_session do |s|
session_key = 'session:' + s.session_id
diff --git a/actionpack/test/fixtures/company.rb b/actionpack/test/fixtures/company.rb
index 0d1c29b906..cbbd0edb14 100644
--- a/actionpack/test/fixtures/company.rb
+++ b/actionpack/test/fixtures/company.rb
@@ -1,4 +1,5 @@
class Company < ActiveRecord::Base
+ has_one :mascot
attr_protected :rating
set_sequence_name :companies_nonstd_seq
diff --git a/actionpack/test/fixtures/db_definitions/sqlite.sql b/actionpack/test/fixtures/db_definitions/sqlite.sql
index 358c2bbb04..8e1947d14a 100644
--- a/actionpack/test/fixtures/db_definitions/sqlite.sql
+++ b/actionpack/test/fixtures/db_definitions/sqlite.sql
@@ -41,3 +41,9 @@ CREATE TABLE 'developers_projects' (
'joined_on' DATE DEFAULT NULL,
'access_level' INTEGER DEFAULT 1
);
+
+CREATE TABLE 'mascots' (
+ 'id' INTEGER PRIMARY KEY NOT NULL,
+ 'company_id' INTEGER NOT NULL,
+ 'name' TEXT DEFAULT NULL
+); \ No newline at end of file
diff --git a/actionpack/test/fixtures/mascot.rb b/actionpack/test/fixtures/mascot.rb
new file mode 100644
index 0000000000..f9f1448b8f
--- /dev/null
+++ b/actionpack/test/fixtures/mascot.rb
@@ -0,0 +1,3 @@
+class Mascot < ActiveRecord::Base
+ belongs_to :company
+end \ No newline at end of file
diff --git a/actionpack/test/fixtures/mascots.yml b/actionpack/test/fixtures/mascots.yml
new file mode 100644
index 0000000000..17b7dff454
--- /dev/null
+++ b/actionpack/test/fixtures/mascots.yml
@@ -0,0 +1,4 @@
+upload_bird:
+ id: 1
+ company_id: 1
+ name: The Upload Bird \ No newline at end of file
diff --git a/actionpack/test/fixtures/mascots/_mascot.html.erb b/actionpack/test/fixtures/mascots/_mascot.html.erb
new file mode 100644
index 0000000000..432773a1da
--- /dev/null
+++ b/actionpack/test/fixtures/mascots/_mascot.html.erb
@@ -0,0 +1 @@
+<%= mascot.name %> \ No newline at end of file
diff --git a/actionpack/test/fixtures/reply.rb b/actionpack/test/fixtures/reply.rb
index 588713de1e..04598437c2 100644
--- a/actionpack/test/fixtures/reply.rb
+++ b/actionpack/test/fixtures/reply.rb
@@ -1,4 +1,5 @@
class Reply < ActiveRecord::Base
+ named_scope :base
belongs_to :topic, :include => [:replies]
belongs_to :developer
diff --git a/actionpack/test/fixtures/shared.html.erb b/actionpack/test/fixtures/shared.html.erb
new file mode 100644
index 0000000000..af262fc9f8
--- /dev/null
+++ b/actionpack/test/fixtures/shared.html.erb
@@ -0,0 +1 @@
+Elastica \ No newline at end of file
diff --git a/actionpack/test/fixtures/test/_raise.html.erb b/actionpack/test/fixtures/test/_raise.html.erb
new file mode 100644
index 0000000000..68b08181d3
--- /dev/null
+++ b/actionpack/test/fixtures/test/_raise.html.erb
@@ -0,0 +1 @@
+<%= doesnt_exist %> \ No newline at end of file
diff --git a/actionpack/test/template/benchmark_helper_test.rb b/actionpack/test/template/benchmark_helper_test.rb
index d95a3dee26..08d453c965 100644
--- a/actionpack/test/template/benchmark_helper_test.rb
+++ b/actionpack/test/template/benchmark_helper_test.rb
@@ -16,32 +16,20 @@ class BenchmarkHelperTest < ActionView::TestCase
end
end
- def setup
- @logger = MockLogger.new
- end
-
- def test_without_logger_or_block
- @logger = nil
- assert_nothing_raised { benchmark }
+ def controller
+ @controller ||= Struct.new(:logger).new(MockLogger.new)
end
def test_without_block
assert_raise(LocalJumpError) { benchmark }
- assert @logger.logged.empty?
- end
-
- def test_without_logger
- @logger = nil
- i_was_run = false
- benchmark { i_was_run = true }
- assert !i_was_run
+ assert controller.logger.logged.empty?
end
def test_defaults
i_was_run = false
benchmark { i_was_run = true }
assert i_was_run
- assert 1, @logger.logged.size
+ assert 1, controller.logger.logged.size
assert_last_logged
end
@@ -49,7 +37,7 @@ class BenchmarkHelperTest < ActionView::TestCase
i_was_run = false
benchmark('test_run') { i_was_run = true }
assert i_was_run
- assert 1, @logger.logged.size
+ assert 1, controller.logger.logged.size
assert_last_logged 'test_run'
end
@@ -57,13 +45,13 @@ class BenchmarkHelperTest < ActionView::TestCase
i_was_run = false
benchmark('debug_run', :debug) { i_was_run = true }
assert i_was_run
- assert 1, @logger.logged.size
+ assert 1, controller.logger.logged.size
assert_last_logged 'debug_run', :debug
end
private
def assert_last_logged(message = 'Benchmarking', level = :info)
- last = @logger.logged.last
+ last = controller.logger.logged.last
assert 2, last.size
assert_equal level, last.first
assert 1, last[1].size
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index c48d5dfd2d..204575fd89 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -6,11 +6,11 @@ silence_warnings do
alias_method :title_before_type_cast, :title unless respond_to?(:title_before_type_cast)
alias_method :body_before_type_cast, :body unless respond_to?(:body_before_type_cast)
alias_method :author_name_before_type_cast, :author_name unless respond_to?(:author_name_before_type_cast)
-
+
def new_record=(boolean)
@new_record = boolean
end
-
+
def new_record?
@new_record
end
@@ -36,13 +36,13 @@ class FormHelperTest < ActionView::TestCase
def setup
@post = Post.new
@comment = Comment.new
- def @post.errors()
- Class.new{
- def on(field); "can't be empty" if field == "author_name"; end
- def empty?() false end
+ def @post.errors()
+ Class.new{
+ def on(field); "can't be empty" if field == "author_name"; end
+ def empty?() false end
def count() 1 end
- def full_messages() [ "Author name can't be empty" ] end
- }.new
+ def full_messages() [ "Author name can't be empty" ] end
+ }.new
end
def @post.id; 123; end
def @post.id_before_type_cast; 123; end
@@ -72,11 +72,19 @@ class FormHelperTest < ActionView::TestCase
label("post", "title", nil, :class => 'title_label')
)
end
-
+
def test_label_with_symbols
assert_dom_equal('<label for="post_title">Title</label>', label(:post, :title))
end
+ def test_label_with_for_attribute_as_symbol
+ assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, :for => "my_for"))
+ end
+
+ def test_label_with_for_attribute_as_string
+ assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, "for" => "my_for"))
+ end
+
def test_text_field
assert_dom_equal(
'<input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />', text_field("post", "title")
@@ -96,6 +104,14 @@ class FormHelperTest < ActionView::TestCase
)
end
+ def test_text_field_with_html_entities
+ @post.title = "The HTML Entity for & is &amp;"
+ assert_dom_equal(
+ '<input id="post_title" name="post[title]" size="30" type="text" value="The HTML Entity for &amp; is &amp;amp;" />',
+ text_field("post", "title")
+ )
+ end
+
def test_text_field_with_options
expected = '<input id="post_title" name="post[title]" size="35" type="text" value="Hello World" />'
assert_dom_equal expected, text_field("post", "title", "size" => 35)
@@ -219,6 +235,14 @@ class FormHelperTest < ActionView::TestCase
)
end
+ def test_text_area_with_html_entities
+ @post.body = "The HTML Entity for & is &amp;"
+ assert_dom_equal(
+ '<textarea cols="40" id="post_body" name="post[body]" rows="20">The HTML Entity for &amp; is &amp;amp;</textarea>',
+ text_area("post", "body")
+ )
+ end
+
def test_text_area_with_size_option
assert_dom_equal(
'<textarea cols="183" id="post_body" name="post[body]" rows="820">Back to the hill and over it again!</textarea>',
@@ -303,7 +327,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.submit('Create post')
end
- expected =
+ expected =
"<form action='http://www.example.com' id='create-post' method='post'>" +
"<label for='post_title'>Title</label>" +
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
@@ -325,7 +349,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<form action='http://www.example.com' id='create-post' method='post'>" +
"<div style='margin:0;padding:0'><input name='_method' type='hidden' value='put' /></div>" +
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
@@ -346,7 +370,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<form action='http://www.example.com' id='create-post' method='post'>" +
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
"<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
@@ -367,7 +391,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<form action='http://www.example.com' method='post'>" +
"<label for=\"post_123_title\">Title</label>" +
"<input name='post[123][title]' size='30' type='text' id='post_123_title' value='Hello World' />" +
@@ -423,7 +447,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
"<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
@@ -494,7 +518,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
"<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
@@ -511,7 +535,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
"<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
"<input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
@@ -532,6 +556,18 @@ class FormHelperTest < ActionView::TestCase
_erbout
end
+ def test_fields_for_object_with_bracketed_name_and_index
+ _erbout = ''
+ fields_for("author[post]", @post, :index => 1) do |f|
+ _erbout.concat f.label(:title)
+ _erbout.concat f.text_field(:title)
+ end
+
+ assert_dom_equal "<label for=\"author_post_1_title\">Title</label>" +
+ "<input name='author[post][1][title]' size='30' type='text' id='author_post_1_title' value='Hello World' />",
+ _erbout
+ end
+
def test_form_builder_does_not_have_form_for_method
assert ! ActionView::Helpers::FormBuilder.instance_methods.include?('form_for')
end
@@ -548,7 +584,7 @@ class FormHelperTest < ActionView::TestCase
end
end
- expected =
+ expected =
"<form action='http://www.example.com' id='create-post' method='post'>" +
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
"<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
@@ -571,7 +607,7 @@ class FormHelperTest < ActionView::TestCase
end
end
- expected =
+ expected =
"<form action='http://www.example.com' id='create-post' method='post'>" +
"<input name='post[title]' size='30' type='text' id='post_title' value='Hello World' />" +
"<textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
@@ -601,7 +637,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<form action='http://www.example.com' method='post'>" +
"<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
"<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
@@ -623,7 +659,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
"<form action='http://www.example.com' method='post'>" +
"<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
"<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
@@ -637,39 +673,39 @@ class FormHelperTest < ActionView::TestCase
end
def test_default_form_builder_with_active_record_helpers
-
- _erbout = ''
+
+ _erbout = ''
form_for(:post, @post) do |f|
_erbout.concat f.error_message_on('author_name')
_erbout.concat f.error_messages
- end
-
- expected = %(<form action='http://www.example.com' method='post'>) +
- %(<div class='formError'>can't be empty</div>) +
+ end
+
+ expected = %(<form action='http://www.example.com' method='post'>) +
+ %(<div class='formError'>can't be empty</div>) +
%(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
%(</form>)
-
+
assert_dom_equal expected, _erbout
end
-
+
def test_default_form_builder_no_instance_variable
post = @post
@post = nil
-
- _erbout = ''
+
+ _erbout = ''
form_for(:post, post) do |f|
_erbout.concat f.error_message_on('author_name')
_erbout.concat f.error_messages
- end
-
- expected = %(<form action='http://www.example.com' method='post'>) +
- %(<div class='formError'>can't be empty</div>) +
+ end
+
+ expected = %(<form action='http://www.example.com' method='post'>) +
+ %(<div class='formError'>can't be empty</div>) +
%(<div class="errorExplanation" id="errorExplanation"><h2>1 error prohibited this post from being saved</h2><p>There were problems with the following fields:</p><ul><li>Author name can't be empty</li></ul></div>) +
%(</form>)
-
+
assert_dom_equal expected, _erbout
-
+
end
# Perhaps this test should be moved to prototype helper tests.
@@ -683,7 +719,7 @@ class FormHelperTest < ActionView::TestCase
_erbout.concat f.check_box(:secret)
end
- expected =
+ expected =
%(<form action="http://www.example.com" onsubmit="new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" method="post">) +
"<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
"<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
@@ -693,31 +729,31 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, _erbout
end
-
+
def test_fields_for_with_labelled_builder
_erbout = ''
-
+
fields_for(:post, @post, :builder => LabelledFormBuilder) do |f|
_erbout.concat f.text_field(:title)
_erbout.concat f.text_area(:body)
_erbout.concat f.check_box(:secret)
end
-
- expected =
+
+ expected =
"<label for='title'>Title:</label> <input name='post[title]' size='30' type='text' id='post_title' value='Hello World' /><br/>" +
"<label for='body'>Body:</label> <textarea name='post[body]' id='post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea><br/>" +
"<label for='secret'>Secret:</label> <input name='post[secret]' checked='checked' type='checkbox' id='post_secret' value='1' />" +
"<input name='post[secret]' type='hidden' value='0' /><br/>"
-
+
assert_dom_equal expected, _erbout
end
def test_form_for_with_html_options_adds_options_to_form_tag
_erbout = ''
-
+
form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\"></form>"
-
+
assert_dom_equal expected, _erbout
end
@@ -793,16 +829,16 @@ class FormHelperTest < ActionView::TestCase
@comment.save
_erbout = ''
form_for([:admin, @post, @comment]) {}
-
+
expected = %(<form action="#{admin_comment_path(@post, @comment)}" class="edit_comment" id="edit_comment_1" method="post"><div style="margin:0;padding:0"><input name="_method" type="hidden" value="put" /></div></form>)
assert_dom_equal expected, _erbout
end
-
+
def test_form_for_with_new_object_and_namespace_in_list
@post.new_record = false
_erbout = ''
form_for([:admin, @post, @comment]) {}
-
+
expected = %(<form action="#{admin_comments_path(@post)}" class="new_comment" id="new_comment" method="post"></form>)
assert_dom_equal expected, _erbout
end
@@ -819,10 +855,10 @@ class FormHelperTest < ActionView::TestCase
def test_remote_form_for_with_html_options_adds_options_to_form_tag
self.extend ActionView::Helpers::PrototypeHelper
_erbout = ''
-
+
remote_form_for(:post, @post, :html => {:id => 'some_form', :class => 'some_class'}) do |f| end
expected = "<form action=\"http://www.example.com\" class=\"some_class\" id=\"some_form\" method=\"post\" onsubmit=\"new Ajax.Request('http://www.example.com', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"></form>"
-
+
assert_dom_equal expected, _erbout
end
@@ -837,21 +873,21 @@ class FormHelperTest < ActionView::TestCase
"/posts/#{post.id}/comments/#{comment.id}"
end
alias_method :post_comment_path, :comment_path
-
+
def admin_comments_path(post)
"/admin/posts/#{post.id}/comments"
end
alias_method :admin_post_comments_path, :admin_comments_path
-
+
def admin_comment_path(post, comment)
"/admin/posts/#{post.id}/comments/#{comment.id}"
end
alias_method :admin_post_comment_path, :admin_comment_path
-
+
def posts_path
"/posts"
- end
-
+ end
+
def post_path(post)
"/posts/#{post.id}"
end
diff --git a/actionpack/test/template/template_finder_test.rb b/actionpack/test/template/template_finder_test.rb
index a162640de3..3d6baff5fb 100644
--- a/actionpack/test/template/template_finder_test.rb
+++ b/actionpack/test/template/template_finder_test.rb
@@ -21,13 +21,14 @@ class TemplateFinderTest < Test::Unit::TestCase
assert_equal ["builder", "erb", "rhtml", "rjs", "rxml", "mab"].sort,
ActionView::TemplateFinder.file_extension_cache[LOAD_PATH_ROOT].values.flatten.uniq.sort
- assert_equal Dir.glob("#{LOAD_PATH_ROOT}/**/*/*.{erb,rjs,rhtml,builder,rxml,mab}").size,
+ assert_equal (Dir.glob("#{LOAD_PATH_ROOT}/**/*/*.{erb,rjs,rhtml,builder,rxml,mab}") |
+ Dir.glob("#{LOAD_PATH_ROOT}/**.{erb,rjs,rhtml,builder,rxml,mab}")).size,
ActionView::TemplateFinder.file_extension_cache[LOAD_PATH_ROOT].keys.size
end
def test_should_cache_dir_content_properly
assert ActionView::TemplateFinder.processed_view_paths[LOAD_PATH_ROOT]
- assert_equal Dir.glob("#{LOAD_PATH_ROOT}/**/*/**").find_all {|f| !File.directory?(f) }.size,
+ assert_equal (Dir.glob("#{LOAD_PATH_ROOT}/**/*/**") | Dir.glob("#{LOAD_PATH_ROOT}/**")).find_all {|f| !File.directory?(f) }.size,
ActionView::TemplateFinder.processed_view_paths[LOAD_PATH_ROOT].size
end
diff --git a/actionpack/test/template/template_object_test.rb b/actionpack/test/template/template_object_test.rb
index 7adcde421f..afb5c5cc16 100644
--- a/actionpack/test/template/template_object_test.rb
+++ b/actionpack/test/template/template_object_test.rb
@@ -51,6 +51,11 @@ class TemplateObjectTest < Test::Unit::TestCase
assert template.locals.has_key?(:partial_only)
end
+ def test_partial_with_errors
+ template = ActionView::PartialTemplate.new(@view, 'test/raise', nil)
+ assert_raise(ActionView::TemplateError) { template.render_template }
+ end
+
uses_mocha 'Partial template preparation tests' do
def test_should_prepare_on_initialization
ActionView::PartialTemplate.any_instance.expects(:prepare!)
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index b15bdb06ca..34ef3b8f6e 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -10,7 +10,7 @@ module ActiveModel
DEFAULT_VALIDATION_OPTIONS = { :on => :save, :allow_nil => false, :allow_blank => false, :message => nil }.freeze
# Adds a validation method or block to the class. This is useful when
- # overriding the #validate instance method becomes too unwieldly and
+ # overriding the +validate+ instance method becomes too unwieldly and
# you're looking for more descriptive declaration of your validations.
#
# This can be done with a symbol pointing to a method:
@@ -35,8 +35,8 @@ module ActiveModel
# end
# end
#
- # This usage applies to #validate_on_create and #validate_on_update as well.
-
+ # This usage applies to +validate_on_create+ and +validate_on_update as well+.
+ #
# Validates each attribute against a block.
#
# class Person < ActiveRecord::Base
@@ -46,14 +46,14 @@ module ActiveModel
# end
#
# Options:
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>allow_nil</tt> - Skip validation if attribute is nil.
- # * <tt>allow_blank</tt> - Skip validation if attribute is blank.
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
+ # * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_each(*attrs)
options = attrs.extract_options!.symbolize_keys
diff --git a/activemodel/lib/active_model/validations/acceptance.rb b/activemodel/lib/active_model/validations/acceptance.rb
index 7363717858..9be7d51ffb 100644
--- a/activemodel/lib/active_model/validations/acceptance.rb
+++ b/activemodel/lib/active_model/validations/acceptance.rb
@@ -8,22 +8,22 @@ module ActiveModel
# validates_acceptance_of :eula, :message => "must be abided"
# end
#
- # If the database column does not exist, the terms_of_service attribute is entirely virtual. This check is
- # performed only if terms_of_service is not nil and by default on save.
+ # If the database column does not exist, the <tt>:terms_of_service</tt> attribute is entirely virtual. This check is
+ # performed only if <tt>:terms_of_service</tt> is not +nil+ and by default on save.
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "must be accepted")
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>allow_nil</tt> - Skip validation if attribute is nil. (default is true)
- # * <tt>accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which
- # makes it easy to relate to an HTML checkbox. This should be set to 'true' if you are validating a database
- # column, since the attribute is typecast from "1" to <tt>true</tt> before validation.
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "must be accepted")
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+. (default is +true+)
+ # * <tt>:accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which
+ # makes it easy to relate to an HTML checkbox. This should be set to +true+ if you are validating a database
+ # column, since the attribute is typecasted from "1" to +true+ before validation.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
+ # method, proc or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
- # method, proc or string should return or evaluate to a true or false value.
def validates_acceptance_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" }
configuration.update(attr_names.extract_options!)
diff --git a/activemodel/lib/active_model/validations/associated.rb b/activemodel/lib/active_model/validations/associated.rb
index dbb098628b..ae3e4974bc 100644
--- a/activemodel/lib/active_model/validations/associated.rb
+++ b/activemodel/lib/active_model/validations/associated.rb
@@ -21,16 +21,16 @@ module ActiveModel
# ...this would specify a circular dependency and cause infinite recursion.
#
# NOTE: This validation will not fail if the association hasn't been assigned. If you want to ensure that the association
- # is both present and guaranteed to be valid, you also need to use validates_presence_of.
+ # is both present and guaranteed to be valid, you also need to use +validates_presence_of+.
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "is invalid")
- # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "is invalid")
+ # * <tt>:on</tt> Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_associated(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }
diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb
index 79c6635177..ba4a18adb7 100644
--- a/activemodel/lib/active_model/validations/confirmation.rb
+++ b/activemodel/lib/active_model/validations/confirmation.rb
@@ -15,20 +15,20 @@ module ActiveModel
#
# The added +password_confirmation+ attribute is virtual; it exists only as an in-memory attribute for validating the password.
# To achieve this, the validation adds accessors to the model for the confirmation attribute. NOTE: This check is performed
- # only if +password_confirmation+ is not nil, and by default only on save. To require confirmation, make sure to add a presence
+ # only if +password_confirmation+ is not +nil+, and by default only on save. To require confirmation, make sure to add a presence
# check for the confirmation attribute:
#
# validates_presence_of :password_confirmation, :if => :password_changed?
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "doesn't match confirmation")
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "doesn't match confirmation")
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
+ # method, proc or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
- # method, proc or string should return or evaluate to a true or false value.
def validates_confirmation_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save }
configuration.update(attr_names.extract_options!)
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb
index a17c517baa..f3367abcf8 100644
--- a/activemodel/lib/active_model/validations/exclusion.rb
+++ b/activemodel/lib/active_model/validations/exclusion.rb
@@ -10,15 +10,15 @@ module ActiveModel
# end
#
# Configuration options:
- # * <tt>in</tt> - An enumerable object of items that the value shouldn't be part of
- # * <tt>message</tt> - Specifies a custom error message (default is: "is reserved")
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved")
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is +nil+ (default is: +false+)
+ # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the attribute is blank (default is: +false+)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_exclusion_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save }
diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb
index f8395543ec..1320ef646a 100644
--- a/activemodel/lib/active_model/validations/format.rb
+++ b/activemodel/lib/active_model/validations/format.rb
@@ -8,21 +8,21 @@ module ActiveModel
# validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
# end
#
- # Note: use \A and \Z to match the start and end of the string, ^ and $ match the start/end of a line.
+ # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
#
# A regular expression must be provided or else an exception will be raised.
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "is invalid")
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>with</tt> - The regular expression used to validate the format with (note: must be supplied!)
- # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "is invalid")
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is +nil+ (default is: +false+)
+ # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the attribute is blank (default is: +false+)
+ # * <tt>:with</tt> - The regular expression used to validate the format with (note: must be supplied!)
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_format_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil }
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index 2cfa1d6107..9fc1caaabe 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -10,15 +10,15 @@ module ActiveModel
# end
#
# Configuration options:
- # * <tt>in</tt> - An enumerable object of available items
- # * <tt>message</tt> - Specifies a custom error message (default is: "is not included in the list")
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:in</tt> - An enumerable object of available items
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list")
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is null (default is: +false+)
+ # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the attribute is blank (default is: +false+)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_inclusion_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save }
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 5e5e0ad4e6..673ad33974 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -6,35 +6,34 @@ module ActiveModel
# Validates that the specified attribute matches the length restrictions supplied. Only one option can be used at a time:
#
# class Person < ActiveRecord::Base
- # validates_length_of :first_name, :maximum=>30
- # validates_length_of :last_name, :maximum=>30, :message=>"less than %d if you don't mind"
+ # validates_length_of :first_name, :maximum => 30
+ # validates_length_of :last_name, :maximum => 30, :message => "less than %d if you don't mind"
# validates_length_of :fax, :in => 7..32, :allow_nil => true
# validates_length_of :phone, :in => 7..32, :allow_blank => true
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
- # validates_length_of :fav_bra_size, :minimum=>1, :too_short=>"please enter at least %d character"
- # validates_length_of :smurf_leader, :is=>4, :message=>"papa is spelled with %d characters... don't play me."
+ # validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least %d character"
+ # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with %d characters... don't play me."
# end
#
# Configuration options:
- # * <tt>minimum</tt> - The minimum size of the attribute
- # * <tt>maximum</tt> - The maximum size of the attribute
- # * <tt>is</tt> - The exact size of the attribute
- # * <tt>within</tt> - A range specifying the minimum and maximum size of the attribute
- # * <tt>in</tt> - A synonym(or alias) for :within
- # * <tt>allow_nil</tt> - Attribute may be nil; skip validation.
- # * <tt>allow_blank</tt> - Attribute may be blank; skip validation.
- #
- # * <tt>too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)")
- # * <tt>too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)")
- # * <tt>wrong_length</tt> - The error message if using the :is method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)")
- # * <tt>message</tt> - The error message to use for a :minimum, :maximum, or :is violation. An alias of the appropriate too_long/too_short/wrong_length message
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:minimum</tt> - The minimum size of the attribute
+ # * <tt>:maximum</tt> - The maximum size of the attribute
+ # * <tt>:is</tt> - The exact size of the attribute
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute
+ # * <tt>:in</tt> - A synonym (or alias) for <tt>:within</tt>
+ # * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
+ # * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)")
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)")
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)")
+ # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>:too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
+ # method, proc or string should return or evaluate to a true or false value.
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
- # method, proc or string should return or evaluate to a true or false value.
def validates_length_of(*attrs)
# Merge given options with defaults.
options = {
diff --git a/activemodel/lib/active_model/validations/numericality.rb b/activemodel/lib/active_model/validations/numericality.rb
index 4c4e0ce952..8f5c5e8df8 100644
--- a/activemodel/lib/active_model/validations/numericality.rb
+++ b/activemodel/lib/active_model/validations/numericality.rb
@@ -8,29 +8,29 @@ module ActiveModel
# Validates whether the value of the specified attribute is numeric by trying to convert it to
# a float with Kernel.Float (if <tt>integer</tt> is false) or applying it to the regular expression
- # <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>integer</tt> is set to true).
+ # <tt>/\A[\+\-]?\d+\Z/</tt> (if <tt>integer</tt> is true).
#
# class Person < ActiveRecord::Base
# validates_numericality_of :value, :on => :create
# end
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "is not a number")
- # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false)
- # * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float columns empty strings are converted to nil
- # * <tt>greater_than</tt> Specifies the value must be greater than the supplied value
- # * <tt>greater_than_or_equal_to</tt> Specifies the value must be greater than or equal the supplied value
- # * <tt>equal_to</tt> Specifies the value must be equal to the supplied value
- # * <tt>less_than</tt> Specifies the value must be less than the supplied value
- # * <tt>less_than_or_equal_to</tt> Specifies the value must be less than or equal the supplied value
- # * <tt>odd</tt> Specifies the value must be an odd number
- # * <tt>even</tt> Specifies the value must be an even number
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "is not a number")
+ # * <tt>:on</tt> Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is +false+)
+ # * <tt>:allow_nil</tt> Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+
+ # * <tt>:greater_than</tt> Specifies the value must be greater than the supplied value
+ # * <tt>:greater_than_or_equal_to</tt> Specifies the value must be greater than or equal the supplied value
+ # * <tt>:equal_to</tt> Specifies the value must be equal to the supplied value
+ # * <tt>:less_than</tt> Specifies the value must be less than the supplied value
+ # * <tt>:less_than_or_equal_to</tt> Specifies the value must be less than or equal the supplied value
+ # * <tt>:odd</tt> Specifies the value must be an odd number
+ # * <tt>:even</tt> Specifies the value must be an even number
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_numericality_of(*attr_names)
configuration = { :on => :save, :only_integer => false, :allow_nil => false }
diff --git a/activemodel/lib/active_model/validations/presence.rb b/activemodel/lib/active_model/validations/presence.rb
index 3dd2c97cd8..62e466901b 100644
--- a/activemodel/lib/active_model/validations/presence.rb
+++ b/activemodel/lib/active_model/validations/presence.rb
@@ -7,22 +7,26 @@ module ActiveModel
# validates_presence_of :first_name
# end
#
- # The first_name attribute must be in the object and it cannot be blank.
+ # The +first_name+ attribute must be in the object and it cannot be blank.
#
- # If you want to validate the presence of a boolean field (where the real values are true and false),
- # you will want to use validates_inclusion_of :field_name, :in => [true, false]
- # This is due to the way Object#blank? handles boolean values. false.blank? # => true
+ # If you want to validate the presence of a boolean field (where the real values are +true+ and +false+),
+ # you will want to use
+ #
+ # validates_inclusion_of :field_name, :in => [true, false]
+ #
+ # This is due to the way Object#blank? handles boolean values:
+ #
+ # false.blank? # => true
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "can't be blank")
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "can't be blank")
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- #
def validates_presence_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:blank], :on => :save }
configuration.update(attr_names.extract_options!)
diff --git a/activemodel/lib/active_model/validations/uniqueness.rb b/activemodel/lib/active_model/validations/uniqueness.rb
index 37a84dc06d..2b47c6bc09 100644
--- a/activemodel/lib/active_model/validations/uniqueness.rb
+++ b/activemodel/lib/active_model/validations/uniqueness.rb
@@ -23,16 +23,16 @@ module ActiveModel
# unique index on the field. See +add_index+ for more information.
#
# Configuration options:
- # * <tt>message</tt> - Specifies a custom error message (default is: "has already been taken")
- # * <tt>scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint.
- # * <tt>case_sensitive</tt> - Looks for an exact match. Ignored by non-text columns (false by default).
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "has already been taken")
+ # * <tt>:scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint.
+ # * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by non-text columns (+false+ by default).
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the attribute is +nil+ (default is: +false+)
+ # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the attribute is blank (default is: +false+)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_uniqueness_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken] }
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 3248594c19..04cf72b38c 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,24 @@
*SVN*
+* Added change_table for migrations (Jeff Dean) [#71]. Example:
+
+ change_table :videos do |t|
+ t.timestamps # adds created_at, updated_at
+ t.belongs_to :goat # add goat_id integer
+ t.string :name, :email, :limit => 20 # adds name and email both with a 20 char limit
+ t.remove :name, :email # removes the name and email columns
+ end
+
+* Fixed has_many :through .create with no parameters caused a "can't dup NilClass" error (Steven Soroka) [#85]
+
+* Added block-setting of attributes for Base.create like Base.new already has (Adam Meehan) [#39]
+
+* Fixed that pessimistic locking you reference the quoted table name (Josh Susser) [#67]
+
+* Fixed that change_column should be able to use :null => true on a field that formerly had false [Nate Wiger] [#26]
+
+* Added that the MySQL adapter should map integer to either smallint, int, or bigint depending on the :limit just like PostgreSQL [DHH]
+
* Change validates_uniqueness_of :case_sensitive option default back to true (from [9160]). Love your database columns, don't LOWER them. [rick]
* Add support for interleaving migrations by storing which migrations have run in the new schema_migrations table. Closes #11493 [jordi]
diff --git a/activerecord/README b/activerecord/README
index 7204b44ec4..ff3f55ee8a 100755
--- a/activerecord/README
+++ b/activerecord/README
@@ -164,6 +164,28 @@ A short rundown of the major features:
ActiveRecord::Base.logger = Log4r::Logger.new("Application Log")
+* Database agnostic schema management with Migrations
+
+ class AddSystemSettings < ActiveRecord::Migration
+ def self.up
+ create_table :system_settings do |t|
+ t.string :name
+ t.string :label
+ t.text :value
+ t.string :type
+ t.integer :position
+ end
+
+ SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
+ end
+
+ def self.down
+ drop_table :system_settings
+ end
+ end
+
+ {Learn more}[link:classes/ActiveRecord/Migration.html]
+
== Simple example (1/2): Defining tables and classes (using MySQL)
Data definitions are specified only in the database. Active Record queries the database for
diff --git a/activerecord/RUNNING_UNIT_TESTS b/activerecord/RUNNING_UNIT_TESTS
index ea7f3c02d2..39fc86759f 100644
--- a/activerecord/RUNNING_UNIT_TESTS
+++ b/activerecord/RUNNING_UNIT_TESTS
@@ -27,7 +27,10 @@ you can do so with:
rake test_mysql TEST=test/cases/base_test.rb
-That'll run the base suite using the MySQL-Ruby adapter.
+That'll run the base suite using the MySQL-Ruby adapter. Some tests rely on the schema
+being initialized - you can initialize the schema with:
+
+ rake test_mysql TEST=test/cases/aaa_create_tables_test.rb
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 50c120107b..d6033a9b85 100755
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -72,8 +72,6 @@ namespace :postgresql do
task :build_databases do
%x( createdb activerecord_unittest )
%x( createdb activerecord_unittest2 )
- %x( psql activerecord_unittest -f #{File.join(SCHEMA_ROOT, 'postgresql.sql')} )
- %x( psql activerecord_unittest2 -f #{File.join(SCHEMA_ROOT, 'postgresql2.sql')} )
end
desc 'Drop the PostgreSQL test databases'
diff --git a/activerecord/lib/active_record/association_preload.rb b/activerecord/lib/active_record/association_preload.rb
index 7e4f7a5d4a..3e7c787dee 100644
--- a/activerecord/lib/active_record/association_preload.rb
+++ b/activerecord/lib/active_record/association_preload.rb
@@ -59,14 +59,14 @@ module ActiveRecord
def set_association_collection_records(id_to_record_map, reflection_name, associated_records, key)
associated_records.each do |associated_record|
- mapped_records = id_to_record_map[associated_record[key].to_i]
+ mapped_records = id_to_record_map[associated_record[key].to_s]
add_preloaded_records_to_collection(mapped_records, reflection_name, associated_record)
end
end
def set_association_single_records(id_to_record_map, reflection_name, associated_records, key)
associated_records.each do |associated_record|
- mapped_records = id_to_record_map[associated_record[key].to_i]
+ mapped_records = id_to_record_map[associated_record[key].to_s]
mapped_records.each do |mapped_record|
mapped_record.send("set_#{reflection_name}_target", associated_record)
end
@@ -78,16 +78,15 @@ module ActiveRecord
ids = []
records.each do |record|
ids << record.id
- mapped_records = (id_to_record_map[record.id] ||= [])
+ mapped_records = (id_to_record_map[record.id.to_s] ||= [])
mapped_records << record
end
ids.uniq!
return id_to_record_map, ids
end
- # FIXME: quoting
def preload_has_and_belongs_to_many_association(records, reflection, preload_options={})
- table_name = reflection.klass.table_name
+ table_name = reflection.klass.quoted_table_name
id_to_record_map, ids = construct_id_map(records)
records.each {|record| record.send(reflection.name).loaded}
options = reflection.options
@@ -97,7 +96,7 @@ module ActiveRecord
associated_records = reflection.klass.find(:all, :conditions => [conditions, ids],
:include => options[:include],
- :joins => "INNER JOIN #{options[:join_table]} as t0 ON #{reflection.klass.table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
+ :joins => "INNER JOIN #{connection.quote_table_name options[:join_table]} as t0 ON #{reflection.klass.quoted_table_name}.#{reflection.klass.primary_key} = t0.#{reflection.association_foreign_key}",
:select => "#{options[:select] || table_name+'.*'}, t0.#{reflection.primary_key_name} as _parent_record_id",
:order => options[:order])
@@ -116,7 +115,7 @@ module ActiveRecord
source = reflection.source_reflection.name
through_records.first.class.preload_associations(through_records, source)
through_records.each do |through_record|
- add_preloaded_record_to_collection(id_to_record_map[through_record[through_primary_key].to_i],
+ add_preloaded_record_to_collection(id_to_record_map[through_record[through_primary_key].to_s],
reflection.name, through_record.send(source))
end
end
@@ -141,7 +140,7 @@ module ActiveRecord
source = reflection.source_reflection.name
through_records.first.class.preload_associations(through_records, source)
through_records.each do |through_record|
- add_preloaded_records_to_collection(id_to_record_map[through_record[through_primary_key].to_i],
+ add_preloaded_records_to_collection(id_to_record_map[through_record[through_primary_key].to_s],
reflection.name, through_record.send(source))
end
end
@@ -157,7 +156,7 @@ module ActiveRecord
if reflection.options[:source_type]
interface = reflection.source_reflection.options[:foreign_type]
- preload_options = {:conditions => ["#{interface} = ?", reflection.options[:source_type]]}
+ preload_options = {:conditions => ["#{connection.quote_column_name interface} = ?", reflection.options[:source_type]]}
records.compact!
records.first.class.preload_associations(records, through_association, preload_options)
@@ -196,18 +195,22 @@ module ActiveRecord
records.each do |record|
if klass = record.send(polymorph_type)
klass_id = record.send(primary_key_name)
-
- id_map = klasses_and_ids[klass] ||= {}
- id_list_for_klass_id = (id_map[klass_id] ||= [])
- id_list_for_klass_id << record
+ if klass_id
+ id_map = klasses_and_ids[klass] ||= {}
+ id_list_for_klass_id = (id_map[klass_id.to_s] ||= [])
+ id_list_for_klass_id << record
+ end
end
end
klasses_and_ids = klasses_and_ids.to_a
else
id_map = {}
records.each do |record|
- mapped_records = (id_map[record.send(primary_key_name)] ||= [])
- mapped_records << record
+ key = record.send(primary_key_name)
+ if key
+ mapped_records = (id_map[key.to_s] ||= [])
+ mapped_records << record
+ end
end
klasses_and_ids = [[reflection.klass.name, id_map]]
end
@@ -216,7 +219,7 @@ module ActiveRecord
klass_name, id_map = *klass_and_id
klass = klass_name.constantize
- table_name = klass.table_name
+ table_name = klass.quoted_table_name
primary_key = klass.primary_key
conditions = "#{table_name}.#{primary_key} IN (?)"
conditions << append_conditions(options, preload_options)
@@ -229,16 +232,15 @@ module ActiveRecord
end
end
- # FIXME: quoting
def find_associated_records(ids, reflection, preload_options)
options = reflection.options
- table_name = reflection.klass.table_name
+ table_name = reflection.klass.quoted_table_name
if interface = reflection.options[:as]
- conditions = "#{reflection.klass.table_name}.#{interface}_id IN (?) and #{reflection.klass.table_name}.#{interface}_type = '#{self.base_class.name.demodulize}'"
+ conditions = "#{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_id"} IN (?) and #{reflection.klass.quoted_table_name}.#{connection.quote_column_name "#{interface}_type"} = '#{self.base_class.name.demodulize}'"
else
foreign_key = reflection.primary_key_name
- conditions = "#{reflection.klass.table_name}.#{foreign_key} IN (?)"
+ conditions = "#{reflection.klass.quoted_table_name}.#{foreign_key} IN (?)"
end
conditions << append_conditions(options, preload_options)
diff --git a/activerecord/lib/active_record/associations/association_proxy.rb b/activerecord/lib/active_record/associations/association_proxy.rb
index df21124e92..c415ad2df3 100644
--- a/activerecord/lib/active_record/associations/association_proxy.rb
+++ b/activerecord/lib/active_record/associations/association_proxy.rb
@@ -179,6 +179,16 @@ module ActiveRecord
end
end
+ # Loads the target if needed and returns it.
+ #
+ # This method is abstract in the sense that it relies on +find_target+,
+ # which is expected to be provided by descendants.
+ #
+ # If the target is already loaded it is just returned. Thus, you can call
+ # +load_target+ unconditionally to get the target.
+ #
+ # ActiveRecord::RecordNotFound is rescued within the method, and it is
+ # not reraised. The proxy is reset and +nil+ is the return value.
def load_target
return nil unless defined?(@loaded)
diff --git a/activerecord/lib/active_record/associations/has_many_through_association.rb b/activerecord/lib/active_record/associations/has_many_through_association.rb
index ebea313c18..f683669615 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -10,14 +10,14 @@ module ActiveRecord
def create!(attrs = nil)
@reflection.klass.transaction do
- self << (object = @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create! })
+ self << (object = attrs ? @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create! } : @reflection.klass.create!)
object
end
end
def create(attrs = nil)
@reflection.klass.transaction do
- self << (object = @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create })
+ self << (object = attrs ? @reflection.klass.send(:with_scope, :create => attrs) { @reflection.klass.create } : @reflection.klass.create)
object
end
end
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 8bef5ed2ae..ffefc3cef3 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -11,22 +11,18 @@ module ActiveRecord #:nodoc:
class SubclassNotFound < ActiveRecordError #:nodoc:
end
- # Raised when object assigned to association is of incorrect type.
+ # Raised when an object assigned to an association has an incorrect type.
#
- # Example:
- #
- # class Ticket < ActiveRecord::Base
- # has_many :patches
- # end
- #
- # class Patch < ActiveRecord::Base
- # belongs_to :ticket
- # end
+ # class Ticket < ActiveRecord::Base
+ # has_many :patches
+ # end
#
- # and somewhere in the code:
+ # class Patch < ActiveRecord::Base
+ # belongs_to :ticket
+ # end
#
- # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
- # @ticket.save
+ # # Comments are not patches, this assignment raises AssociationTypeMismatch.
+ # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.")
class AssociationTypeMismatch < ActiveRecordError
end
@@ -59,14 +55,14 @@ module ActiveRecord #:nodoc:
class StatementInvalid < ActiveRecordError
end
- # Raised when number of bind variables in statement given to :condition key (for example, when using +find+ method)
+ # Raised when number of bind variables in statement given to <tt>:condition</tt> key (for example, when using +find+ method)
# does not match number of expected variables.
#
- # Example:
+ # For example, in
#
- # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]
+ # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362]
#
- # in example above two placeholders are given but only one variable to fill them.
+ # two placeholders are given but only one variable to fill them.
class PreparedStatementInvalid < ActiveRecordError
end
@@ -97,8 +93,8 @@ module ActiveRecord #:nodoc:
end
# Raised when you've tried to access a column which wasn't
- # loaded by your finder. Typically this is because :select
- # has been specified
+ # loaded by your finder. Typically this is because <tt>:select</tt>
+ # has been specified.
class MissingAttributeError < NoMethodError
end
@@ -206,7 +202,7 @@ module ActiveRecord #:nodoc:
# # Uses an integer of seconds to hold the length of the song
#
# def length=(minutes)
- # write_attribute(:length, minutes * 60)
+ # write_attribute(:length, minutes.to_i * 60)
# end
#
# def length
@@ -256,7 +252,7 @@ module ActiveRecord #:nodoc:
#
# It's even possible to use all the additional parameters to find. For example, the full interface for Payment.find_all_by_amount
# is actually Payment.find_all_by_amount(amount, options). And the full interface to Person.find_by_user_name is
- # actually Person.find_by_user_name(user_name, options). So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>.
+ # actually <tt>Person.find_by_user_name(user_name, options)</tt>. So you could call <tt>Payment.find_all_by_amount(50, :order => "created_on")</tt>.
#
# The same dynamic finder style can be used to create the object if it doesn't already exist. This dynamic finder is called with
# <tt>find_or_create_by_</tt> and will return the object if it already exists and otherwise creates it, then returns it. Protected attributes won't be set unless they are given in a block. For example:
@@ -423,7 +419,9 @@ module ActiveRecord #:nodoc:
@@default_timezone = :local
# Determines whether to use a connection for each thread, or a single shared connection for all threads.
- # Defaults to false. Set to true if you're writing a threaded application.
+ # Defaults to false. If you're writing a threaded application, set to true
+ # and periodically call verify_active_connections! to clear out connections
+ # assigned to stale threads.
cattr_accessor :allow_concurrency, :instance_writer => false
@@allow_concurrency = false
@@ -455,9 +453,9 @@ module ActiveRecord #:nodoc:
# * <tt>:limit</tt>: An integer determining the limit on the number of rows that should be returned.
# * <tt>:offset</tt>: An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.
# * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
- # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s).
+ # or named associations in the same form used for the <tt>:include</tt> option, which will perform an INNER JOIN on the associated table(s).
# If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns.
- # Pass :readonly => false to override.
+ # Pass <tt>:readonly => false</tt> to override.
# * <tt>:include</tt>: Names associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
# to already defined associations. See eager loading under Associations.
# * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
@@ -466,7 +464,7 @@ module ActiveRecord #:nodoc:
# of a database view).
# * <tt>:readonly</tt>: Mark the returned records read-only so they cannot be saved or updated.
# * <tt>:lock</tt>: An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE".
- # :lock => true gives connection's default exclusive lock, usually "FOR UPDATE".
+ # <tt>:lock => true</tt> gives connection's default exclusive lock, usually "FOR UPDATE".
#
# Examples for find by id:
# Person.find(1) # returns the object for ID = 1
@@ -476,7 +474,7 @@ module ActiveRecord #:nodoc:
# Person.find(1, :conditions => "administrator = 1", :order => "created_on DESC")
#
# Note that returned records may not be in the same order as the ids you
- # provide since database rows are unordered. Give an explicit :order
+ # provide since database rows are unordered. Give an explicit <tt>:order</tt>
# to ensure the results are sorted.
#
# Examples for find first:
@@ -532,6 +530,12 @@ module ActiveRecord #:nodoc:
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
@@ -595,13 +599,25 @@ module ActiveRecord #:nodoc:
# ==== Examples
# # Create a single new object
# User.create(:first_name => 'Jamie')
+ #
# # Create an Array of new objects
# User.create([{:first_name => 'Jamie'}, {:first_name => 'Jeremy'}])
- def create(attributes = nil)
+ #
+ # # Create a single object and pass it into a block to set other attributes.
+ # User.create(:first_name => 'Jamie') do |u|
+ # u.is_admin = false
+ # end
+ #
+ # # 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
+ def create(attributes = nil, &block)
if attributes.is_a?(Array)
- attributes.collect { |attr| create(attr) }
+ attributes.collect { |attr| create(attr, &block) }
else
object = new(attributes)
+ yield(object) if block_given?
object.save
object
end
@@ -691,7 +707,7 @@ module ActiveRecord #:nodoc:
# +updates+ A String of column and value pairs that will be set on any records that match conditions
# +conditions+ An SQL fragment like "administrator = 1" or [ "user_name = ?", username ].
# See conditions in the intro for more info.
- # +options+ Additional options are :limit and/or :order, see the examples for usage.
+ # +options+ Additional options are <tt>:limit</tt> and/or <tt>:order</tt>, see the examples for usage.
#
# ==== Examples
#
@@ -1272,7 +1288,7 @@ module ActiveRecord #:nodoc:
private
def find_initial(options)
- options.update(:limit => 1) unless options[:include]
+ options.update(:limit => 1)
find_every(options).first
end
@@ -1501,7 +1517,7 @@ module ActiveRecord #:nodoc:
end
end
- # The optional scope argument is for the current :find scope.
+ # The optional scope argument is for the current <tt>:find</tt> scope.
def add_limit!(sql, options, scope = :auto)
scope = scope(:find) if :auto == scope
@@ -1513,15 +1529,15 @@ module ActiveRecord #:nodoc:
connection.add_limit_offset!(sql, options)
end
- # The optional scope argument is for the current :find scope.
- # The :lock option has precedence over a scoped :lock.
+ # The optional scope argument is for the current <tt>:find</tt> scope.
+ # The <tt>:lock</tt> option has precedence over a scoped <tt>:lock</tt>.
def add_lock!(sql, options, scope = :auto)
scope = scope(:find) if :auto == scope
options = options.reverse_merge(:lock => scope[:lock]) if scope
connection.add_lock!(sql, options)
end
- # The optional scope argument is for the current :find scope.
+ # The optional scope argument is for the current <tt>:find</tt> scope.
def add_joins!(sql, options, scope = :auto)
scope = scope(:find) if :auto == scope
[(scope && scope[:joins]), options[:joins]].each do |join|
@@ -1536,7 +1552,7 @@ module ActiveRecord #:nodoc:
end
# Adds a sanitized version of +conditions+ to the +sql+ string. Note that the passed-in +sql+ string is changed.
- # The optional scope argument is for the current :find scope.
+ # The optional scope argument is for the current <tt>:find</tt> scope.
def add_conditions!(sql, conditions, scope = :auto)
scope = scope(:find) if :auto == scope
conditions = [conditions]
@@ -1733,8 +1749,8 @@ module ActiveRecord #:nodoc:
protected
# Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash.
- # method_name may be :find or :create. :find parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>,
- # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. :create parameters are an attributes hash.
+ # method_name may be <tt>:find</tt> or <tt>:create</tt>. <tt>:find</tt> parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>,
+ # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. <tt>:create</tt> parameters are an attributes hash.
#
# class Article < ActiveRecord::Base
# def self.create_with_scope
@@ -1747,7 +1763,7 @@ module ActiveRecord #:nodoc:
# end
#
# In nested scopings, all previous parameters are overwritten by the innermost rule, with the exception of
- # :conditions and :include options in :find, which are merged.
+ # <tt>:conditions</tt> and <tt>:include</tt> options in <tt>:find</tt>, which are merged.
#
# class Article < ActiveRecord::Base
# def self.find_with_scope
@@ -2197,9 +2213,9 @@ module ActiveRecord #:nodoc:
record
end
- # Returns an instance of the specified klass with the attributes of the current record. This is mostly useful in relation to
+ # Returns an instance of the specified +klass+ with the attributes of the current record. This is mostly useful in relation to
# single-table inheritance structures where you want a subclass to appear as the superclass. This can be used along with record
- # identification in Action Pack to allow, say, Client < Company to do something like render :partial => @client.becomes(Company)
+ # identification in Action Pack to allow, say, <tt>Client < Company</tt> to do something like render <tt>:partial => @client.becomes(Company)</tt>
# to render that instance using the companies/company partial instead of clients/client.
#
# Note: The new instance will share a link to the same attributes as the original class. So any change to the attributes in either
diff --git a/activerecord/lib/active_record/calculations.rb b/activerecord/lib/active_record/calculations.rb
index b5bf82ee11..3c5caefe3b 100644
--- a/activerecord/lib/active_record/calculations.rb
+++ b/activerecord/lib/active_record/calculations.rb
@@ -9,16 +9,16 @@ module ActiveRecord
# Count operates using three different approaches.
#
# * Count all: By not passing any parameters to count, it will return a count of all the rows for the model.
- # * Count using column : By passing a column name to count, it will return a count of all the rows for the model with supplied column present
+ # * Count using column: By passing a column name to count, it will return a count of all the rows for the model with supplied column present
# * Count using options will find the row count matched by the options used.
#
# The third approach, count using options, accepts an option hash as the only parameter. The options are:
#
# * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
# * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
- # or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s).
+ # or named associations in the same form used for the <tt>:include</tt> option, which will perform an INNER JOIN on the associated table(s).
# If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns.
- # Pass :readonly => false to override.
+ # Pass <tt>:readonly => false</tt> to override.
# * <tt>:include</tt>: Named associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
# to already defined associations. When using named associations, count returns the number of DISTINCT items for the model you're counting.
# See eager loading under Associations.
@@ -41,7 +41,7 @@ module ActiveRecord
# Person.count('id', :conditions => "age > 26") # Performs a COUNT(id)
# Person.count(:all, :conditions => "age > 26") # Performs a COUNT(*) (:all is an alias for '*')
#
- # Note: Person.count(:all) will not work because it will use :all as the condition. Use Person.count instead.
+ # Note: <tt>Person.count(:all)</tt> will not work because it will use <tt>:all</tt> as the condition. Use Person.count instead.
def count(*args)
calculate(:count, *construct_count_options_from_args(*args))
end
@@ -75,11 +75,11 @@ module ActiveRecord
end
# This calculates aggregate values in the given column. Methods for count, sum, average, minimum, and maximum have been added as shortcuts.
- # Options such as :conditions, :order, :group, :having, and :joins can be passed to customize the query.
+ # Options such as <tt>:conditions</tt>, <tt>:order</tt>, <tt>:group</tt>, <tt>:having</tt>, and <tt>:joins</tt> can be passed to customize the query.
#
# There are two basic forms of output:
# * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float for AVG, and the given column's type for everything else.
- # * Grouped values: This returns an ordered hash of the values and groups them by the :group option. It takes either a column name, or the name
+ # * Grouped values: This returns an ordered hash of the values and groups them by the <tt>:group</tt> option. It takes either a column name, or the name
# of a belongs_to association.
#
# values = Person.maximum(:age, :group => 'last_name')
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
index d950181566..34627dfaf9 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
@@ -175,7 +175,7 @@ module ActiveRecord
end
# Establishes the connection to the database. Accepts a hash as input where
- # the :adapter key must be specified with the name of a database adapter (in lower-case)
+ # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
# example for regular databases (MySQL, Postgresql, etc):
#
# ActiveRecord::Base.establish_connection(
@@ -194,6 +194,7 @@ module ActiveRecord
# )
#
# Also accepts keys as strings (for parsing from yaml for example):
+ #
# ActiveRecord::Base.establish_connection(
# "adapter" => "sqlite",
# "database" => "path/to/dbfile"
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
index d30f9b4d32..d73ffc3da6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb
@@ -398,8 +398,8 @@ module ActiveRecord
# TableDefinition#timestamps that'll add created_at and updated_at as datetimes.
#
# TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
- # column if the :polymorphic option is supplied. If :polymorphic is a hash of options, these will be
- # used when creating the _type column. So what can be written like this:
+ # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of options, these will be
+ # used when creating the <tt>_type</tt> column. So what can be written like this:
#
# create_table :taggings do |t|
# t.integer :tag_id, :tagger_id, :taggable_id
@@ -469,5 +469,195 @@ module ActiveRecord
@base.native_database_types
end
end
+
+ # Represents a SQL table in an abstract way for updating a table.
+ # Also see TableDefinition and SchemaStatements#create_table
+ #
+ # Available transformations are:
+ #
+ # change_table :table do |t|
+ # t.column
+ # t.index
+ # t.timestamps
+ # t.change
+ # t.change_default
+ # t.rename
+ # t.references
+ # t.belongs_to
+ # t.string
+ # t.text
+ # t.integer
+ # t.float
+ # t.decimal
+ # t.datetime
+ # t.timestamp
+ # t.time
+ # t.date
+ # t.binary
+ # t.boolean
+ # t.remove
+ # t.remove_references
+ # t.remove_belongs_to
+ # t.remove_index
+ # t.remove_timestamps
+ # end
+ #
+ class Table
+ def initialize(table_name, base)
+ @table_name = table_name
+ @base = base
+ end
+
+ # Adds a new column to the named table.
+ # See TableDefinition#column for details of the options you can use.
+ # ===== Examples
+ # ====== Creating a simple columns
+ # t.column(:name, :string)
+ def column(column_name, type, options = {})
+ @base.add_column(@table_name, column_name, type, options)
+ end
+
+ # Adds a new index to the table. +column_name+ can be a single Symbol, or
+ # an Array of Symbols. See SchemaStatements#add_index
+ #
+ # ===== Examples
+ # ====== Creating a simple index
+ # t.index(:name)
+ # ====== Creating a unique index
+ # t.index([:branch_id, :party_id], :unique => true)
+ # ====== Creating a named index
+ # t.index([:branch_id, :party_id], :unique => true, :name => 'by_branch_party')
+ def index(column_name, options = {})
+ @base.add_index(@table_name, column_name, options)
+ end
+
+ # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#timestamps
+ # ===== Examples
+ # t.timestamps
+ def timestamps
+ @base.add_timestamps(@table_name)
+ end
+
+ # Changes the column's definition according to the new options.
+ # See TableDefinition#column for details of the options you can use.
+ # ===== Examples
+ # t.change(:name, :string, :limit => 80)
+ # t.change(:description, :text)
+ def change(column_name, type, options = {})
+ @base.change_column(@table_name, column_name, type, options)
+ end
+
+ # Sets a new default value for a column. See
+ # ===== Examples
+ # t.change_default(:qualification, 'new')
+ # t.change_default(:authorized, 1)
+ def change_default(column_name, default)
+ @base.change_column_default(@table_name, column_name, default)
+ end
+
+ # Removes the column(s) from the table definition.
+ # ===== Examples
+ # t.remove(:qualification)
+ # t.remove(:qualification, :experience)
+ # t.removes(:qualification, :experience)
+ def remove(*column_names)
+ @base.remove_column(@table_name, column_names)
+ end
+
+ # Remove the given index from the table.
+ #
+ # Remove the suppliers_name_index in the suppliers table.
+ # t.remove_index :name
+ # Remove the index named accounts_branch_id_index in the accounts table.
+ # t.remove_index :column => :branch_id
+ # Remove the index named accounts_branch_id_party_id_index in the accounts table.
+ # t.remove_index :column => [:branch_id, :party_id]
+ # Remove the index named by_branch_party in the accounts table.
+ # t.remove_index :name => :by_branch_party
+ def remove_index(options = {})
+ @base.remove_index(@table_name, options)
+ end
+
+ # Removes the timestamp columns (created_at and updated_at) from the table.
+ # ===== Examples
+ # t.remove_timestamps
+ def remove_timestamps
+ @base.remove_timestamps(@table_name)
+ end
+
+ # Renames a column.
+ # ===== Example
+ # t.rename(:description, :name)
+ def rename(column_name, new_column_name)
+ @base.rename_column(@table_name, column_name, new_column_name)
+ end
+
+ # Adds a reference. Optionally adds a +type+ column. <tt>reference</tt>,
+ # <tt>references</tt> and <tt>belongs_to</tt> are all acceptable
+ # ===== Example
+ # t.references(:goat)
+ # t.references(:goat, :polymorphic => true)
+ # t.references(:goat)
+ # t.belongs_to(:goat)
+ def references(*args)
+ options = args.extract_options!
+ polymorphic = options.delete(:polymorphic)
+ args.each do |col|
+ @base.add_column(@table_name, "#{col}_id", :integer, options)
+ @base.add_column(@table_name, "#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) unless polymorphic.nil?
+ end
+ end
+ alias :belongs_to :references
+
+ # Adds a reference. Optionally removes a +type+ column. <tt>remove_reference</tt>,
+ # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are all acceptable
+ # ===== Example
+ # t.remove_reference(:goat)
+ # t.remove_reference(:goat, :polymorphic => true)
+ # t.remove_references(:goat)
+ # t.remove_belongs_to(:goat)
+ def remove_references(*args)
+ options = args.extract_options!
+ polymorphic = options.delete(:polymorphic)
+ args.each do |col|
+ @base.remove_column(@table_name, "#{col}_id")
+ @base.remove_column(@table_name, "#{col}_type") unless polymorphic.nil?
+ end
+ end
+ alias :remove_belongs_to :remove_references
+
+ # Adds a column or columns of a specified type
+ # ===== Example
+ # t.string(:goat)
+ # t.string(:goat, :sheep)
+ %w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
+ class_eval <<-EOV
+ def #{column_type}(*args)
+ options = args.extract_options!
+ column_names = args
+
+ column_names.each do |name|
+ column = ColumnDefinition.new(@base, name, '#{column_type}')
+ if options[:limit]
+ column.limit = options[:limit]
+ elsif native['#{column_type}'.to_sym].is_a?(Hash)
+ column.limit = native['#{column_type}'.to_sym][:limit]
+ end
+ column.precision = options[:precision]
+ column.scale = options[:scale]
+ column.default = options[:default]
+ column.null = options[:null]
+ @base.add_column(@table_name, name, column.sql_type, options)
+ end
+ end
+ EOV
+ end
+
+ private
+ def native
+ @base.native_database_types
+ end
+ end
+
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index c986f0c6f1..6aae556d67 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -45,7 +45,7 @@ module ActiveRecord
# The +options+ hash can include the following keys:
# [<tt>:id</tt>]
# Whether to automatically add a primary key column. Defaults to true.
- # Join tables for has_and_belongs_to_many should set :id => false.
+ # Join tables for +has_and_belongs_to_many+ should set <tt>:id => false</tt>.
# [<tt>:primary_key</tt>]
# The name of the primary key, if one is to be added automatically.
# Defaults to +id+.
@@ -104,6 +104,67 @@ module ActiveRecord
execute create_sql
end
+ # A block for changing columns in +table+.
+ #
+ # === Example
+ # # change_table() yields a Table instance
+ # change_table(:suppliers) do |t|
+ # t.column :name, :string, :limit => 60
+ # # Other column alterations here
+ # end
+ #
+ # ===== Examples
+ # ====== Add a column
+ # change_table(:suppliers) do |t|
+ # t.column :name, :string, :limit => 60
+ # end
+ #
+ # ====== Add 2 integer columns
+ # change_table(:suppliers) do |t|
+ # t.integer :width, :height, :null => false, :default => 0
+ # end
+ #
+ # ====== Add created_at/updated_at columns
+ # change_table(:suppliers) do |t|
+ # t.timestamps
+ # end
+ #
+ # ====== Add a foreign key column
+ # change_table(:suppliers) do |t|
+ # t.references :company
+ # end
+ #
+ # Creates a <tt>company_id(integer)</tt> column
+ #
+ # ====== Add a polymorphic foreign key column
+ # change_table(:suppliers) do |t|
+ # t.belongs_to :company, :polymorphic => true
+ # end
+ #
+ # Creates <tt>company_type(varchar)</tt> and <tt>company_id(integer)</tt> columns
+ #
+ # ====== Remove a column
+ # change_table(:suppliers) do |t|
+ # t.remove :company
+ # end
+ #
+ # ====== Remove a column
+ # change_table(:suppliers) do |t|
+ # t.remove :company_id
+ # t.remove :width, :height
+ # end
+ #
+ # ====== Remove an index
+ # change_table(:suppliers) do |t|
+ # t.remove_index :company_id
+ # end
+ #
+ # See also Table for details on
+ # all of the various column transformation
+ def change_table(table_name)
+ yield Table.new(table_name, self)
+ end
+
# Renames a table.
# ===== Example
# rename_table('octopuses', 'octopi')
@@ -124,13 +185,17 @@ module ActiveRecord
execute(add_column_sql)
end
- # Removes the column from the table definition.
+ # Removes the column(s) from the table definition.
# ===== Examples
# remove_column(:suppliers, :qualification)
- def remove_column(table_name, column_name)
- execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
+ # remove_columns(:suppliers, :qualification, :experience)
+ def remove_column(table_name, *column_names)
+ column_names.flatten.each do |column_name|
+ execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}"
+ end
end
-
+ alias :remove_columns :remove_column
+
# Changes the column's definition according to the new options.
# See TableDefinition#column for details of the options you can use.
# ===== Examples
@@ -297,7 +362,14 @@ module ActiveRecord
def add_column_options!(sql, options) #:nodoc:
sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
- sql << " NOT NULL" if options[:null] == false
+ # must explcitly check for :null to allow change_column to work on migrations
+ if options.has_key? :null
+ if options[:null] == false
+ sql << " NOT NULL"
+ else
+ sql << " NULL"
+ end
+ end
end
# SELECT DISTINCT clause for a given set of columns and a given ORDER BY clause.
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 6432c3cfee..e742d60c5f 100755
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -196,7 +196,7 @@ module ActiveRecord
:primary_key => "int(11) DEFAULT NULL auto_increment PRIMARY KEY",
:string => { :name => "varchar", :limit => 255 },
:text => { :name => "text" },
- :integer => { :name => "int", :limit => 11 },
+ :integer => { :name => "int"},
:float => { :name => "float" },
:decimal => { :name => "decimal" },
:datetime => { :name => "datetime" },
@@ -365,7 +365,7 @@ module ActiveRecord
create_database(name)
end
- # Create a new MySQL database with optional :charset and :collation.
+ # Create a new MySQL database with optional <tt>:charset</tt> and <tt>:collation</tt>.
# Charset defaults to utf8.
#
# Example:
@@ -463,6 +463,22 @@ module ActiveRecord
execute "ALTER TABLE #{quote_table_name(table_name)} CHANGE #{quote_column_name(column_name)} #{quote_column_name(new_column_name)} #{current_type}"
end
+ # Maps logical Rails types to MySQL-specific data types.
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
+ return super unless type.to_s == 'integer'
+
+ case limit
+ when 0..3
+ "smallint(#{limit})"
+ when 4..8
+ "int(#{limit})"
+ when 9..20
+ "bigint(#{limit})"
+ else
+ 'int(11)'
+ end
+ end
+
# SHOW VARIABLES LIKE 'name'
def show_variable(name)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 54b50fabd8..e3f7969cdf 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -233,7 +233,7 @@ module ActiveRecord
# * <tt>:username</tt> -- Defaults to nothing
# * <tt>:password</tt> -- Defaults to nothing
# * <tt>:database</tt> -- The name of the database. No default, must be provided.
- # * <tt>:schema_search_path</tt> -- An optional schema search path for the connection given as a string of comma-separated schema names. This is backward-compatible with the :schema_order option.
+ # * <tt>:schema_search_path</tt> -- An optional schema search path for the connection given as a string of comma-separated schema names. This is backward-compatible with the <tt>:schema_order</tt> option.
# * <tt>:encoding</tt> -- An optional client encoding that is used in a SET client_encoding TO <encoding> call on the connection.
# * <tt>:min_messages</tt> -- An optional client min messages that is used in a SET client_min_messages TO <min_messages> call on the connection.
# * <tt>:allow_concurrency</tt> -- If true, use async query methods so Ruby threads don't deadlock; otherwise, use blocking query methods.
@@ -479,9 +479,9 @@ module ActiveRecord
create_database(name)
end
- # Create a new PostgreSQL database. Options include :owner, :template,
- # :encoding, :tablespace, and :connection_limit (note that MySQL uses
- # :charset while PostgreSQL uses :encoding).
+ # Create a new PostgreSQL database. Options include <tt>:owner</tt>, <tt>:template</tt>,
+ # <tt>:encoding</tt>, <tt>:tablespace</tt>, and <tt>:connection_limit</tt> (note that MySQL uses
+ # <tt>:charset</tt> while PostgreSQL uses <tt>:encoding</tt>).
#
# Example:
# create_database config[:database], config
diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
index 59a51c0279..8fa62c1845 100644
--- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb
@@ -219,11 +219,14 @@ module ActiveRecord
execute "VACUUM"
end
- def remove_column(table_name, column_name) #:nodoc:
- alter_table(table_name) do |definition|
- definition.columns.delete(definition[column_name])
+ def remove_column(table_name, *column_names) #:nodoc:
+ column_names.flatten.each do |column_name|
+ alter_table(table_name) do |definition|
+ definition.columns.delete(definition[column_name])
+ end
end
end
+ alias :remove_columns :remove_column
def change_column_default(table_name, column_name, default) #:nodoc:
alter_table(table_name) do |definition|
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index f5b2e73da9..7d5fd35dae 100755
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -469,8 +469,8 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
fixtures.size > 1 ? fixtures : fixtures.first
end
- def self.cache_fixtures(connection, fixtures)
- cache_for_connection(connection).update(fixtures.index_by { |f| f.table_name })
+ def self.cache_fixtures(connection, fixtures_map)
+ cache_for_connection(connection).update(fixtures_map)
end
def self.instantiate_fixtures(object, table_name, fixtures, load_instances = true)
@@ -526,7 +526,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
end
end
- cache_fixtures(connection, fixtures)
+ cache_fixtures(connection, fixtures_map)
end
end
end
diff --git a/activerecord/lib/active_record/locking/optimistic.rb b/activerecord/lib/active_record/locking/optimistic.rb
index f2c2c5f070..65f88cfdc7 100644
--- a/activerecord/lib/active_record/locking/optimistic.rb
+++ b/activerecord/lib/active_record/locking/optimistic.rb
@@ -78,7 +78,7 @@ module ActiveRecord
begin
affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking")
- UPDATE #{self.class.table_name}
+ UPDATE #{self.class.quoted_table_name}
SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, false, attribute_names))}
WHERE #{self.class.primary_key} = #{quote_value(id)}
AND #{self.class.quoted_locking_column} = #{quote_value(previous_value)}
diff --git a/activerecord/lib/active_record/locking/pessimistic.rb b/activerecord/lib/active_record/locking/pessimistic.rb
index caad760742..320659596f 100644
--- a/activerecord/lib/active_record/locking/pessimistic.rb
+++ b/activerecord/lib/active_record/locking/pessimistic.rb
@@ -25,12 +25,12 @@ module ActiveRecord
# Locking::Pessimistic provides support for row-level locking using
# SELECT ... FOR UPDATE and other lock types.
#
- # Pass :lock => true to ActiveRecord::Base.find to obtain an exclusive
+ # Pass <tt>:lock => true</tt> to ActiveRecord::Base.find to obtain an exclusive
# lock on the selected rows:
# # select * from accounts where id=1 for update
# Account.find(1, :lock => true)
#
- # Pass :lock => 'some locking clause' to give a database-specific locking clause
+ # Pass <tt>:lock => 'some locking clause'</tt> to give a database-specific locking clause
# of your own such as 'LOCK IN SHARE MODE' or 'FOR UPDATE NOWAIT'.
#
# Example:
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 1d63bb2f84..af4fb6e83c 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -76,16 +76,16 @@ module ActiveRecord
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+ to +new_name+.
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column to the table called +table_name+
# named +column_name+ specified to be one of the following types:
- # :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time,
- # :date, :binary, :boolean. A default value can be specified by passing an
- # +options+ hash like { :default => 11 }. Other options include :limit and :null (e.g. { :limit => 50, :null => false })
+ # <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
+ # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be specified by passing an
+ # +options+ hash like <tt>{ :default => 11 }</tt>. Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g. <tt>{ :limit => 50, :null => false }</tt>)
# -- see ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames a column but keeps the type and content.
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes the column to a different type using the same
# parameters as add_column.
# * <tt>remove_column(table_name, column_name)</tt>: Removes the column named +column_name+ from the table called +table_name+.
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index with the name of the column. Other options include
- # :name and :unique (e.g. { :name => "users_name_index", :unique => true }).
+ # <tt>:name</tt> and <tt>:unique</tt> (e.g. <tt>{ :name => "users_name_index", :unique => true }</tt>).
# * <tt>remove_index(table_name, index_name)</tt>: Removes the index specified by +index_name+.
#
# == Irreversible transformations
diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb
index 120ec88f95..81b99f8e96 100644
--- a/activerecord/lib/active_record/named_scope.rb
+++ b/activerecord/lib/active_record/named_scope.rb
@@ -11,7 +11,6 @@ module ActiveRecord
def self.included(base)
base.class_eval do
extend ClassMethods
- named_scope :all
named_scope :scoped, lambda { |scope| scope }
end
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 3f11133e8c..61005af83f 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -45,7 +45,7 @@ module ActiveRecord
end
# Returns an array of AssociationReflection objects for all the associations in the class. If you only want to reflect on a
- # certain association type, pass in the symbol (:has_many, :has_one, :belongs_to) for that as the first parameter.
+ # certain association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>, <tt>:belongs_to</tt>) for that as the first parameter.
# Example:
#
# Account.reflect_on_all_associations # returns an array of all associations
@@ -90,13 +90,12 @@ module ActiveRecord
# Returns the hash of options used for the macro. For example, it would return <tt>{ :class_name => "Money" }</tt> for
# <tt>composed_of :balance, :class_name => 'Money'</tt> or +{}+ for <tt>has_many :clients</tt>.
-
def options
@options
end
- # Returns the class for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns the +Money+
- # class and <tt>has_many :clients</tt> returns the +Client+ class.
+ # Returns the class for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money
+ # class and <tt>has_many :clients</tt> returns the Client class.
def klass
@klass ||= class_name.constantize
end
@@ -158,16 +157,16 @@ module ActiveRecord
@through_reflection ||= options[:through] ? active_record.reflect_on_association(options[:through]) : false
end
- # Gets an array of possible :through source reflection names
+ # Gets an array of possible <tt>:through</tt> source reflection names:
#
- # [singularized, pluralized]
+ # [:singularized, :pluralized]
#
def source_reflection_names
@source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
end
- # Gets the source of the through reflection. It checks both a singularized and pluralized form for :belongs_to or :has_many.
- # (The :tags association on Tagging below)
+ # Gets the source of the through reflection. It checks both a singularized and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
+ # (The <tt>:tags</tt> association on Tagging below.)
#
# class Post
# has_many :tags, :through => :taggings
diff --git a/activerecord/lib/active_record/serialization.rb b/activerecord/lib/active_record/serialization.rb
index 2c8210a299..332cda1e16 100644
--- a/activerecord/lib/active_record/serialization.rb
+++ b/activerecord/lib/active_record/serialization.rb
@@ -8,11 +8,11 @@ module ActiveRecord #:nodoc:
end
# To replicate the behavior in ActiveRecord#attributes,
- # :except takes precedence over :only. If :only is not set
+ # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
# for a N level model but is set for the N+1 level models,
- # then because :except is set to a default value, the second
- # level model can have both :except and :only set. So if
- # :only is set, always delete :except.
+ # then because <tt>:except</tt> is set to a default value, the second
+ # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
+ # <tt>:only</tt> is set, always delete <tt>:except</tt>.
def serializable_attribute_names
attribute_names = @record.attribute_names
@@ -38,7 +38,7 @@ module ActiveRecord #:nodoc:
serializable_attribute_names + serializable_method_names
end
- # Add associations specified via the :includes option.
+ # Add associations specified via the <tt>:includes</tt> option.
# Expects a block that takes as arguments:
# +association+ - name of the association
# +records+ - the association record(s) to be serialized
diff --git a/activerecord/lib/active_record/serializers/json_serializer.rb b/activerecord/lib/active_record/serializers/json_serializer.rb
index d024adba39..419b45d475 100644
--- a/activerecord/lib/active_record/serializers/json_serializer.rb
+++ b/activerecord/lib/active_record/serializers/json_serializer.rb
@@ -16,8 +16,8 @@ module ActiveRecord #:nodoc:
# # => {"id": 1, "name": "Konata Izumi", "age": 16,
# "created_at": "2006/08/01", "awesome": true}
#
- # The :only and :except options can be used to limit the attributes
- # included, and work similar to the #attributes method. For example:
+ # The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the attributes
+ # included, and work similar to the +attributes+ method. For example:
#
# konata.to_json(:only => [ :id, :name ])
# # => {"id": 1, "name": "Konata Izumi"}
@@ -25,14 +25,14 @@ module ActiveRecord #:nodoc:
# konata.to_json(:except => [ :id, :created_at, :age ])
# # => {"name": "Konata Izumi", "awesome": true}
#
- # To include any methods on the model, use :methods.
+ # To include any methods on the model, use <tt>:methods</tt>.
#
# konata.to_json(:methods => :permalink)
# # => {"id": 1, "name": "Konata Izumi", "age": 16,
# "created_at": "2006/08/01", "awesome": true,
# "permalink": "1-konata-izumi"}
#
- # To include associations, use :include.
+ # To include associations, use <tt>:include</tt>.
#
# konata.to_json(:include => :posts)
# # => {"id": 1, "name": "Konata Izumi", "age": 16,
diff --git a/activerecord/lib/active_record/serializers/xml_serializer.rb b/activerecord/lib/active_record/serializers/xml_serializer.rb
index fbd15e06dc..2d0887ecf0 100644
--- a/activerecord/lib/active_record/serializers/xml_serializer.rb
+++ b/activerecord/lib/active_record/serializers/xml_serializer.rb
@@ -2,7 +2,7 @@ module ActiveRecord #:nodoc:
module Serialization
# Builds an XML document to represent the model. Some configuration is
# available through +options+. However more complicated cases should
- # override ActiveRecord's to_xml method.
+ # override ActiveRecord::Base#to_xml.
#
# By default the generated XML document will include the processing
# instruction and all the object's attributes. For example:
@@ -22,12 +22,12 @@ module ActiveRecord #:nodoc:
# <last-read type="date">2004-04-15</last-read>
# </topic>
#
- # This behavior can be controlled with :only, :except,
- # :skip_instruct, :skip_types and :dasherize. The :only and
- # :except options are the same as for the #attributes method.
- # The default is to dasherize all column names, to disable this,
- # set :dasherize to false. To not have the column type included
- # in the XML output, set :skip_types to true.
+ # This behavior can be controlled with <tt>:only</tt>, <tt>:except</tt>,
+ # <tt>:skip_instruct</tt>, <tt>:skip_types</tt> and <tt>:dasherize</tt>.
+ # The <tt>:only</tt> and <tt>:except</tt> options are the same as for the
+ # +attributes+ method. The default is to dasherize all column names, but you
+ # can disable this setting <tt>:dasherize</tt> to +false+. To not have the
+ # column type included in the XML output set <tt>:skip_types</tt> to +true+.
#
# For instance:
#
@@ -43,7 +43,7 @@ module ActiveRecord #:nodoc:
# <last-read type="date">2004-04-15</last-read>
# </topic>
#
- # To include first level associations use :include
+ # To include first level associations use <tt>:include</tt>:
#
# firm.to_xml :include => [ :account, :clients ]
#
@@ -98,7 +98,7 @@ module ActiveRecord #:nodoc:
# </account>
# </firm>
#
- # To include any methods on the object(s) being called use :methods
+ # To include any methods on the model being called use <tt>:methods</tt>:
#
# firm.to_xml :methods => [ :calculated_earnings, :real_earnings ]
#
@@ -108,9 +108,8 @@ module ActiveRecord #:nodoc:
# <real-earnings>5</real-earnings>
# </firm>
#
- # To call any Procs on the object(s) use :procs. The Procs
- # are passed a modified version of the options hash that was
- # given to #to_xml.
+ # To call any additional Procs use <tt>:procs</tt>. The Procs are passed a
+ # modified version of the options hash that was given to +to_xml+:
#
# proc = Proc.new { |options| options[:builder].tag!('abc', 'def') }
# firm.to_xml :procs => [ proc ]
@@ -120,7 +119,7 @@ module ActiveRecord #:nodoc:
# <abc>def</abc>
# </firm>
#
- # Alternatively, you can yield the builder object as part of the to_xml call:
+ # Alternatively, you can yield the builder object as part of the +to_xml+ call:
#
# firm.to_xml do |xml|
# xml.creator do
@@ -137,8 +136,9 @@ module ActiveRecord #:nodoc:
# </creator>
# </firm>
#
- # You can override the to_xml method in your ActiveRecord::Base
- # subclasses if you need to. The general form of doing this is:
+ # As noted above, you may override +to_xml+ in your ActiveRecord::Base
+ # subclasses to have complete control about what's generated. The general
+ # form of doing this is:
#
# class IHaveMyOwnXML < ActiveRecord::Base
# def to_xml(options = {})
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index 1d12ea8ad7..50db32725d 100755
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -201,7 +201,7 @@ module ActiveRecord
alias_method :count, :size
alias_method :length, :size
- # Return an XML representation of this error object.
+ # Returns an XML representation of this error object.
#
# class Company < ActiveRecord::Base
# validates_presence_of :name, :address, :email
@@ -266,7 +266,7 @@ module ActiveRecord
# person.attributes = { "last_name" => "Heinemeier", "phone_number" => "555-555" }
# person.save # => true (and person is now saved in the database)
#
- # An +Errors+ object is automatically created for every Active Record.
+ # An Errors object is automatically created for every Active Record.
#
# Please do have a look at ActiveRecord::Validations::ClassMethods for a higher level of validations.
module Validations
@@ -286,7 +286,7 @@ module ActiveRecord
# All of the following validations are defined in the class scope of the model that you're interested in validating.
# They offer a more declarative way of specifying when the model is valid and when it is not. It is recommended to use
- # these over the low-level calls to validate and validate_on_create when possible.
+ # these over the low-level calls to +validate+ and +validate_on_create+ when possible.
module ClassMethods
DEFAULT_VALIDATION_OPTIONS = {
:on => :save,
@@ -337,14 +337,14 @@ module ActiveRecord
# end
#
# Options:
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>allow_nil</tt> - Skip validation if attribute is nil.
- # * <tt>allow_blank</tt> - Skip validation if attribute is blank.
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
+ # * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_each(*attrs)
options = attrs.extract_options!.symbolize_keys
@@ -374,19 +374,19 @@ module ActiveRecord
#
# The added +password_confirmation+ attribute is virtual; it exists only as an in-memory attribute for validating the password.
# To achieve this, the validation adds accessors to the model for the confirmation attribute. NOTE: This check is performed
- # only if +password_confirmation+ is not nil, and by default only on save. To require confirmation, make sure to add a presence
+ # only if +password_confirmation+ is not +nil+, and by default only on save. To require confirmation, make sure to add a presence
# check for the confirmation attribute:
#
# validates_presence_of :password_confirmation, :if => :password_changed?
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "doesn't match confirmation")
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "doesn't match confirmation").
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_confirmation_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save }
@@ -406,21 +406,21 @@ module ActiveRecord
# validates_acceptance_of :eula, :message => "must be abided"
# end
#
- # If the database column does not exist, the terms_of_service attribute is entirely virtual. This check is
- # performed only if terms_of_service is not nil and by default on save.
+ # If the database column does not exist, the +terms_of_service+ attribute is entirely virtual. This check is
+ # performed only if +terms_of_service+ is not +nil+ and by default on save.
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "must be accepted")
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>allow_nil</tt> - Skip validation if attribute is nil. (default is true)
- # * <tt>accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which
- # makes it easy to relate to an HTML checkbox. This should be set to 'true' if you are validating a database
- # column, since the attribute is typecast from "1" to <tt>true</tt> before validation.
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "must be accepted").
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is true).
+ # * <tt>:accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which
+ # makes it easy to relate to an HTML checkbox. This should be set to +true+ if you are validating a database
+ # column, since the attribute is typecast from "1" to +true+ before validation.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_acceptance_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" }
@@ -452,8 +452,8 @@ module ActiveRecord
# This is due to the way Object#blank? handles boolean values. false.blank? # => true
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "can't be blank")
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
+ # * <tt>message</tt> - A custom error message (default is: "can't be blank").
+ # * <tt>on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
# occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
# method, proc or string should return or evaluate to a true or false value.
@@ -485,24 +485,24 @@ module ActiveRecord
# end
#
# Configuration options:
- # * <tt>minimum</tt> - The minimum size of the attribute
- # * <tt>maximum</tt> - The maximum size of the attribute
- # * <tt>is</tt> - The exact size of the attribute
- # * <tt>within</tt> - A range specifying the minimum and maximum size of the attribute
- # * <tt>in</tt> - A synonym(or alias) for :within
- # * <tt>allow_nil</tt> - Attribute may be nil; skip validation.
- # * <tt>allow_blank</tt> - Attribute may be blank; skip validation.
- #
- # * <tt>too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)")
- # * <tt>too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)")
- # * <tt>wrong_length</tt> - The error message if using the :is method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)")
- # * <tt>message</tt> - The error message to use for a :minimum, :maximum, or :is violation. An alias of the appropriate too_long/too_short/wrong_length message
- # * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:minimum</tt> - The minimum size of the attribute.
+ # * <tt>:maximum</tt> - The maximum size of the attribute.
+ # * <tt>:is</tt> - The exact size of the attribute.
+ # * <tt>:within</tt> - A range specifying the minimum and maximum size of the attribute.
+ # * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
+ # * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
+ # * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
+ #
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %d characters)").
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %d characters)").
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %d characters)").
+ # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_length_of(*attrs)
# Merge given options with defaults.
@@ -584,16 +584,16 @@ module ActiveRecord
# unique index on the field. See +add_index+ for more information.
#
# Configuration options:
- # * <tt>message</tt> - Specifies a custom error message (default is: "has already been taken")
- # * <tt>scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint.
- # * <tt>case_sensitive</tt> - Looks for an exact match. Ignored by non-text columns (true by default).
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "has already been taken").
+ # * <tt>:scope</tt> - One or more columns by which to limit the scope of the uniqueness constraint.
+ # * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by non-text columns (+false+ by default).
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_uniqueness_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:taken], :case_sensitive => true }
@@ -669,21 +669,21 @@ module ActiveRecord
# validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
# end
#
- # Note: use \A and \Z to match the start and end of the string, ^ and $ match the start/end of a line.
+ # Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string, <tt>^</tt> and <tt>$</tt> match the start/end of a line.
#
# A regular expression must be provided or else an exception will be raised.
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "is invalid")
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>with</tt> - The regular expression used to validate the format with (note: must be supplied!)
- # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "is invalid").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:with</tt> - The regular expression used to validate the format with (note: must be supplied!).
+ # * <tt>:on</tt> Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_format_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save, :with => nil }
@@ -705,15 +705,15 @@ module ActiveRecord
# end
#
# Configuration options:
- # * <tt>in</tt> - An enumerable object of available items
- # * <tt>message</tt> - Specifies a custom error message (default is: "is not included in the list")
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:in</tt> - An enumerable object of available items.
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is not included in the list").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_inclusion_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:inclusion], :on => :save }
@@ -737,15 +737,15 @@ module ActiveRecord
# end
#
# Configuration options:
- # * <tt>in</tt> - An enumerable object of items that the value shouldn't be part of
- # * <tt>message</tt> - Specifies a custom error message (default is: "is reserved")
- # * <tt>allow_nil</tt> - If set to true, skips this validation if the attribute is null (default is: false)
- # * <tt>allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is: false)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:in</tt> - An enumerable object of items that the value shouldn't be part of.
+ # * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
+ # * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute is +nil+ (default is +false+).
+ # * <tt>:allow_blank</tt> - If set to true, skips this validation if the attribute is blank (default is +false+).
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_exclusion_of(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:exclusion], :on => :save }
@@ -777,19 +777,19 @@ module ActiveRecord
# validates_associated :book
# end
#
- # ...this would specify a circular dependency and cause infinite recursion.
+ # this would specify a circular dependency and cause infinite recursion.
#
# NOTE: This validation will not fail if the association hasn't been assigned. If you want to ensure that the association
- # is both present and guaranteed to be valid, you also need to use validates_presence_of.
+ # is both present and guaranteed to be valid, you also need to use +validates_presence_of+.
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "is invalid")
- # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "is invalid")
+ # * <tt>:on</tt> Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>)
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_associated(*attr_names)
configuration = { :message => ActiveRecord::Errors.default_error_messages[:invalid], :on => :save }
@@ -810,22 +810,22 @@ module ActiveRecord
# end
#
# Configuration options:
- # * <tt>message</tt> - A custom error message (default is: "is not a number")
- # * <tt>on</tt> Specifies when this validation is active (default is :save, other options :create, :update)
- # * <tt>only_integer</tt> Specifies whether the value has to be an integer, e.g. an integral value (default is false)
- # * <tt>allow_nil</tt> Skip validation if attribute is nil (default is false). Notice that for fixnum and float columns empty strings are converted to nil
- # * <tt>greater_than</tt> Specifies the value must be greater than the supplied value
- # * <tt>greater_than_or_equal_to</tt> Specifies the value must be greater than or equal the supplied value
- # * <tt>equal_to</tt> Specifies the value must be equal to the supplied value
- # * <tt>less_than</tt> Specifies the value must be less than the supplied value
- # * <tt>less_than_or_equal_to</tt> Specifies the value must be less than or equal the supplied value
- # * <tt>odd</tt> Specifies the value must be an odd number
- # * <tt>even</tt> Specifies the value must be an even number
- # * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
- # occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
+ # * <tt>:message</tt> - A custom error message (default is: "is not a number").
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
+ # * <tt>:only_integer</tt> - Specifies whether the value has to be an integer, e.g. an integral value (default is +false+).
+ # * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+ (default is +false+). Notice that for fixnum and float columns empty strings are converted to +nil+.
+ # * <tt>:greater_than</tt> - Specifies the value must be greater than the supplied value.
+ # * <tt>:greater_than_or_equal_to</tt> - Specifies the value must be greater than or equal the supplied value.
+ # * <tt>:equal_to</tt> - Specifies the value must be equal to the supplied value.
+ # * <tt>:less_than</tt> - Specifies the value must be less than the supplied value.
+ # * <tt>:less_than_or_equal_to</tt> - Specifies the value must be less than or equal the supplied value.
+ # * <tt>:odd</tt> - Specifies the value must be an odd number.
+ # * <tt>:even</tt> - Specifies the value must be an even number.
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
- # * <tt>unless</tt> - Specifies a method, proc or string to call to determine if the validation should
- # not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
# method, proc or string should return or evaluate to a true or false value.
def validates_numericality_of(*attr_names)
configuration = { :on => :save, :only_integer => false, :allow_nil => false }
@@ -873,11 +873,12 @@ module ActiveRecord
# Creates an object just like Base.create but calls save! instead of save
# so an exception is raised if the record is invalid.
- def create!(attributes = nil)
+ def create!(attributes = nil, &block)
if attributes.is_a?(Array)
- attributes.collect { |attr| create!(attr) }
+ attributes.collect { |attr| create!(attr, &block) }
else
object = new(attributes)
+ yield(object) if block_given?
object.save!
object
end
@@ -921,7 +922,7 @@ module ActiveRecord
save(false)
end
- # Runs validate and validate_on_create or validate_on_update and returns true if no errors were added otherwise false.
+ # Runs +validate+ and +validate_on_create+ or +validate_on_update+ and returns true if no errors were added otherwise false.
def valid?
errors.clear
@@ -945,7 +946,7 @@ module ActiveRecord
end
protected
- # Overwrite this method for validation checks on all saves and use Errors.add(field, msg) for invalid attributes.
+ # Overwrite this method for validation checks on all saves and use <tt>Errors.add(field, msg)</tt> for invalid attributes.
def validate #:doc:
end
diff --git a/activerecord/test/cases/associations/eager_test.rb b/activerecord/test/cases/associations/eager_test.rb
index 0bc345428f..546ed80894 100644
--- a/activerecord/test/cases/associations/eager_test.rb
+++ b/activerecord/test/cases/associations/eager_test.rb
@@ -9,11 +9,16 @@ require 'models/person'
require 'models/reader'
require 'models/owner'
require 'models/pet'
+require 'models/reference'
+require 'models/job'
+require 'models/subscriber'
+require 'models/subscription'
+require 'models/book'
class EagerAssociationTest < ActiveRecord::TestCase
fixtures :posts, :comments, :authors, :categories, :categories_posts,
:companies, :accounts, :tags, :taggings, :people, :readers,
- :owners, :pets, :author_favorites
+ :owners, :pets, :author_favorites, :jobs, :references, :subscribers, :subscriptions, :books
def test_loading_with_one_association
posts = Post.find(:all, :include => :comments)
@@ -194,6 +199,48 @@ class EagerAssociationTest < ActiveRecord::TestCase
assert_equal authors(:mary), assert_no_queries { author_favorite.favorite_author }
end
+ def test_eager_load_belongs_to_quotes_table_and_column_names
+ job = Job.find jobs(:unicyclist).id, :include => :ideal_reference
+ references(:michael_unicyclist)
+ assert_no_queries{ assert_equal references(:michael_unicyclist), job.ideal_reference}
+ end
+
+ def test_eager_load_has_one_quotes_table_and_column_names
+ michael = Person.find(people(:michael), :include => :favourite_reference)
+ references(:michael_unicyclist)
+ assert_no_queries{ assert_equal references(:michael_unicyclist), michael.favourite_reference}
+ end
+
+ def test_eager_load_has_many_quotes_table_and_column_names
+ michael = Person.find(people(:michael), :include => :references)
+ references(:michael_magician,:michael_unicyclist)
+ assert_no_queries{ assert_equal references(:michael_magician,:michael_unicyclist), michael.references.sort_by(&:id) }
+ end
+
+ def test_eager_load_has_many_through_quotes_table_and_column_names
+ michael = Person.find(people(:michael), :include => :jobs)
+ jobs(:magician, :unicyclist)
+ assert_no_queries{ assert_equal jobs(:unicyclist, :magician), michael.jobs.sort_by(&:id) }
+ end
+
+ def test_eager_load_has_many_with_string_keys
+ subscriptions = subscriptions(:webster_awdr, :webster_rfr)
+ subscriber =Subscriber.find(subscribers(:second).id, :include => :subscriptions)
+ assert_equal subscriptions, subscriber.subscriptions.sort_by(&:id)
+ end
+
+ def test_eager_load_has_many_through_with_string_keys
+ books = books(:awdr, :rfr)
+ subscriber = Subscriber.find(subscribers(:second).id, :include => :books)
+ assert_equal books, subscriber.books.sort_by(&:id)
+ end
+
+ def test_eager_load_belongs_to_with_string_keys
+ subscriber = subscribers(:second)
+ subscription = Subscription.find(subscriptions(:webster_awdr).id, :include => :subscriber)
+ assert_equal subscriber, subscription.subscriber
+ end
+
def test_eager_association_loading_with_explicit_join
posts = Post.find(:all, :include => :comments, :joins => "INNER JOIN authors ON posts.author_id = authors.id AND authors.name = 'Mary'", :limit => 1, :order => 'author_id')
assert_equal 1, posts.length
diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb
index a9899102d7..5561361bca 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -115,6 +115,18 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
assert posts(:thinking).reload.people(true).collect(&:first_name).include?("Jeb")
end
+ def test_associate_with_create_and_no_options
+ peeps = posts(:thinking).people.count
+ posts(:thinking).people.create(:first_name => 'foo')
+ assert_equal peeps + 1, posts(:thinking).people.count
+ end
+
+ def test_associate_with_create_exclamation_and_no_options
+ peeps = posts(:thinking).people.count
+ posts(:thinking).people.create!(:first_name => 'foo')
+ assert_equal peeps + 1, posts(:thinking).people.count
+ end
+
def test_clear_associations
assert_queries(2) { posts(:welcome);posts(:welcome).people(true) }
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 45d47837a4..e07ec50c46 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -251,6 +251,27 @@ class BasicsTest < ActiveRecord::TestCase
topic = Topic.create("title" => "New Topic")
topicReloaded = Topic.find(topic.id)
assert_equal(topic, topicReloaded)
+ end
+
+ def test_create_through_factory_with_block
+ topic = Topic.create("title" => "New Topic") do |t|
+ t.author_name = "David"
+ end
+ topicReloaded = Topic.find(topic.id)
+ assert_equal("New Topic", topic.title)
+ assert_equal("David", topic.author_name)
+ end
+
+ def test_create_many_through_factory_with_block
+ topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) do |t|
+ t.author_name = "David"
+ end
+ assert_equal 2, topics.size
+ topic1, topic2 = Topic.find(topics[0].id), Topic.find(topics[1].id)
+ assert_equal "first", topic1.title
+ assert_equal "David", topic1.author_name
+ assert_equal "second", topic2.title
+ assert_equal "David", topic2.author_name
end
def test_update
@@ -1630,6 +1651,10 @@ class BasicsTest < ActiveRecord::TestCase
def test_last
assert_equal Developer.find(:first, :order => 'id desc'), Developer.last
end
+
+ def test_all_with_conditions
+ assert_equal Developer.find(:all, :order => 'id desc'), Developer.all(:order => 'id desc')
+ end
def test_find_ordered_last
last = Developer.find :last, :order => 'developers.salary ASC'
diff --git a/activerecord/test/cases/fixtures_test.rb b/activerecord/test/cases/fixtures_test.rb
index 182f4f0f0b..2787b9a39d 100755
--- a/activerecord/test/cases/fixtures_test.rb
+++ b/activerecord/test/cases/fixtures_test.rb
@@ -96,6 +96,10 @@ class FixturesTest < ActiveRecord::TestCase
second_row = ActiveRecord::Base.connection.select_one("SELECT * FROM prefix_topics_suffix WHERE author_name = 'Mary'")
assert_nil(second_row["author_email_address"])
+
+ # This checks for a caching problem which causes a bug in the fixtures
+ # class-level configuration helper.
+ assert_not_nil topics, "Fixture data inserted, but fixture objects not returned from create"
ensure
# Restore prefix/suffix to its previous values
ActiveRecord::Base.table_name_prefix = old_prefix
diff --git a/activerecord/test/cases/locking_test.rb b/activerecord/test/cases/locking_test.rb
index e80f902d0d..7db6c570b5 100644
--- a/activerecord/test/cases/locking_test.rb
+++ b/activerecord/test/cases/locking_test.rb
@@ -2,6 +2,7 @@ require "cases/helper"
require 'models/person'
require 'models/reader'
require 'models/legacy_thing'
+require 'models/reference'
class LockWithoutDefault < ActiveRecord::Base; end
@@ -15,7 +16,7 @@ class ReadonlyFirstNamePerson < Person
end
class OptimisticLockingTest < ActiveRecord::TestCase
- fixtures :people, :legacy_things
+ fixtures :people, :legacy_things, :references
# need to disable transactional fixtures, because otherwise the sqlite3
# adapter (at least) chokes when we try and change the schema in the middle
@@ -138,6 +139,12 @@ class OptimisticLockingTest < ActiveRecord::TestCase
end
end
end
+
+ def test_quote_table_name
+ ref = references(:michael_magician)
+ ref.favourite = !ref.favourite
+ assert ref.save
+ end
private
diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb
index f99e736c55..d4e81827aa 100644
--- a/activerecord/test/cases/migration_test.rb
+++ b/activerecord/test/cases/migration_test.rb
@@ -1077,7 +1077,7 @@ if ActiveRecord::Base.connection.supports_migrations?
protected
def with_new_table
- Person.connection.create_table :delete_me do |t|
+ Person.connection.create_table :delete_me, :force => true do |t|
yield t
end
ensure
@@ -1086,4 +1086,210 @@ if ActiveRecord::Base.connection.supports_migrations?
end # SexyMigrationsTest
end # uses_mocha
+
+ uses_mocha 'ChangeTable migration tests' do
+ class ChangeTableMigrationsTest < ActiveRecord::TestCase
+ def setup
+ @connection = Person.connection
+ @connection.create_table :delete_me, :force => true do |t|
+ end
+ end
+
+ def teardown
+ Person.connection.drop_table :delete_me rescue nil
+ end
+
+ def test_references_column_type_adds_id
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, 'customer_id', :integer, {})
+ t.references :customer
+ end
+ end
+
+ def test_remove_references_column_type_removes_id
+ with_change_table do |t|
+ @connection.expects(:remove_column).with(:delete_me, 'customer_id')
+ t.remove_references :customer
+ end
+ end
+
+ def test_add_belongs_to_works_like_add_references
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, 'customer_id', :integer, {})
+ t.belongs_to :customer
+ end
+ end
+
+ def test_remove_belongs_to_works_like_remove_references
+ with_change_table do |t|
+ @connection.expects(:remove_column).with(:delete_me, 'customer_id')
+ t.remove_belongs_to :customer
+ end
+ end
+
+ def test_references_column_type_with_polymorphic_adds_type
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, 'taggable_type', :string, {})
+ @connection.expects(:add_column).with(:delete_me, 'taggable_id', :integer, {})
+ t.references :taggable, :polymorphic => true
+ end
+ end
+
+ def test_remove_references_column_type_with_polymorphic_removes_type
+ with_change_table do |t|
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_type')
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_id')
+ t.remove_references :taggable, :polymorphic => true
+ end
+ end
+
+ def test_references_column_type_with_polymorphic_and_options_null_is_false_adds_table_flag
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, 'taggable_type', :string, {:null => false})
+ @connection.expects(:add_column).with(:delete_me, 'taggable_id', :integer, {:null => false})
+ t.references :taggable, :polymorphic => true, :null => false
+ end
+ end
+
+ def test_remove_references_column_type_with_polymorphic_and_options_null_is_false_removes_table_flag
+ with_change_table do |t|
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_type')
+ @connection.expects(:remove_column).with(:delete_me, 'taggable_id')
+ t.remove_references :taggable, :polymorphic => true, :null => false
+ end
+ end
+
+ def test_timestamps_creates_updated_at_and_created_at
+ with_change_table do |t|
+ @connection.expects(:add_timestamps).with(:delete_me)
+ t.timestamps
+ end
+ end
+
+ def test_remove_timestamps_creates_updated_at_and_created_at
+ with_change_table do |t|
+ @connection.expects(:remove_timestamps).with(:delete_me)
+ t.remove_timestamps
+ end
+ end
+
+ def string_column
+ if current_adapter?(:PostgreSQLAdapter)
+ "character varying(255)"
+ else
+ 'varchar(255)'
+ end
+ end
+
+ def integer_column
+ if current_adapter?(:SQLite3Adapter) || current_adapter?(:SQLiteAdapter) || current_adapter?(:PostgreSQLAdapter)
+ "integer"
+ else
+ 'int(11)'
+ end
+ end
+
+ def test_integer_creates_integer_column
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, :foo, integer_column, {})
+ @connection.expects(:add_column).with(:delete_me, :bar, integer_column, {})
+ t.integer :foo, :bar
+ end
+ end
+
+ def test_string_creates_string_column
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, :foo, string_column, {})
+ @connection.expects(:add_column).with(:delete_me, :bar, string_column, {})
+ t.string :foo, :bar
+ end
+ end
+
+ def test_column_creates_column
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, :bar, :integer, {})
+ t.column :bar, :integer
+ end
+ end
+
+ def test_column_creates_column_with_options
+ with_change_table do |t|
+ @connection.expects(:add_column).with(:delete_me, :bar, :integer, {:null => false})
+ t.column :bar, :integer, :null => false
+ end
+ end
+
+ def test_index_creates_index
+ with_change_table do |t|
+ @connection.expects(:add_index).with(:delete_me, :bar, {})
+ t.index :bar
+ end
+ end
+
+ def test_index_creates_index_with_options
+ with_change_table do |t|
+ @connection.expects(:add_index).with(:delete_me, :bar, {:unique => true})
+ t.index :bar, :unique => true
+ end
+ end
+
+ def test_change_changes_column
+ with_change_table do |t|
+ @connection.expects(:change_column).with(:delete_me, :bar, :string, {})
+ t.change :bar, :string
+ end
+ end
+
+ def test_change_changes_column_with_options
+ with_change_table do |t|
+ @connection.expects(:change_column).with(:delete_me, :bar, :string, {:null => true})
+ t.change :bar, :string, :null => true
+ end
+ end
+
+ def test_change_default_changes_column
+ with_change_table do |t|
+ @connection.expects(:change_column_default).with(:delete_me, :bar, :string)
+ t.change_default :bar, :string
+ end
+ end
+
+ def test_remove_drops_single_column
+ with_change_table do |t|
+ @connection.expects(:remove_column).with(:delete_me, [:bar])
+ t.remove :bar
+ end
+ end
+
+ def test_remove_drops_multiple_columns
+ with_change_table do |t|
+ @connection.expects(:remove_column).with(:delete_me, [:bar, :baz])
+ t.remove :bar, :baz
+ end
+ end
+
+ def test_remove_index_removes_index_with_options
+ with_change_table do |t|
+ @connection.expects(:remove_index).with(:delete_me, {:unique => true})
+ t.remove_index :unique => true
+ end
+ end
+
+ def test_rename_renames_column
+ with_change_table do |t|
+ @connection.expects(:rename_column).with(:delete_me, :bar, :baz)
+ t.rename :bar, :baz
+ end
+ end
+
+ protected
+ def with_change_table
+ Person.connection.change_table :delete_me do |t|
+ yield t
+ end
+ end
+
+ end # ChangeTable test
+ end # uses_mocha
+
end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 3d3cecd603..e99448c23e 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -11,15 +11,15 @@ class NamedScopeTest < ActiveRecord::TestCase
def test_implements_enumerable
assert !Topic.find(:all).empty?
- assert_equal Topic.find(:all), Topic.all
- assert_equal Topic.find(:all), Topic.all.to_a
- assert_equal Topic.find(:first), Topic.all.first
- assert_equal Topic.find(:all), Topic.all.each { |i| i }
+ assert_equal Topic.find(:all), Topic.base
+ assert_equal Topic.find(:all), Topic.base.to_a
+ assert_equal Topic.find(:first), Topic.base.first
+ assert_equal Topic.find(:all), Topic.base.each { |i| i }
end
def test_found_items_are_cached
Topic.columns
- all_posts = Topic.all
+ all_posts = Topic.base
assert_queries(1) do
all_posts.collect
@@ -28,7 +28,7 @@ class NamedScopeTest < ActiveRecord::TestCase
end
def test_reload_expires_cache_of_found_items
- all_posts = Topic.all
+ all_posts = Topic.base
all_posts.inspect
new_post = Topic.create!
@@ -39,17 +39,17 @@ class NamedScopeTest < ActiveRecord::TestCase
def test_delegates_finds_and_calculations_to_the_base_class
assert !Topic.find(:all).empty?
- assert_equal Topic.find(:all), Topic.all.find(:all)
- assert_equal Topic.find(:first), Topic.all.find(:first)
- assert_equal Topic.count, Topic.all.count
- assert_equal Topic.average(:replies_count), Topic.all.average(:replies_count)
+ assert_equal Topic.find(:all), Topic.base.find(:all)
+ assert_equal Topic.find(:first), Topic.base.find(:first)
+ assert_equal Topic.count, Topic.base.count
+ assert_equal Topic.average(:replies_count), Topic.base.average(:replies_count)
end
def test_subclasses_inherit_scopes
- assert Topic.scopes.include?(:all)
+ assert Topic.scopes.include?(:base)
- assert Reply.scopes.include?(:all)
- assert_equal Reply.find(:all), Reply.all
+ assert Reply.scopes.include?(:base)
+ assert_equal Reply.find(:all), Reply.base
end
def test_scopes_with_options_limit_finds_to_those_matching_the_criteria_specified
@@ -104,7 +104,7 @@ class NamedScopeTest < ActiveRecord::TestCase
def test_active_records_have_scope_named__all__
assert !Topic.find(:all).empty?
- assert_equal Topic.find(:all), Topic.all
+ assert_equal Topic.find(:all), Topic.base
end
def test_active_records_have_scope_named__scoped__
diff --git a/activerecord/test/cases/validations_test.rb b/activerecord/test/cases/validations_test.rb
index ca36ad3581..e3ca8660ac 100755
--- a/activerecord/test/cases/validations_test.rb
+++ b/activerecord/test/cases/validations_test.rb
@@ -133,6 +133,22 @@ class ValidationsTest < ActiveRecord::TestCase
Reply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }])
end
end
+
+ def test_exception_on_create_bang_with_block
+ assert_raises(ActiveRecord::RecordInvalid) do
+ Reply.create!({ "title" => "OK" }) do |r|
+ r.content = nil
+ end
+ end
+ end
+
+ def test_exception_on_create_bang_many_with_block
+ assert_raises(ActiveRecord::RecordInvalid) do
+ Reply.create!([{ "title" => "OK" }, { "title" => "Wrong Create" }]) do |r|
+ r.content = nil
+ end
+ end
+ end
def test_scoped_create_without_attributes
Reply.with_scope(:create => {}) do
diff --git a/activerecord/test/fixtures/jobs.yml b/activerecord/test/fixtures/jobs.yml
new file mode 100644
index 0000000000..f5775d27d3
--- /dev/null
+++ b/activerecord/test/fixtures/jobs.yml
@@ -0,0 +1,7 @@
+unicyclist:
+ id: 1
+ ideal_reference_id: 2
+clown:
+ id: 2
+magician:
+ id: 3
diff --git a/activerecord/test/fixtures/references.yml b/activerecord/test/fixtures/references.yml
new file mode 100644
index 0000000000..8e3953e916
--- /dev/null
+++ b/activerecord/test/fixtures/references.yml
@@ -0,0 +1,17 @@
+michael_magician:
+ id: 1
+ person_id: 1
+ job_id: 3
+ favourite: false
+
+michael_unicyclist:
+ id: 2
+ person_id: 1
+ job_id: 1
+ favourite: true
+
+david_unicyclist:
+ id: 3
+ person_id: 2
+ job_id: 1
+ favourite: false
diff --git a/activerecord/test/fixtures/subscriptions.yml b/activerecord/test/fixtures/subscriptions.yml
new file mode 100644
index 0000000000..371bfd3422
--- /dev/null
+++ b/activerecord/test/fixtures/subscriptions.yml
@@ -0,0 +1,12 @@
+webster_awdr:
+ id: 1
+ subscriber_id: webster132
+ book_id: 1
+webster_rfr:
+ id: 2
+ subscriber_id: webster132
+ book_id: 2
+alterself_awdr:
+ id: 3
+ subscriber_id: alterself
+ book_id: 3 \ No newline at end of file
diff --git a/activerecord/test/models/job.rb b/activerecord/test/models/job.rb
new file mode 100644
index 0000000000..3333a02e27
--- /dev/null
+++ b/activerecord/test/models/job.rb
@@ -0,0 +1,5 @@
+class Job < ActiveRecord::Base
+ has_many :references
+ has_many :people, :through => :references
+ belongs_to :ideal_reference, :class_name => 'Reference'
+end
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index 366f9fb708..4f4d695b24 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -2,4 +2,9 @@ class Person < ActiveRecord::Base
has_many :readers
has_many :posts, :through => :readers
has_many :posts_with_no_comments, :through => :readers, :source => :post, :include => :comments, :conditions => 'comments.id is null'
+
+ has_many :references
+ has_many :jobs, :through => :references
+ has_one :favourite_reference, :class_name => 'Reference', :conditions => ['favourite=?', true]
+
end
diff --git a/activerecord/test/models/reference.rb b/activerecord/test/models/reference.rb
new file mode 100644
index 0000000000..479e8b72c6
--- /dev/null
+++ b/activerecord/test/models/reference.rb
@@ -0,0 +1,4 @@
+class Reference < ActiveRecord::Base
+ belongs_to :person
+ belongs_to :job
+end
diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb
index 27621bd703..812bc1f535 100755
--- a/activerecord/test/models/reply.rb
+++ b/activerecord/test/models/reply.rb
@@ -1,6 +1,8 @@
require 'models/topic'
class Reply < Topic
+ named_scope :base
+
belongs_to :topic, :foreign_key => "parent_id", :counter_cache => true
has_many :replies, :class_name => "SillyReply", :dependent => :destroy, :foreign_key => "parent_id"
diff --git a/activerecord/test/models/subscriber.rb b/activerecord/test/models/subscriber.rb
index 51335a8f20..5b78014e6f 100644
--- a/activerecord/test/models/subscriber.rb
+++ b/activerecord/test/models/subscriber.rb
@@ -1,5 +1,7 @@
class Subscriber < ActiveRecord::Base
set_primary_key 'nick'
+ has_many :subscriptions
+ has_many :books, :through => :subscriptions
end
class SpecialSubscriber < Subscriber
diff --git a/activerecord/test/models/subscription.rb b/activerecord/test/models/subscription.rb
new file mode 100644
index 0000000000..4bdb36ea46
--- /dev/null
+++ b/activerecord/test/models/subscription.rb
@@ -0,0 +1,4 @@
+class Subscription < ActiveRecord::Base
+ belongs_to :subscriber
+ belongs_to :book
+end
diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb
index d2503b78df..f63e862cfd 100755
--- a/activerecord/test/models/topic.rb
+++ b/activerecord/test/models/topic.rb
@@ -1,4 +1,5 @@
class Topic < ActiveRecord::Base
+ named_scope :base
named_scope :written_before, lambda { |time|
{ :conditions => ['written_on < ?', time] }
}
diff --git a/activerecord/test/schema/postgresql_specific_schema.rb b/activerecord/test/schema/postgresql_specific_schema.rb
index 35e9ecf64d..576a4d03c6 100644
--- a/activerecord/test/schema/postgresql_specific_schema.rb
+++ b/activerecord/test/schema/postgresql_specific_schema.rb
@@ -2,7 +2,7 @@ ActiveRecord::Schema.define do
%w(postgresql_arrays postgresql_moneys postgresql_numbers postgresql_times postgresql_network_addresses postgresql_bit_strings
postgresql_oids defaults geometrics).each do |table_name|
- drop_table table_name
+ execute "DROP TABLE IF EXISTS #{quote_table_name table_name}"
end
execute 'DROP SEQUENCE IF EXISTS companies_nonstd_seq CASCADE'
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 2e78844c9b..818237f076 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -162,6 +162,11 @@ ActiveRecord::Schema.define do
t.column :type, :string
end
+
+ create_table :jobs, :force => true do |t|
+ t.integer :ideal_reference_id
+ end
+
create_table :keyboards, :force => true, :id => false do |t|
t.primary_key :key_number
t.string :name
@@ -197,6 +202,13 @@ ActiveRecord::Schema.define do
t.string :type
end
+ create_table :references, :force => true do |t|
+ t.integer :person_id
+ t.integer :job_id
+ t.boolean :favourite
+ t.integer :lock_version, :default => 0
+ end
+
create_table :minimalistics, :force => true do |t|
end
@@ -337,6 +349,11 @@ ActiveRecord::Schema.define do
end
add_index :subscribers, :nick, :unique => true
+ create_table :subscriptions, :force => true do |t|
+ t.string :subscriber_id
+ t.integer :book_id
+ end
+
create_table :tasks, :force => true do |t|
t.datetime :starting
t.datetime :ending
diff --git a/activeresource/CHANGELOG b/activeresource/CHANGELOG
index 6048a6aafc..7becf4fc0c 100644
--- a/activeresource/CHANGELOG
+++ b/activeresource/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Fixed response logging to use length instead of the entire thing (seangeo) [#27]
+
* Fixed that to_param should be used and honored instead of hardcoding the id #11406 [gspiers]
* Improve documentation. [Radar, Jan De Poorter, chuyeow, xaviershay, danger, miloops, Xavier Noria, Sunny Ripert]
diff --git a/activeresource/lib/active_resource/base.rb b/activeresource/lib/active_resource/base.rb
index 4072b9494d..eff92c91de 100644
--- a/activeresource/lib/active_resource/base.rb
+++ b/activeresource/lib/active_resource/base.rb
@@ -457,13 +457,14 @@ module ActiveResource
# The first argument is considered to be the scope of the query. That is, how many
# resources are returned from the request. It can be one of the following.
#
- # +:one+:: Returns a single resource.
- # +:first+:: Returns the first resource found.
- # +:all+:: Returns every resource that matches the request.
+ # * <tt>:one</tt>: Returns a single resource.
+ # * <tt>:first</tt>: Returns the first resource found.
+ # * <tt>:all</tt>: Returns every resource that matches the request.
#
# ==== Options
- # +from+:: Sets the path or custom method that resources will be fetched from.
- # +params+:: Sets query and prefix (nested URL) parameters.
+ #
+ # * +from+: Sets the path or custom method that resources will be fetched from.
+ # * +params+: Sets query and prefix (nested URL) parameters.
#
# ==== Examples
# Person.find(1)
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index 98b3f87167..0c4ea432d7 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -128,8 +128,8 @@ module ActiveResource
end
# Execute a HEAD request.
- # Used to ...
- def head(path, headers= {})
+ # Used to obtain meta-information about resources, such as whether they exist and their size (via response headers).
+ def head(path, headers = {})
request(:head, path, build_request_headers(headers))
end
@@ -140,7 +140,7 @@ module ActiveResource
logger.info "#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}" if logger
result = nil
time = Benchmark.realtime { result = http.send(method, path, *arguments) }
- logger.info "--> #{result.code} #{result.message} (#{result.body ? result.body : 0}b %.2fs)" % time if logger
+ logger.info "--> #{result.code} #{result.message} (#{result.body ? result.body.length : 0}b %.2fs)" % time if logger
handle_response(result)
rescue Timeout::Error => e
raise TimeoutError.new(e.message)
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index a911361d3b..3ee9ed925c 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Added Ruby 1.8 implementation of Process.daemon
+
* Duration #since and #ago with no argument (e.g., 5.days.ago) return TimeWithZone when config.time_zone is set. Introducing Time.current, which returns Time.zone.now if config.time_zone is set, otherwise just returns Time.now [Geoff Buesing]
* Time#since behaves correctly when passed a Duration. Closes #11527 [kemiller]
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 64394afec4..b3c9c23d9f 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -49,7 +49,7 @@ module ActiveSupport
self
end
- # Pass :force => true to force a cache miss.
+ # Pass <tt>:force => true</tt> to force a cache miss.
def fetch(key, options = {})
@logger_off = true
if !options[:force] && value = read(key, options)
@@ -87,8 +87,25 @@ module ActiveSupport
def delete_matched(matcher, options = nil)
log("delete matched", matcher.inspect, options)
+ end
+
+ def increment(key, amount = 1)
+ log("incrementing", key, amount)
+ if num = read(key)
+ write(key, num + amount)
+ else
+ nil
+ end
end
+ def decrement(key, amount = 1)
+ log("decrementing", key, amount)
+ if num = read(key)
+ write(key, num - amount)
+ else
+ nil
+ end
+ end
private
def log(operation, key, options)
diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb
index 88f9ac19db..16a2509ce2 100644
--- a/activesupport/lib/active_support/cache/file_store.rb
+++ b/activesupport/lib/active_support/cache/file_store.rb
@@ -20,14 +20,14 @@ module ActiveSupport
RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER
end
- def delete(name, options)
+ def delete(name, options = nil)
super
File.delete(real_file_path(name))
rescue SystemCallError => e
# If there's no cache, then there's nothing to complain about
end
- def delete_matched(matcher, options)
+ def delete_matched(matcher, options = nil)
super
search_dir(@cache_path) do |f|
if f =~ matcher
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index 9b787702b2..bfe7e2ccf3 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -29,12 +29,11 @@ module ActiveSupport
nil
end
- # Set key = value if key isn't already set. Pass :force => true
- # to unconditionally set key = value. Returns a boolean indicating
- # whether the key was set.
+ # Set key = value. Pass :unless_exist => true if you don't
+ # want to update the cache if the key is already set.
def write(key, value, options = nil)
super
- method = options && options[:force] ? :set : :add
+ method = options && options[:unless_exist] ? :add : :set
response = @data.send(method, key, value, expires_in(options), raw?(options))
response == Response::STORED
rescue MemCache::MemCacheError => e
@@ -49,15 +48,37 @@ module ActiveSupport
rescue MemCache::MemCacheError => e
logger.error("MemCacheError (#{e}): #{e.message}")
false
+ end
+
+ def increment(key, amount = 1)
+ log("incrementing", key, amount)
+
+ response = @data.incr(key, amount)
+ response == Response::NOT_FOUND ? nil : response
+ rescue MemCache::MemCacheError
+ nil
end
+ def decrement(key, amount = 1)
+ log("decrement", key, amount)
+
+ response = data.decr(key, amount)
+ response == Response::NOT_FOUND ? nil : response
+ rescue MemCache::MemCacheError
+ nil
+ end
+
def delete_matched(matcher, options = nil)
super
raise "Not supported by Memcache"
- end
-
+ end
+
def clear
@data.flush_all
+ end
+
+ def stats
+ @data.stats
end
private
diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb
index e0aba6b19a..4872e025cd 100644
--- a/activesupport/lib/active_support/cache/memory_store.rb
+++ b/activesupport/lib/active_support/cache/memory_store.rb
@@ -24,6 +24,10 @@ module ActiveSupport
super
@data.delete_if { |k,v| k =~ matcher }
end
+
+ def clear
+ @data.clear
+ end
end
end
end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 34b1551abc..a9882828ca 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -67,17 +67,35 @@ module ActiveSupport #:nodoc:
end
end
- # Returns a string that represents this array in XML by sending
- # <tt>to_xml</tt> to each element.
+ # Returns a string that represents this array in XML by sending +to_xml+
+ # to each element. Active Record collections delegate their representation
+ # in XML to this method.
#
- # All elements are expected to respond to <tt>to_xml</tt>, if any of
- # them does not an exception is raised.
+ # All elements are expected to respond to +to_xml+, if any of them does
+ # not an exception is raised.
#
# The root node reflects the class name of the first element in plural
- # if all elements belong to the same type and that's not <tt>Hash</tt>.
- # Otherwise the root element is "records".
+ # if all elements belong to the same type and that's not Hash:
#
- # Root children have as node name the one of the root singularized.
+ # customer.projects.to_xml
+ #
+ # <?xml version="1.0" encoding="UTF-8"?>
+ # <projects type="array">
+ # <project>
+ # <amount type="decimal">20000.0</amount>
+ # <customer-id type="integer">1567</customer-id>
+ # <deal-date type="date">2008-04-09</deal-date>
+ # ...
+ # </project>
+ # <project>
+ # <amount type="decimal">57230.0</amount>
+ # <customer-id type="integer">1567</customer-id>
+ # <deal-date type="date">2008-04-15</deal-date>
+ # ...
+ # </project>
+ # </projects>
+ #
+ # Otherwise the root element is "records":
#
# [{:foo => 1, :bar => 2}, {:baz => 3}].to_xml
#
@@ -92,9 +110,26 @@ module ActiveSupport #:nodoc:
# </record>
# </records>
#
+ # If the collection is empty the root element is "nil-classes" by default:
+ #
+ # [].to_xml
+ #
+ # <?xml version="1.0" encoding="UTF-8"?>
+ # <nil-classes type="array"/>
+ #
+ # To ensure a meaningful root element use the <tt>:root</tt> option:
+ #
+ # customer_with_no_projects.projects.to_xml(:root => "projects")
+ #
+ # <?xml version="1.0" encoding="UTF-8"?>
+ # <projects type="array"/>
+ #
+ # By default root children have as node name the one of the root
+ # singularized. You can change it with the <tt>:children</tt> option.
+ #
# The +options+ hash is passed downwards:
#
- # [Message.find(:first)].to_xml(:skip_types => true)
+ # Message.all.to_xml(:skip_types => true)
#
# <?xml version="1.0" encoding="UTF-8"?>
# <messages>
diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
index eee61d48c4..186ca69c05 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
@@ -1,6 +1,12 @@
# Extends the class object with class and instance accessors for class attributes,
# just like the native attr* accessors for instance attributes.
-class Class # :nodoc:
+#
+# class Person
+# cattr_accessor :hair_colors
+# end
+#
+# Person.hair_colors = [:brown, :black, :blonde, :red]
+class Class
def cattr_reader(*syms)
syms.flatten.each do |sym|
next if sym.is_a?(Hash)
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index bb561f675f..183471706b 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -70,7 +70,7 @@ module ActiveSupport #:nodoc:
end
# Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
- # any of these keys: :years, :months, :weeks, :days.
+ # any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
def advance(options)
d = self
d = d >> options.delete(:years) * 12 if options[:years]
diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
index fa444f71b1..155c961a91 100644
--- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb
@@ -42,8 +42,10 @@ module ActiveSupport #:nodoc:
)
end
- # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with
- # any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds.
+ # Uses Date to provide precise Time calculations for years, months, and days.
+ # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
+ # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
+ # <tt>:minutes</tt>, <tt>:seconds</tt>.
def advance(options)
d = to_date.advance(options)
datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index 8f111e29fc..f1469aa0e3 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -8,7 +8,7 @@ module Enumerable
# Example:
#
# latest_transcripts.group_by(&:day).each do |day, transcripts|
- # p "#{day} -> #{transcripts.map(&:class) * ', '}"
+ # p "#{day} -> #{transcripts.map(&:class).join(', ')}"
# end
# "2006-03-01 -> Transcript"
# "2006-02-28 -> Transcript"
@@ -26,21 +26,22 @@ module Enumerable
# Calculates a sum from the elements. Examples:
#
- # payments.sum { |p| p.price * p.tax_rate }
- # payments.sum(&:price)
+ # payments.sum { |p| p.price * p.tax_rate }
+ # payments.sum(&:price)
#
- # This is instead of
+ # The latter is a shortcut for:
#
- # payments.inject { |sum, p| sum + p.price }
+ # payments.inject { |sum, p| sum + p.price }
#
- # Also calculates sums without the use of a block:
+ # It can also calculate the sum without the use of a block.
#
- # [5, 15, 10].sum # => 30
+ # [5, 15, 10].sum # => 30
+ # ["foo", "bar"].sum # => "foobar"
+ # [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
#
- # The default identity (sum of an empty list) is zero.
- # However, you can override this default:
+ # The default sum of an empty list is zero. You can override this default:
#
- # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
+ # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
#
def sum(identity = 0, &block)
return identity unless size > 0
diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
index 0ec0538024..7af10846e7 100644
--- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
+++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb
@@ -8,7 +8,7 @@ module ActiveSupport #:nodoc:
# options.reverse_merge! :size => 25, :velocity => 10
# end
#
- # The default :size and :velocity is only set if the +options+ passed in doesn't already have those keys set.
+ # The default <tt>:size</tt> and <tt>:velocity</tt> is only set if the +options+ passed in doesn't already have those keys set.
module ReverseMerge
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
def reverse_merge(other_hash)
diff --git a/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb b/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb
index 0e78819fdf..ed9d1f9bf2 100644
--- a/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb
+++ b/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb
@@ -2,14 +2,6 @@ module Kernel
# Turns the current script into a daemon process that detaches from the console.
# It can be shut down with a TERM signal.
def daemonize
- exit if fork # Parent exits, child continues.
- Process.setsid # Become session leader.
- exit if fork # Zap session leader. See [1].
- Dir.chdir "/" # Release old working directory.
- File.umask 0000 # Ensure sensible umask. Adjust as needed.
- STDIN.reopen "/dev/null" # Free file descriptors and
- STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
- STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
- trap("TERM") { exit }
+ Process.daemon
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index 58ff363244..51e1c9af90 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -1,6 +1,16 @@
# Extends the module object with module and instance accessors for class attributes,
# just like the native attr* accessors for instance attributes.
-class Module # :nodoc:
+#
+# module AppConfiguration
+# mattr_accessor :google_api_key
+# self.google_api_key = "123456789"
+#
+# mattr_accessor :paypal_url
+# self.paypal_url = "www.sandbox.paypal.com"
+# end
+#
+# AppConfiguration.google_api_key = "overriding the api key!"
+class Module
def mattr_reader(*syms)
syms.each do |sym|
next if sym.is_a?(Hash)
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index f6647eaed3..e0b5f3e379 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -1,8 +1,8 @@
class Module
# Provides a delegate class method to easily expose contained objects' methods
# as your own. Pass one or more methods (specified as symbols or strings)
- # and the name of the target object as the final :to option (also a symbol
- # or string). At least one method and the :to option are required.
+ # and the name of the target object as the final <tt>:to</tt> option (also a symbol
+ # or string). At least one method and the <tt>:to</tt> option are required.
#
# Delegation is particularly useful with Active Record associations:
#
@@ -20,6 +20,7 @@ class Module
# Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
#
# Multiple delegates to the same target are allowed:
+ #
# class Foo < ActiveRecord::Base
# belongs_to :greeter
# delegate :hello, :goodbye, :to => :greeter
@@ -28,7 +29,8 @@ class Module
# Foo.new.goodbye # => "goodbye"
#
# Methods can be delegated to instance variables, class variables, or constants
- # by providing the variable as a symbol:
+ # by providing them as a symbols:
+ #
# class Foo
# CONSTANT_ARRAY = [0,1,2,3]
# @@class_array = [4,5,6,7]
diff --git a/activesupport/lib/active_support/core_ext/process.rb b/activesupport/lib/active_support/core_ext/process.rb
new file mode 100644
index 0000000000..0b0bc6dc69
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/process.rb
@@ -0,0 +1 @@
+require 'active_support/core_ext/process/daemon'
diff --git a/activesupport/lib/active_support/core_ext/process/daemon.rb b/activesupport/lib/active_support/core_ext/process/daemon.rb
new file mode 100644
index 0000000000..95ad5f8a5d
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/process/daemon.rb
@@ -0,0 +1,25 @@
+if RUBY_VERSION < "1.9"
+ module Process
+ def self.daemon(nochdir = nil, noclose = nil)
+ exit if fork # Parent exits, child continues.
+ Process.setsid # Become session leader.
+ exit if fork # Zap session leader. See [1].
+
+ unless nochdir
+ Dir.chdir "/" # Release old working directory.
+ end
+
+ File.umask 0000 # Ensure sensible umask. Adjust as needed.
+
+ unless noclose
+ STDIN.reopen "/dev/null" # Free file descriptors and
+ STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
+ STDERR.reopen '/dev/null', 'a'
+ end
+
+ trap("TERM") { exit }
+
+ return 0
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/range/include_range.rb b/activesupport/lib/active_support/core_ext/range/include_range.rb
index cd53cf154a..9a7d235695 100644
--- a/activesupport/lib/active_support/core_ext/range/include_range.rb
+++ b/activesupport/lib/active_support/core_ext/range/include_range.rb
@@ -7,6 +7,14 @@ module ActiveSupport #:nodoc:
base.alias_method_chain :include?, :range
end
+ # Extends the default Range#include? to support range comparisons.
+ # (1..5).include?(1..5) # => true
+ # (1..5).include?(2..3) # => true
+ # (1..5).include?(2..6) # => false
+ #
+ # The native Range#include? behavior is untouched.
+ # ("a".."f").include?("c") # => true
+ # (5..9).include?(11) # => false
def include_with_range?(value)
if value.is_a?(::Range)
operator = exclude_end? ? :< : :<=
diff --git a/activesupport/lib/active_support/core_ext/range/overlaps.rb b/activesupport/lib/active_support/core_ext/range/overlaps.rb
index 80ed1bba9d..43c69453e7 100644
--- a/activesupport/lib/active_support/core_ext/range/overlaps.rb
+++ b/activesupport/lib/active_support/core_ext/range/overlaps.rb
@@ -3,6 +3,9 @@ module ActiveSupport #:nodoc:
module Range #:nodoc:
# Check if Ranges overlap.
module Overlaps
+ # Compare two ranges and see if they overlap eachother
+ # (1..5).overlaps?(4..6) # => true
+ # (1..5).overlaps?(7..9) # => false
def overlaps?(other)
include?(other.first) || other.include?(first)
end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index ffbdf37789..2cce782676 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -46,12 +46,12 @@ module ActiveSupport #:nodoc:
::DateTime.civil(year, month, day, hour, min, sec, offset)
end
- # wraps class method time_with_datetime_fallback with utc_or_local == :utc
+ # Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:utc</tt>.
def utc_time(*args)
time_with_datetime_fallback(:utc, *args)
end
- # wraps class method time_with_datetime_fallback with utc_or_local == :local
+ # Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:local</tt>.
def local_time(*args)
time_with_datetime_fallback(:local, *args)
end
@@ -78,8 +78,10 @@ module ActiveSupport #:nodoc:
)
end
- # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with
- # any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds.
+ # Uses Date to provide precise Time calculations for years, months, and days.
+ # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
+ # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
+ # <tt>:minutes</tt>, <tt>:seconds</tt>.
def advance(options)
d = to_date.advance(options)
time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index 64b2248e28..eaba46dd9c 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -120,15 +120,26 @@ module Dependencies #:nodoc:
# We can't use defined? because it will invoke const_missing for the parent
# of the name we are checking.
names.inject(Object) do |mod, name|
- return false unless mod.const_defined? name
+ return false unless uninherited_const_defined?(mod, name)
mod.const_get name
end
return true
end
+ if Module.method(:const_defined?).arity == 1
+ # Does this module define this constant?
+ # Wrapper to accomodate changing Module#const_defined? in Ruby 1.9
+ def uninherited_const_defined?(mod, const)
+ mod.const_defined?(const)
+ end
+ else
+ def uninherited_const_defined?(mod, const) #:nodoc:
+ mod.const_defined?(const, false)
+ end
+ end
+
# Given +path+, a filesystem path to a ruby file, return an array of constant
# paths which would cause Dependencies to attempt to load this file.
- #
def loadable_constants_for_path(path, bases = load_paths)
path = $1 if path =~ /\A(.*)\.rb\Z/
expanded_path = File.expand_path(path)
@@ -237,7 +248,7 @@ module Dependencies #:nodoc:
raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
end
- raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if from_mod.const_defined?(const_name)
+ raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if uninherited_const_defined?(from_mod, const_name)
qualified_name = qualified_name_for from_mod, const_name
path_suffix = qualified_name.underscore
@@ -246,12 +257,12 @@ module Dependencies #:nodoc:
file_path = search_for_file(path_suffix)
if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
require_or_load file_path
- raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name)
+ raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless uninherited_const_defined?(from_mod, const_name)
return from_mod.const_get(const_name)
elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
return mod
elsif (parent = from_mod.parent) && parent != from_mod &&
- ! from_mod.parents.any? { |p| p.const_defined?(const_name) }
+ ! from_mod.parents.any? { |p| uninherited_const_defined?(p, const_name) }
# If our parents do not have a constant named +const_name+ then we are free
# to attempt to load upwards. If they do have such a constant, then this
# const_missing must be due to from_mod::const_name, which should not
@@ -423,10 +434,12 @@ module Dependencies #:nodoc:
protected
def log_call(*args)
- arg_str = args.collect(&:inspect) * ', '
- /in `([a-z_\?\!]+)'/ =~ caller(1).first
- selector = $1 || '<unknown>'
- log "called #{selector}(#{arg_str})"
+ if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity
+ arg_str = args.collect(&:inspect) * ', '
+ /in `([a-z_\?\!]+)'/ =~ caller(1).first
+ selector = $1 || '<unknown>'
+ log "called #{selector}(#{arg_str})"
+ end
end
def log(msg)
diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb
index 9f724619e9..c8736549f4 100644
--- a/activesupport/lib/active_support/inflector.rb
+++ b/activesupport/lib/active_support/inflector.rb
@@ -68,8 +68,9 @@ module Inflector
(@uncountables << words).flatten!
end
- # Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type,
- # the options are: :plurals, :singulars, :uncountables
+ # Clears the loaded inflections within a given scope (default is <tt>:all</tt>).
+ # Give the scope as a symbol of the inflection type, the options are: <tt>:plurals</tt>,
+ # <tt>:singulars</tt>, <tt>:uncountables</tt>.
#
# Examples:
# clear :all
@@ -245,13 +246,23 @@ module Inflector
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
end
- # Constantize tries to find a declared constant with the name specified
- # in the string. It raises a NameError when the name is not in CamelCase
- # or is not initialized.
+ # Tries to find a constant with the name specified in the argument string:
#
- # Examples
- # "Module".constantize #=> Module
- # "Class".constantize #=> Class
+ # "Module".constantize # => Module
+ # "Test::Unit".constantize # => Test::Unit
+ #
+ # The name is assumed to be the one of a top-level constant, no matter whether
+ # it starts with "::" or not. No lexical context is taken into account:
+ #
+ # C = 'outside'
+ # module M
+ # C = 'inside'
+ # C # => 'inside'
+ # "C".constantize # => 'outside', same as ::C
+ # end
+ #
+ # NameError is raised when the name is not in CamelCase or the constant is
+ # unknown.
def constantize(camel_cased_word)
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
diff --git a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb
index 66fe47a604..0166b69ac3 100644
--- a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb
+++ b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb
@@ -284,7 +284,9 @@ module ActiveSupport::Multibyte::Handlers #:nodoc:
# passing strings to databases and validations.
#
# * <tt>str</tt> - The string to perform normalization on.
- # * <tt>form</tt> - The form you want to normalize in. Should be one of the following: :c, :kc, :d or :kd.
+ # * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
+ # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
+ # ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM.
def normalize(str, form=ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM)
# See http://www.unicode.org/reports/tr15, Table 1
codepoints = u_unpack(str)
diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb
index b2b1b0e438..3172f62f0d 100644
--- a/activesupport/lib/active_support/ordered_options.rb
+++ b/activesupport/lib/active_support/ordered_options.rb
@@ -18,6 +18,12 @@ module ActiveSupport
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 }
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index f1a2498298..461d52e40e 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -101,7 +101,8 @@ module ActiveSupport
end
alias_method :rfc822, :rfc2822
- # :db format outputs time in UTC; all others output time in local. Uses TimeWithZone's strftime, so %Z and %z work correctly
+ # <tt>:db</tt> format outputs time in UTC; all others output time in local.
+ # Uses TimeWithZone's +strftime+, so <tt>%Z</tt> and <tt>%z</tt> work correctly.
def to_s(format = :default)
return utc.to_s(format) if format == :db
if formatter = ::Time::DATE_FORMATS[format]
@@ -111,7 +112,7 @@ module ActiveSupport
end
end
- # Replaces %Z and %z directives with #zone and #formatted_offset, respectively, before passing to
+ # Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and +formatted_offset+, respectively, before passing to
# Time#strftime, so that zone information is correct
def strftime(format)
format = format.gsub('%Z', zone).gsub('%z', formatted_offset(false))
@@ -138,9 +139,9 @@ module ActiveSupport
result.in_time_zone(time_zone)
end
- # If a time-like object is passed in, compare it with #utc
- # Else if wrapped #time is a DateTime, use DateTime#ago instead of #-
- # Otherwise, just pass on to method missing
+ # If a time-like object is passed in, compare it with +utc+.
+ # Else if wrapped +time+ is a DateTime, use DateTime#ago instead of DateTime#-.
+ # Otherwise, just pass on to +method_missing+.
def -(other)
if other.acts_like?(:time)
utc - other
@@ -180,7 +181,7 @@ module ActiveSupport
alias_method :hash, :to_i
alias_method :tv_sec, :to_i
- # A TimeWithZone acts like a Time, so just return self
+ # A TimeWithZone acts like a Time, so just return +self+.
def to_time
self
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 80057fe832..9cdc2a74ed 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -1,149 +1,152 @@
class TimeZone
- # Keys are Rails TimeZone names, values are TZInfo identifiers
- MAPPING = {
- "International Date Line West" => "Pacific/Midway",
- "Midway Island" => "Pacific/Midway",
- "Samoa" => "Pacific/Pago_Pago",
- "Hawaii" => "Pacific/Honolulu",
- "Alaska" => "America/Juneau",
- "Pacific Time (US & Canada)" => "America/Los_Angeles",
- "Tijuana" => "America/Tijuana",
- "Mountain Time (US & Canada)" => "America/Denver",
- "Arizona" => "America/Phoenix",
- "Chihuahua" => "America/Chihuahua",
- "Mazatlan" => "America/Mazatlan",
- "Central Time (US & Canada)" => "America/Chicago",
- "Saskatchewan" => "America/Regina",
- "Guadalajara" => "America/Mexico_City",
- "Mexico City" => "America/Mexico_City",
- "Monterrey" => "America/Monterrey",
- "Central America" => "America/Guatemala",
- "Eastern Time (US & Canada)" => "America/New_York",
- "Indiana (East)" => "America/Indiana/Indianapolis",
- "Bogota" => "America/Bogota",
- "Lima" => "America/Lima",
- "Quito" => "America/Lima",
- "Atlantic Time (Canada)" => "America/Halifax",
- "Caracas" => "America/Caracas",
- "La Paz" => "America/La_Paz",
- "Santiago" => "America/Santiago",
- "Newfoundland" => "America/St_Johns",
- "Brasilia" => "America/Argentina/Buenos_Aires",
- "Buenos Aires" => "America/Argentina/Buenos_Aires",
- "Georgetown" => "America/Argentina/San_Juan",
- "Greenland" => "America/Godthab",
- "Mid-Atlantic" => "Atlantic/South_Georgia",
- "Azores" => "Atlantic/Azores",
- "Cape Verde Is." => "Atlantic/Cape_Verde",
- "Dublin" => "Europe/Dublin",
- "Edinburgh" => "Europe/Dublin",
- "Lisbon" => "Europe/Lisbon",
- "London" => "Europe/London",
- "Casablanca" => "Africa/Casablanca",
- "Monrovia" => "Africa/Monrovia",
- "UTC" => "Etc/UTC",
- "Belgrade" => "Europe/Belgrade",
- "Bratislava" => "Europe/Bratislava",
- "Budapest" => "Europe/Budapest",
- "Ljubljana" => "Europe/Ljubljana",
- "Prague" => "Europe/Prague",
- "Sarajevo" => "Europe/Sarajevo",
- "Skopje" => "Europe/Skopje",
- "Warsaw" => "Europe/Warsaw",
- "Zagreb" => "Europe/Zagreb",
- "Brussels" => "Europe/Brussels",
- "Copenhagen" => "Europe/Copenhagen",
- "Madrid" => "Europe/Madrid",
- "Paris" => "Europe/Paris",
- "Amsterdam" => "Europe/Amsterdam",
- "Berlin" => "Europe/Berlin",
- "Bern" => "Europe/Berlin",
- "Rome" => "Europe/Rome",
- "Stockholm" => "Europe/Stockholm",
- "Vienna" => "Europe/Vienna",
- "West Central Africa" => "Africa/Algiers",
- "Bucharest" => "Europe/Bucharest",
- "Cairo" => "Africa/Cairo",
- "Helsinki" => "Europe/Helsinki",
- "Kyev" => "Europe/Kiev",
- "Riga" => "Europe/Riga",
- "Sofia" => "Europe/Sofia",
- "Tallinn" => "Europe/Tallinn",
- "Vilnius" => "Europe/Vilnius",
- "Athens" => "Europe/Athens",
- "Istanbul" => "Europe/Istanbul",
- "Minsk" => "Europe/Minsk",
- "Jerusalem" => "Asia/Jerusalem",
- "Harare" => "Africa/Harare",
- "Pretoria" => "Africa/Johannesburg",
- "Moscow" => "Europe/Moscow",
- "St. Petersburg" => "Europe/Moscow",
- "Volgograd" => "Europe/Moscow",
- "Kuwait" => "Asia/Kuwait",
- "Riyadh" => "Asia/Riyadh",
- "Nairobi" => "Africa/Nairobi",
- "Baghdad" => "Asia/Baghdad",
- "Tehran" => "Asia/Tehran",
- "Abu Dhabi" => "Asia/Muscat",
- "Muscat" => "Asia/Muscat",
- "Baku" => "Asia/Baku",
- "Tbilisi" => "Asia/Tbilisi",
- "Yerevan" => "Asia/Yerevan",
- "Kabul" => "Asia/Kabul",
- "Ekaterinburg" => "Asia/Yekaterinburg",
- "Islamabad" => "Asia/Karachi",
- "Karachi" => "Asia/Karachi",
- "Tashkent" => "Asia/Tashkent",
- "Chennai" => "Asia/Kolkata",
- "Kolkata" => "Asia/Kolkata",
- "Mumbai" => "Asia/Kolkata",
- "New Delhi" => "Asia/Kolkata",
- "Kathmandu" => "Asia/Katmandu",
- "Astana" => "Asia/Dhaka",
- "Dhaka" => "Asia/Dhaka",
- "Sri Jayawardenepura" => "Asia/Dhaka",
- "Almaty" => "Asia/Almaty",
- "Novosibirsk" => "Asia/Novosibirsk",
- "Rangoon" => "Asia/Rangoon",
- "Bangkok" => "Asia/Bangkok",
- "Hanoi" => "Asia/Bangkok",
- "Jakarta" => "Asia/Jakarta",
- "Krasnoyarsk" => "Asia/Krasnoyarsk",
- "Beijing" => "Asia/Shanghai",
- "Chongqing" => "Asia/Chongqing",
- "Hong Kong" => "Asia/Hong_Kong",
- "Urumqi" => "Asia/Urumqi",
- "Kuala Lumpur" => "Asia/Kuala_Lumpur",
- "Singapore" => "Asia/Singapore",
- "Taipei" => "Asia/Taipei",
- "Perth" => "Australia/Perth",
- "Irkutsk" => "Asia/Irkutsk",
- "Ulaan Bataar" => "Asia/Ulaanbaatar",
- "Seoul" => "Asia/Seoul",
- "Osaka" => "Asia/Tokyo",
- "Sapporo" => "Asia/Tokyo",
- "Tokyo" => "Asia/Tokyo",
- "Yakutsk" => "Asia/Yakutsk",
- "Darwin" => "Australia/Darwin",
- "Adelaide" => "Australia/Adelaide",
- "Canberra" => "Australia/Melbourne",
- "Melbourne" => "Australia/Melbourne",
- "Sydney" => "Australia/Sydney",
- "Brisbane" => "Australia/Brisbane",
- "Hobart" => "Australia/Hobart",
- "Vladivostok" => "Asia/Vladivostok",
- "Guam" => "Pacific/Guam",
- "Port Moresby" => "Pacific/Port_Moresby",
- "Magadan" => "Asia/Magadan",
- "Solomon Is." => "Asia/Magadan",
- "New Caledonia" => "Pacific/Noumea",
- "Fiji" => "Pacific/Fiji",
- "Kamchatka" => "Asia/Kamchatka",
- "Marshall Is." => "Pacific/Majuro",
- "Auckland" => "Pacific/Auckland",
- "Wellington" => "Pacific/Auckland",
- "Nuku'alofa" => "Pacific/Tongatapu"
- }
+ unless const_defined?(:MAPPING)
+ # Keys are Rails TimeZone names, values are TZInfo identifiers
+ MAPPING = {
+ "International Date Line West" => "Pacific/Midway",
+ "Midway Island" => "Pacific/Midway",
+ "Samoa" => "Pacific/Pago_Pago",
+ "Hawaii" => "Pacific/Honolulu",
+ "Alaska" => "America/Juneau",
+ "Pacific Time (US & Canada)" => "America/Los_Angeles",
+ "Tijuana" => "America/Tijuana",
+ "Mountain Time (US & Canada)" => "America/Denver",
+ "Arizona" => "America/Phoenix",
+ "Chihuahua" => "America/Chihuahua",
+ "Mazatlan" => "America/Mazatlan",
+ "Central Time (US & Canada)" => "America/Chicago",
+ "Saskatchewan" => "America/Regina",
+ "Guadalajara" => "America/Mexico_City",
+ "Mexico City" => "America/Mexico_City",
+ "Monterrey" => "America/Monterrey",
+ "Central America" => "America/Guatemala",
+ "Eastern Time (US & Canada)" => "America/New_York",
+ "Indiana (East)" => "America/Indiana/Indianapolis",
+ "Bogota" => "America/Bogota",
+ "Lima" => "America/Lima",
+ "Quito" => "America/Lima",
+ "Atlantic Time (Canada)" => "America/Halifax",
+ "Caracas" => "America/Caracas",
+ "La Paz" => "America/La_Paz",
+ "Santiago" => "America/Santiago",
+ "Newfoundland" => "America/St_Johns",
+ "Brasilia" => "America/Argentina/Buenos_Aires",
+ "Buenos Aires" => "America/Argentina/Buenos_Aires",
+ "Georgetown" => "America/Argentina/San_Juan",
+ "Greenland" => "America/Godthab",
+ "Mid-Atlantic" => "Atlantic/South_Georgia",
+ "Azores" => "Atlantic/Azores",
+ "Cape Verde Is." => "Atlantic/Cape_Verde",
+ "Dublin" => "Europe/Dublin",
+ "Edinburgh" => "Europe/Dublin",
+ "Lisbon" => "Europe/Lisbon",
+ "London" => "Europe/London",
+ "Casablanca" => "Africa/Casablanca",
+ "Monrovia" => "Africa/Monrovia",
+ "UTC" => "Etc/UTC",
+ "Belgrade" => "Europe/Belgrade",
+ "Bratislava" => "Europe/Bratislava",
+ "Budapest" => "Europe/Budapest",
+ "Ljubljana" => "Europe/Ljubljana",
+ "Prague" => "Europe/Prague",
+ "Sarajevo" => "Europe/Sarajevo",
+ "Skopje" => "Europe/Skopje",
+ "Warsaw" => "Europe/Warsaw",
+ "Zagreb" => "Europe/Zagreb",
+ "Brussels" => "Europe/Brussels",
+ "Copenhagen" => "Europe/Copenhagen",
+ "Madrid" => "Europe/Madrid",
+ "Paris" => "Europe/Paris",
+ "Amsterdam" => "Europe/Amsterdam",
+ "Berlin" => "Europe/Berlin",
+ "Bern" => "Europe/Berlin",
+ "Rome" => "Europe/Rome",
+ "Stockholm" => "Europe/Stockholm",
+ "Vienna" => "Europe/Vienna",
+ "West Central Africa" => "Africa/Algiers",
+ "Bucharest" => "Europe/Bucharest",
+ "Cairo" => "Africa/Cairo",
+ "Helsinki" => "Europe/Helsinki",
+ "Kyev" => "Europe/Kiev",
+ "Riga" => "Europe/Riga",
+ "Sofia" => "Europe/Sofia",
+ "Tallinn" => "Europe/Tallinn",
+ "Vilnius" => "Europe/Vilnius",
+ "Athens" => "Europe/Athens",
+ "Istanbul" => "Europe/Istanbul",
+ "Minsk" => "Europe/Minsk",
+ "Jerusalem" => "Asia/Jerusalem",
+ "Harare" => "Africa/Harare",
+ "Pretoria" => "Africa/Johannesburg",
+ "Moscow" => "Europe/Moscow",
+ "St. Petersburg" => "Europe/Moscow",
+ "Volgograd" => "Europe/Moscow",
+ "Kuwait" => "Asia/Kuwait",
+ "Riyadh" => "Asia/Riyadh",
+ "Nairobi" => "Africa/Nairobi",
+ "Baghdad" => "Asia/Baghdad",
+ "Tehran" => "Asia/Tehran",
+ "Abu Dhabi" => "Asia/Muscat",
+ "Muscat" => "Asia/Muscat",
+ "Baku" => "Asia/Baku",
+ "Tbilisi" => "Asia/Tbilisi",
+ "Yerevan" => "Asia/Yerevan",
+ "Kabul" => "Asia/Kabul",
+ "Ekaterinburg" => "Asia/Yekaterinburg",
+ "Islamabad" => "Asia/Karachi",
+ "Karachi" => "Asia/Karachi",
+ "Tashkent" => "Asia/Tashkent",
+ "Chennai" => "Asia/Kolkata",
+ "Kolkata" => "Asia/Kolkata",
+ "Mumbai" => "Asia/Kolkata",
+ "New Delhi" => "Asia/Kolkata",
+ "Kathmandu" => "Asia/Katmandu",
+ "Astana" => "Asia/Dhaka",
+ "Dhaka" => "Asia/Dhaka",
+ "Sri Jayawardenepura" => "Asia/Dhaka",
+ "Almaty" => "Asia/Almaty",
+ "Novosibirsk" => "Asia/Novosibirsk",
+ "Rangoon" => "Asia/Rangoon",
+ "Bangkok" => "Asia/Bangkok",
+ "Hanoi" => "Asia/Bangkok",
+ "Jakarta" => "Asia/Jakarta",
+ "Krasnoyarsk" => "Asia/Krasnoyarsk",
+ "Beijing" => "Asia/Shanghai",
+ "Chongqing" => "Asia/Chongqing",
+ "Hong Kong" => "Asia/Hong_Kong",
+ "Urumqi" => "Asia/Urumqi",
+ "Kuala Lumpur" => "Asia/Kuala_Lumpur",
+ "Singapore" => "Asia/Singapore",
+ "Taipei" => "Asia/Taipei",
+ "Perth" => "Australia/Perth",
+ "Irkutsk" => "Asia/Irkutsk",
+ "Ulaan Bataar" => "Asia/Ulaanbaatar",
+ "Seoul" => "Asia/Seoul",
+ "Osaka" => "Asia/Tokyo",
+ "Sapporo" => "Asia/Tokyo",
+ "Tokyo" => "Asia/Tokyo",
+ "Yakutsk" => "Asia/Yakutsk",
+ "Darwin" => "Australia/Darwin",
+ "Adelaide" => "Australia/Adelaide",
+ "Canberra" => "Australia/Melbourne",
+ "Melbourne" => "Australia/Melbourne",
+ "Sydney" => "Australia/Sydney",
+ "Brisbane" => "Australia/Brisbane",
+ "Hobart" => "Australia/Hobart",
+ "Vladivostok" => "Asia/Vladivostok",
+ "Guam" => "Pacific/Guam",
+ "Port Moresby" => "Pacific/Port_Moresby",
+ "Magadan" => "Asia/Magadan",
+ "Solomon Is." => "Asia/Magadan",
+ "New Caledonia" => "Pacific/Noumea",
+ "Fiji" => "Pacific/Fiji",
+ "Kamchatka" => "Asia/Kamchatka",
+ "Marshall Is." => "Pacific/Majuro",
+ "Auckland" => "Pacific/Auckland",
+ "Wellington" => "Pacific/Auckland",
+ "Nuku'alofa" => "Pacific/Tongatapu"
+ }.each { |name, zone| name.freeze; zone.freeze }
+ MAPPING.freeze
+ end
include Comparable
attr_reader :name
@@ -157,7 +160,7 @@ class TimeZone
@utc_offset = utc_offset
@tzinfo = tzinfo
end
-
+
def utc_offset
@utc_offset ||= tzinfo.current_period.utc_offset
end
@@ -180,7 +183,7 @@ class TimeZone
def to_s
"(UTC#{formatted_offset}) #{name}"
end
-
+
# Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example:
#
# Time.zone = "Hawaii" # => "Hawaii"
@@ -199,7 +202,7 @@ class TimeZone
utc = Time.at(secs).utc rescue DateTime.civil(1970).since(secs)
utc.in_time_zone(self)
end
-
+
# Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example:
#
# Time.zone = "Hawaii" # => "Hawaii"
@@ -213,7 +216,7 @@ class TimeZone
time = Time.parse(str, now) rescue DateTime.parse(str)
ActiveSupport::TimeWithZone.new(nil, self, time)
end
-
+
# Returns an ActiveSupport::TimeWithZone instance representing the current time
# in the time zone represented by +self+. Example:
#
@@ -228,12 +231,12 @@ class TimeZone
tzinfo.now.to_date
end
- # Adjust the given time to the simultaneous time in the time zone represented by +self+. Returns a
+ # Adjust the given time to the simultaneous time in the time zone represented by +self+. Returns a
# Time.utc() instance -- if you want an ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead.
def utc_to_local(time)
tzinfo.utc_to_local(time)
end
-
+
# Adjust the given time to the simultaneous time in UTC. Returns a Time.utc() instance.
def local_to_utc(time, dst=true)
tzinfo.local_to_utc(time, dst)
@@ -248,12 +251,75 @@ class TimeZone
def period_for_local(time, dst=true)
tzinfo.period_for_local(time, dst)
end
-
+
+ # TODO: Preload instead of lazy load for thread safety
def tzinfo
@tzinfo ||= TZInfo::Timezone.get(MAPPING[name])
end
- @@zones = nil
+ unless const_defined?(:ZONES)
+ ZONES = []
+ ZONES_MAP = {}
+ [[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
+ [-36_000, "Hawaii" ],
+ [-32_400, "Alaska" ],
+ [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
+ [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
+ "Arizona" ],
+ [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
+ "Mexico City", "Monterrey", "Central America" ],
+ [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
+ "Lima", "Quito" ],
+ [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ],
+ [-12_600, "Newfoundland" ],
+ [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
+ [ -7_200, "Mid-Atlantic" ],
+ [ -3_600, "Azores", "Cape Verde Is." ],
+ [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
+ "Monrovia", "UTC" ],
+ [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
+ "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
+ "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
+ "Bern", "Rome", "Stockholm", "Vienna",
+ "West Central Africa" ],
+ [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
+ "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
+ "Jerusalem", "Harare", "Pretoria" ],
+ [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
+ "Nairobi", "Baghdad" ],
+ [ 12_600, "Tehran" ],
+ [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
+ [ 16_200, "Kabul" ],
+ [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
+ [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ],
+ [ 20_700, "Kathmandu" ],
+ [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty",
+ "Novosibirsk" ],
+ [ 23_400, "Rangoon" ],
+ [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
+ [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
+ "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
+ "Ulaan Bataar" ],
+ [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
+ [ 34_200, "Darwin", "Adelaide" ],
+ [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
+ "Vladivostok", "Guam", "Port Moresby" ],
+ [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
+ [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
+ "Wellington" ],
+ [ 46_800, "Nuku'alofa" ]].
+ each do |offset, *places|
+ places.each do |place|
+ place.freeze
+ zone = new(place, offset)
+ ZONES << zone
+ ZONES_MAP[place] = zone
+ end
+ end
+ ZONES.sort!
+ ZONES.freeze
+ ZONES_MAP.freeze
+ end
class << self
alias_method :create, :new
@@ -269,67 +335,7 @@ class TimeZone
# TimeZone objects per time zone, in many cases, to make it easier
# for users to find their own time zone.
def all
- unless @@zones
- @@zones = []
- @@zones_map = {}
- [[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
- [-36_000, "Hawaii" ],
- [-32_400, "Alaska" ],
- [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
- [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
- "Arizona" ],
- [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
- "Mexico City", "Monterrey", "Central America" ],
- [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
- "Lima", "Quito" ],
- [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ],
- [-12_600, "Newfoundland" ],
- [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
- [ -7_200, "Mid-Atlantic" ],
- [ -3_600, "Azores", "Cape Verde Is." ],
- [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
- "Monrovia", "UTC" ],
- [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
- "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
- "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
- "Bern", "Rome", "Stockholm", "Vienna",
- "West Central Africa" ],
- [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
- "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
- "Jerusalem", "Harare", "Pretoria" ],
- [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
- "Nairobi", "Baghdad" ],
- [ 12_600, "Tehran" ],
- [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
- [ 16_200, "Kabul" ],
- [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
- [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ],
- [ 20_700, "Kathmandu" ],
- [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty",
- "Novosibirsk" ],
- [ 23_400, "Rangoon" ],
- [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
- [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
- "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
- "Ulaan Bataar" ],
- [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
- [ 34_200, "Darwin", "Adelaide" ],
- [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
- "Vladivostok", "Guam", "Port Moresby" ],
- [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
- [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
- "Wellington" ],
- [ 46_800, "Nuku'alofa" ]].
- each do |offset, *places|
- places.each do |place|
- zone = create(place, offset)
- @@zones << zone
- @@zones_map[place] = zone
- end
- end
- @@zones.sort!
- end
- @@zones
+ ZONES
end
# Locate a specific time zone object. If the argument is a string, it
@@ -340,8 +346,7 @@ class TimeZone
def [](arg)
case arg
when String
- all # force the zones to be loaded
- @@zones_map[arg]
+ ZONES_MAP[arg]
when Numeric, ActiveSupport::Duration
arg *= 3600 if arg.abs <= 13
all.find { |z| z.utc_offset == arg.to_i }
@@ -352,7 +357,7 @@ class TimeZone
# A regular expression that matches the names of all time zones in
# the USA.
- US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/
+ US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/.freeze
# A convenience method for returning a collection of TimeZone objects
# for time zones in the USA.
diff --git a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb
index 375cfb1430..dda7f2c30e 100644
--- a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb
+++ b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb
@@ -278,12 +278,12 @@ class MemCache
results = {}
- server_keys.each do |server, keys|
- keys = keys.join ' '
+ server_keys.each do |server, keys_for_server|
+ keys_for_server = keys_for_server.join ' '
values = if @multithread then
- threadsafe_cache_get_multi server, keys
+ threadsafe_cache_get_multi server, keys_for_server
else
- cache_get_multi server, keys
+ cache_get_multi server, keys_for_server
end
values.each do |key, value|
results[cache_keys[key]] = Marshal.load value
diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb
index 099619191c..36fe9510ba 100644
--- a/activesupport/lib/active_support/whiny_nil.rb
+++ b/activesupport/lib/active_support/whiny_nil.rb
@@ -28,12 +28,12 @@ class NilClass
WHINERS = [::Array]
WHINERS << ::ActiveRecord::Base if defined? ::ActiveRecord
- @@method_class_map = Hash.new
+ METHOD_CLASS_MAP = Hash.new
WHINERS.each do |klass|
methods = klass.public_instance_methods - public_instance_methods
class_name = klass.name
- methods.each { |method| @@method_class_map[method.to_sym] = class_name }
+ methods.each { |method| METHOD_CLASS_MAP[method.to_sym] = class_name }
end
# Raises a RuntimeError when you attempt to call +id+ on +nil+.
@@ -43,7 +43,7 @@ class NilClass
private
def method_missing(method, *args, &block)
- raise_nil_warning_for @@method_class_map[method], method, caller
+ raise_nil_warning_for METHOD_CLASS_MAP[method], method, caller
end
# Raises a NoMethodError when you attempt to call a method on +nil+.
diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb
index 00d8f45028..26af245ff7 100644
--- a/activesupport/test/inflector_test.rb
+++ b/activesupport/test/inflector_test.rb
@@ -120,14 +120,8 @@ class InflectorTest < Test::Unit::TestCase
assert_raises(NameError) { Inflector.constantize("InvalidClass\n") }
end
- if RUBY_VERSION < '1.9.0'
- def test_constantize_does_lexical_lookup
- assert_raises(NameError) { Inflector.constantize("Ace::Base::InflectorTest") }
- end
- else
- def test_constantize_does_dynamic_lookup
- assert_equal self.class, Inflector.constantize("Ace::Base::InflectorTest")
- end
+ def test_constantize_does_lexical_lookup
+ assert_raises(NameError) { Inflector.constantize("Ace::Base::InflectorTest") }
end
def test_ordinal
diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb
index 1a1d0c7648..3d537a0ae4 100644
--- a/activesupport/test/ordered_options_test.rb
+++ b/activesupport/test/ordered_options_test.rb
@@ -29,6 +29,19 @@ class OrderedHashTest < Test::Unit::TestCase
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
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 6cd2b5364f..a1f9db28e0 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Made the location of the routes file configurable with config.routes_configuration_file (Scott Fleckenstein) [#88]
+
* Rails Edge info returns the latest git commit hash [Francesc Esplugas]
* Added Rails.public_path to control where HTML and assets are expected to be loaded from (defaults to Rails.root + "/public") #11581 [nicksieger]
diff --git a/railties/lib/commands/servers/mongrel.rb b/railties/lib/commands/servers/mongrel.rb
index 5eb14bce1e..f59265e698 100644
--- a/railties/lib/commands/servers/mongrel.rb
+++ b/railties/lib/commands/servers/mongrel.rb
@@ -34,10 +34,10 @@ end
puts "=> Rails application starting on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
-parameters = [
- "start",
- "-p", OPTIONS[:port].to_s,
- "-a", OPTIONS[:ip].to_s,
+parameters = [
+ "start",
+ "-p", OPTIONS[:port].to_s,
+ "-a", OPTIONS[:ip].to_s,
"-e", OPTIONS[:environment],
"-P", "#{RAILS_ROOT}/tmp/pids/mongrel.pid"
]
@@ -50,12 +50,12 @@ else
start_debugger if OPTIONS[:debugger]
- require 'initializer'
- Rails::Initializer.run(:initialize_logger)
-
puts "=> Call with -d to detach"
puts "=> Ctrl-C to shutdown server"
- tail_thread = tail(Pathname.new("#{File.expand_path(RAILS_ROOT)}/log/#{RAILS_ENV}.log").cleanpath)
+
+ log = Pathname.new("#{File.expand_path(RAILS_ROOT)}/log/#{RAILS_ENV}.log").cleanpath
+ open(log, (File::WRONLY | File::APPEND | File::CREAT)) unless File.exist? log
+ tail_thread = tail(log)
trap(:INT) { exit }
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index b5bf9266f5..6db96f0158 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -28,7 +28,11 @@ module Rails
end
def root
- RAILS_ROOT
+ if defined?(RAILS_ROOT)
+ RAILS_ROOT
+ else
+ nil
+ end
end
def env
@@ -40,7 +44,7 @@ module Rails
end
def public_path
- @@public_path ||= File.join(self.root, "public")
+ @@public_path ||= self.root ? File.join(self.root, "public") : "public"
end
def public_path=(path)
@@ -135,12 +139,12 @@ module Rails
load_application_initializers
- # Prepare dispatcher callbacks and run 'prepare' callbacks
- prepare_dispatcher
-
# the framework is now fully initialized
after_initialize
+ # Prepare dispatcher callbacks and run 'prepare' callbacks
+ prepare_dispatcher
+
# Routing must be initialized after plugins to allow the former to extend the routes
initialize_routing
@@ -160,6 +164,10 @@ module Rails
# ActiveResource. This allows Gem plugins to depend on Rails even when
# the Gem version of Rails shouldn't be loaded.
def install_gem_spec_stubs
+ unless Rails.respond_to?(:vendor_rails?)
+ abort "Your config/boot.rb is outdated: Run 'rake rails:update'."
+ end
+
if Rails.vendor_rails?
begin; require "rubygems"; rescue LoadError; return; end
@@ -378,6 +386,7 @@ module Rails
def initialize_routing
return unless configuration.frameworks.include?(:action_controller)
ActionController::Routing.controller_paths = configuration.controller_paths
+ ActionController::Routing::Routes.configuration_file = configuration.routes_configuration_file
ActionController::Routing::Routes.reload
end
@@ -495,6 +504,10 @@ module Rails
# The path to the database configuration file to use. (Defaults to
# <tt>config/database.yml</tt>.)
attr_accessor :database_configuration_file
+
+ # The path to the routes configuration file to use. (Defaults to
+ # <tt>config/routes.rb</tt>.)
+ attr_accessor :routes_configuration_file
# The list of rails framework components that should be loaded. (Defaults
# to <tt>:active_record</tt>, <tt>:action_controller</tt>,
@@ -559,11 +572,11 @@ module Rails
attr_accessor :plugin_loader
# Enables or disables plugin reloading. You can get around this setting per plugin.
- # If #reload_plugins? == false, add this to your plugin's init.rb to make it reloadable:
+ # If <tt>reload_plugins?</tt> is false, add this to your plugin's init.rb to make it reloadable:
#
# Dependencies.load_once_paths.delete lib_path
#
- # If #reload_plugins? == true, add this to your plugin's init.rb to only load it once:
+ # If <tt>reload_plugins?</tt> is true, add this to your plugin's init.rb to only load it once:
#
# Dependencies.load_once_paths << lib_path
#
@@ -627,6 +640,7 @@ module Rails
self.plugin_locators = default_plugin_locators
self.plugin_loader = default_plugin_loader
self.database_configuration_file = default_database_configuration_file
+ self.routes_configuration_file = default_routes_configuration_file
self.gems = default_gems
for framework in default_frameworks
@@ -767,6 +781,10 @@ module Rails
File.join(root_path, 'config', 'database.yml')
end
+ def default_routes_configuration_file
+ File.join(root_path, 'config', 'routes.rb')
+ end
+
def default_view_path
File.join(root_path, 'app', 'views')
end
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb b/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb
index 35eae462c6..e289975596 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb
+++ b/railties/lib/rails_generator/generators/components/scaffold/templates/view_edit.html.erb
@@ -5,7 +5,7 @@
<% for attribute in attributes -%>
<p>
- <%%= f.label :<%= attribute.name %> %><br />
+ <%%= f.label :<%= attribute.name %> %><br />
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
</p>
<% end -%>
@@ -15,4 +15,4 @@
<%% end %>
<%%= link_to 'Show', @<%= singular_name %> %> |
-<%%= link_to 'Back', <%= plural_name %>_path %> \ No newline at end of file
+<%%= link_to 'Back', <%= plural_name %>_path %>
diff --git a/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb b/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb
index bc1f08abef..c47e8117b4 100644
--- a/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb
+++ b/railties/lib/rails_generator/generators/components/scaffold/templates/view_new.html.erb
@@ -5,7 +5,7 @@
<% for attribute in attributes -%>
<p>
- <%%= f.label :<%= attribute.name %> %><br />
+ <%%= f.label :<%= attribute.name %> %><br />
<%%= f.<%= attribute.field_type %> :<%= attribute.name %> %>
</p>
<% end -%>
@@ -14,4 +14,4 @@
</p>
<%% end %>
-<%%= link_to 'Back', <%= plural_name %>_path %> \ No newline at end of file
+<%%= link_to 'Back', <%= plural_name %>_path %>
diff --git a/railties/lib/tasks/databases.rake b/railties/lib/tasks/databases.rake
index e39f9ca197..20fdcce205 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' => nil))
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'template1'))
ActiveRecord::Base.connection.create_database(config['database'], :encoding => @encoding)
ActiveRecord::Base.establish_connection(config)
rescue
@@ -373,7 +373,7 @@ def drop_database(config)
when /^sqlite/
FileUtils.rm(File.join(RAILS_ROOT, config['database']))
when 'postgresql'
- ActiveRecord::Base.establish_connection(config.merge('database' => nil))
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'template1'))
ActiveRecord::Base.connection.drop_database config['database']
end
end
diff --git a/railties/test/fixtures/lib/generators/missing_class/templates/.empty b/railties/test/fixtures/lib/generators/missing_class/templates/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/lib/generators/missing_class/templates/.empty
+++ b/railties/test/fixtures/lib/generators/missing_class/templates/.gitignore
diff --git a/railties/test/fixtures/lib/generators/missing_generator/templates/.empty b/railties/test/fixtures/lib/generators/missing_generator/templates/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/lib/generators/missing_generator/templates/.empty
+++ b/railties/test/fixtures/lib/generators/missing_generator/templates/.gitignore
diff --git a/railties/test/fixtures/lib/generators/missing_templates/.empty b/railties/test/fixtures/lib/generators/missing_templates/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/lib/generators/missing_templates/.empty
+++ b/railties/test/fixtures/lib/generators/missing_templates/.gitignore
diff --git a/railties/test/fixtures/plugins/alternate/a/lib/.empty b/railties/test/fixtures/plugins/alternate/a/lib/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/plugins/alternate/a/lib/.empty
+++ b/railties/test/fixtures/plugins/alternate/a/lib/.gitignore
diff --git a/railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.empty b/railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.empty
+++ b/railties/test/fixtures/plugins/default/acts/acts_as_chunky_bacon/lib/.gitignore
diff --git a/railties/test/fixtures/plugins/default/empty/.empty b/railties/test/fixtures/plugins/default/empty/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/railties/test/fixtures/plugins/default/empty/.empty
+++ b/railties/test/fixtures/plugins/default/empty/.gitignore