aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
Diffstat (limited to 'railties')
-rw-r--r--railties/guides/source/active_support_core_extensions.textile356
-rw-r--r--railties/guides/source/form_helpers.textile2
-rw-r--r--railties/guides/source/index.html.erb4
-rw-r--r--railties/guides/source/layout.html.erb1
-rw-r--r--railties/lib/rails/application.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt4
-rw-r--r--railties/test/application/routing_test.rb96
8 files changed, 275 insertions, 192 deletions
diff --git a/railties/guides/source/active_support_core_extensions.textile b/railties/guides/source/active_support_core_extensions.textile
index 9a449debae..8ccfc8e304 100644
--- a/railties/guides/source/active_support_core_extensions.textile
+++ b/railties/guides/source/active_support_core_extensions.textile
@@ -1,8 +1,10 @@
h2. Active Support Core Extensions
-Active Support is the Rails component responsible for providing Ruby language extensions, utilities, and other transversal stuff. It offers a richer bottom-line at the language level, targeted both at the development of Rails applications, and at the development of Rails itself.
+Active Support is the Ruby on Rails component responsible for providing Ruby language extensions, utilities, and other transversal stuff.
-By referring to this guide you will learn the extensions to the Ruby core classes and modules provided by Rails.
+It offers a richer bottom-line at the language level, targeted both at the development of Rails applications, and at the development of Ruby on Rails itself.
+
+By referring to this guide you will learn the extensions to the Ruby core classes and modules provided by Active Support.
endprologue.
@@ -84,32 +86,25 @@ The following values are considered to be blank in a Rails application:
WARNING: Note that numbers are not mentioned, in particular 0 and 0.0 are *not* blank.
-For example, this method from +ActionDispatch::Response+ uses +blank?+ to easily be robust to +nil+ and whitespace strings in one shot:
+For example, this method from +ActionDispatch::Session::AbstractStore+ uses +blank?+ for checking whether a session key is present:
<ruby>
-def charset
- charset = String(headers["Content-Type"] || headers["type"]).split(";")[1]
- charset.blank? ? nil : charset.strip.split("=")[1]
+def ensure_session_key!
+ if @key.blank?
+ raise ArgumentError, 'A key is required...'
+ end
end
</ruby>
-That's a typical use case for +blank?+.
-
-Here, the method Rails runs to instantiate observers upon initialization has nothing to do if there are none:
+The method +present?+ is equivalent to +!blank?+. This example is taken from +ActionDispatch::Http::Cache::Response+:
<ruby>
-def instantiate_observers
- return if @observers.blank?
- # ...
+def set_conditional_cache_control!
+ return if self["Cache-Control"].present?
+ ...
end
</ruby>
-The method +present?+ is equivalent to +!blank?+:
-
-<ruby>
-assert @response.body.present? # same as !@response.body.blank?
-</ruby>
-
NOTE: Defined in +active_support/core_ext/object/blank.rb+.
h4. +presence+
@@ -151,28 +146,17 @@ Active Support provides +duplicable?+ to programmatically query an object about
false.duplicable? # => false
</ruby>
-By definition all objects are +duplicable?+ except +nil+, +false+, +true+, symbols, numbers, and class objects.
+By definition all objects are +duplicable?+ except +nil+, +false+, +true+, symbols, numbers, and class and module objects.
-WARNING. Using +duplicable?+ is discouraged because it depends on a hard-coded list. Classes have means to disallow duplication like removing +dup+ and +clone+ or raising exceptions from them, only +rescue+ can tell.
+WARNING. Any class can disallow duplication removing +dup+ and +clone+ or raising exceptions from them, only +rescue+ can tell whether a given arbitrary object is duplicable. +duplicable?+ depends on the hard-coded list above, but it is much faster than +rescue+. Use it only if you know the hard-coded list is enough in your use case.
NOTE: Defined in +active_support/core_ext/object/duplicable.rb+.
h4. +try+
-Sometimes you want to call a method provided the receiver object is not +nil+, which is something you usually check first.
+Sometimes you want to call a method provided the receiver object is not +nil+, which is something you usually check first. +try+ is like +Object#send+ except that it returns +nil+ if sent to +nil+.
-For instance, note how this method of +ActiveRecord::ConnectionAdapters::AbstractAdapter+ checks if there's a +@logger+:
-
-<ruby>
-def log_info(sql, name, ms)
- if @logger && @logger.debug?
- name = '%s (%.1fms)' % [name || 'SQL', ms]
- @logger.debug(format_log_entry(name, sql.squeeze(' ')))
- end
-end
-</ruby>
-
-You can shorten that using +Object#try+. This method is a synonym for +Object#send+ except that it returns +nil+ if sent to +nil+. The previous example could then be rewritten as:
+For instance, in this code from +ActiveRecord::ConnectionAdapters::AbstractAdapter+ +@logger+ could be +nil+, but you save the check and write in an optimistic style:
<ruby>
def log_info(sql, name, ms)
@@ -667,129 +651,6 @@ end
NOTE: Defined in +active_support/core_ext/module/attribute_accessors.rb+.
-h4. Method Delegation
-
-The class method +delegate+ offers an easy way to forward methods.
-
-For example, if +User+ has some details like the age factored out to +Profile+, it could be handy to still be able to access such attributes directly, <tt>user.age</tt>, instead of having to explicit the chain <tt>user.profile.age</tt>.
-
-That can be accomplished by hand:
-
-<ruby>
-class User
- has_one :profile
-
- def age
- profile.age
- end
-end
-</ruby>
-
-But with +delegate+ you can make that shorter and the intention even more obvious:
-
-<ruby>
-class User
- has_one :profile
-
- delegate :age, to => :profile
-end
-</ruby>
-
-The macro accepts more than one method:
-
-<ruby>
-class User
- has_one :profile
-
- delegate :age, :avatar, :twitter_username, to => :profile
-end
-</ruby>
-
-Methods can be delegated to objects returned by methods, as in the examples above, but also to instance variables, class variables, and constants. Just pass their names as symbols or strings, including the at signs in the last cases.
-
-For example, +ActionView::Base+ delegates +erb_trim_mode=+:
-
-<ruby>
-module ActionView
- class Base
- delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
- end
-end
-</ruby>
-
-In fact, you can delegate to any expression passed as a string. It will be evaluated in the context of the receiver. Controllers for example delegate alerts and notices to the current flash:
-
-<ruby>
-delegate :alert, :notice, :to => "request.flash"
-</ruby>
-
-If the target is +nil+ calling any delegated method will raise an exception even if +nil+ responds to such method. You can override this behavior setting the option +:allow_nil+ to true, in which case the forwarded call will simply return +nil+.
-
-If the target is a method, the name of delegated methods can also be prefixed. If the +:prefix+ option is set to (exactly) the +true+ object, the value of the +:to+ option is prefixed:
-
-<ruby>
-class Invoice
- belongs_to :customer
-
- # defines a method called customer_name
- delegate :name, :to => :customer, :prefix => true
-end
-</ruby>
-
-And a custom prefix can be set as well, in that case it does not matter wheter the target is a method or not:
-
-<ruby>
-class Account
- belongs_to :user
-
- # defines a method called admin_email
- delegate :email, :to => :user, :prefix => 'admin'
-end
-</ruby>
-
-NOTE: Defined in +active_support/core_ext/module/delegation.rb+.
-
-h4. Method Removal
-
-h5. +remove_possible_method+
-
-The method +remove_possible_method+ is like the standard +remove_method+, except it silently returns on failure:
-
-<ruby>
-class A; end
-
-A.class_eval do
- remove_method(:nonexistent) # raises NameError
- remove_possible_method(:nonexistent) # no problem, continue
-end
-</ruby>
-
-This may come in handy if you need to define a method that may already exist, since redefining a method issues a warning "method redefined; discarding old redefined_method_name".
-
-h5. +redefine_method(method_name, &block)+
-
-The method first removes method with given name (using +remove_possible_method+) and then defines new one.
-
-<ruby>
-class A; end
-
-A.class_eval do
- redefine_method(:foobar) do |foo|
- #do something here
- end
-
- #Code above does the same as this:
-
- method_name = :foobar
- remove_possible_method(method_name)
- define_method(method_name) do |foo|
- #do something here
- end
-end
-</ruby>
-
-NOTE: Defined in +active_support/core_ext/module/remove_method.rb+.
-
h4. Parents
h5. +parent+
@@ -984,6 +845,121 @@ though an anonymous module is unreachable by definition.
NOTE: Defined in +active_support/core_ext/module/anonymous.rb+.
+h4. Method Delegation
+
+The macro +delegate+ offers an easy way to forward methods.
+
+Let's imagine that users in some application have login information in the +User+ model but name and other data in a separate +Profile+ model:
+
+<ruby>
+class User < ActiveRecord::Base
+ has_one :profile
+end
+</ruby>
+
+With that configuration you get a user's name via his profile, +user.profile.name+, but it could be handy to still be able to access such attribute directly:
+
+<ruby>
+class User < ActiveRecord::Base
+ has_one :profile
+
+ def name
+ profile.name
+ end
+end
+</ruby>
+
+That is what +delegate+ does for you:
+
+<ruby>
+class User < ActiveRecord::Base
+ has_one :profile
+
+ delegate :name, :to => :profile
+end
+</ruby>
+
+It is shorter, and the intention more obvious.
+
+The macro accepts several methods:
+
+<ruby>
+delegate :name, :age, :address, :twitter, :to => :profile
+</ruby>
+
+When interpolated into a string, the +:to+ option should become an expression that evaluates to the object the method is delegated to. Typically a string or symbol. Such a expression is evaluated in the context of the receiver:
+
+<ruby>
+# delegates to the Rails constant
+delegate :logger, :to => :Rails
+
+# delegates to the receiver's class
+delegate :table_name, :to => 'self.class'
+</ruby>
+
+WARNING: If the +:prefix+ option is +true+ this is less generic, see below.
+
+By default, if the delegation raises +NoMethodError+ and the target is +nil+ the exception is propagated. You can ask that +nil+ is returned instead with the +:allow_nil+ option:
+
+<ruby>
+delegate :name, :to => :profile, :allow_nil => true
+</ruby>
+
+With +:allow_nil+ the call +user.name+ returns +nil+ if the user has no profile.
+
+The option +:prefix+ adds a prefix to the name of the generated method. This may be handy for example to get a better name:
+
+<ruby>
+delegate :street, :to => :address, :prefix => true
+</ruby>
+
+The previous example generates +address_street+ rather than +street+.
+
+WARNING: Since in this case the name of the generated method is composed of the target object and target method names, the +:to+ option must be a method name.
+
+A custom prefix may also be configured:
+
+<ruby>
+delegate :size, :to => :attachment, :prefix => :avatar
+</ruby>
+
+In the previous example the macro generates +avatar_size+ rather than +size+.
+
+NOTE: Defined in +active_support/core_ext/module/delegation.rb+
+
+h4. Method Names
+
+The builtin methods +instance_methods+ and +methods+ return method names as strings or symbols depending on the Ruby version. Active Support defines +instance_method_names+ and +method_names+ to be equivalent to them, respectively, but always getting strings back.
+
+For example, +ActionView::Helpers::FormBuilder+ knows this array difference is going to work no matter the Ruby version:
+
+<ruby>
+self.field_helpers = (FormHelper.instance_method_names - ['form_for'])
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/module/method_names.rb+
+
+h4. Redefining Methods
+
+There are cases where you need to define a method with +define_method+, but don't know whether a method with that name already exists. If it does, a warning is issued if they are enabled. No big deal, but not clean either.
+
+The method +redefine_method+ prevents such a potential warning, removing the existing method before if needed. Rails uses it in a few places, for instance when it generates an association's API:
+
+<ruby>
+redefine_method("#{reflection.name}=") do |new_value|
+ association = association_instance_get(reflection.name)
+
+ if association.nil? || association.target != new_value
+ association = association_proxy_class.new(self, reflection)
+ end
+
+ association.replace(new_value)
+ association_instance_set(reflection.name, new_value.nil? ? nil : association)
+end
+</ruby>
+
+NOTE: Defined in +active_support/core_ext/module/remove_method.rb+
+
h3. Extensions to +Class+
h4. Class Attributes
@@ -3009,6 +2985,26 @@ Date.new(2010, 1, 31).change(:month => 2)
# => ArgumentError: invalid date
</ruby>
+h5. Durations
+
+Durations can be added and substracted to dates:
+
+<ruby>
+d = Date.current
+# => Mon, 09 Aug 2010
+d + 1.year
+# => Tue, 09 Aug 2011
+d - 3.hours
+# => Sun, 08 Aug 2010 21:00:00 UTC +00:00
+</ruby>
+
+They translate to calls to +since+ or +advance+. For example here we get the correct jump in the calendar reform:
+
+<ruby>
+Date.new(1582, 10, 4) + 1.day
+# => Fri, 15 Oct 1582
+</ruby>
+
h5. Timestamps
INFO: The following methods return a +Time+ object if possible, otherwise a +DateTime+. If set, they honor the user time zone.
@@ -3195,7 +3191,25 @@ DateTime.current.change(:month => 2, :day => 30)
# => ArgumentError: invalid date
</ruby>
-h4(#datetime-conversions). Conversions
+h5. Durations
+
+Durations can be added and substracted to datetimes:
+
+<ruby>
+now = DateTime.current
+# => Mon, 09 Aug 2010 23:15:17 +0000
+now + 1.year
+# => Tue, 09 Aug 2011 23:15:17 +0000
+now - 1.week
+# => Mon, 02 Aug 2010 23:15:17 +0000
+</ruby>
+
+They translate to calls to +since+ or +advance+. For example here we get the correct jump in the calendar reform:
+
+<ruby>
+DateTime.new(1582, 10, 4, 23) + 1.hour
+# => Fri, 15 Oct 1582 00:00:00 +0000
+</ruby>
h3. Extensions to +Time+
@@ -3243,6 +3257,9 @@ They are analogous. Please refer to their documentation above and take into acco
* +Time+ understands DST, so you get correct DST calculations as in
<ruby>
+Time.zone_default
+# => #<ActiveSupport::TimeZone:0x7f73654d4f38 @utc_offset=nil, @name="Madrid", ...>
+
# In Barcelona, 2010/03/28 02:00 +0100 becomes 2010/03/28 03:00 +0200 due to DST.
t = Time.local_time(2010, 3, 28, 1, 59, 59)
# => Sun Mar 28 01:59:59 +0100 2010
@@ -3287,9 +3304,31 @@ Both +local_time+ and +utc_time+ accept up to seven positional arguments: year,
If the time to be constructed lies beyond the range supported by +Time+ in the runtime platform, usecs are discarded and a +DateTime+ object is returned instead.
+h5. Durations
+
+Durations can be added and substracted to time objects:
+
+<ruby>
+now = Time.current
+# => Mon, 09 Aug 2010 23:20:05 UTC +00:00
+now + 1.year
+# => Tue, 09 Aug 2011 23:21:11 UTC +00:00
+now - 1.week
+# => Mon, 02 Aug 2010 23:21:11 UTC +00:00
+</ruby>
+
+They translate to calls to +since+ or +advance+. For example here we get the correct jump in the calendar reform:
+
+<ruby>
+Time.utc_time(1582, 10, 3) + 5.days
+# => Mon Oct 18 00:00:00 UTC 1582
+</ruby>
+
h3. Extensions to +Process+
-...
+h4. +daemon+
+
+Ruby 1.9 provides +Process.daemon+, and Active Support defines it for previous versions. It accepts the same two arguments, whether it should chdir to the root directory (default, true), and whether it should inherit the standard file descriptors from the parent (default, false).
h3. Extensions to +File+
@@ -3365,4 +3404,5 @@ h3. Changelog
"Lighthouse ticket":https://rails.lighthouseapp.com/projects/16213/tickets/67
+* August 10, 2010: Starts to take shape, added to the index.
* April 18, 2009: Initial version by "Xavier Noria":credits.html#fxn
diff --git a/railties/guides/source/form_helpers.textile b/railties/guides/source/form_helpers.textile
index 1f1b7d076e..146b75da3f 100644
--- a/railties/guides/source/form_helpers.textile
+++ b/railties/guides/source/form_helpers.textile
@@ -647,7 +647,7 @@ the +params+ hash will contain
{'person' => {'name' => 'Henry'}}
</erb>
-and +params["name"]+ will retrieve the submitted value in the controller.
+and +params[:person][:name]+ will retrieve the submitted value in the controller.
Hashes can be nested as many levels as required, for example
diff --git a/railties/guides/source/index.html.erb b/railties/guides/source/index.html.erb
index 254ee91ab4..a0db87c188 100644
--- a/railties/guides/source/index.html.erb
+++ b/railties/guides/source/index.html.erb
@@ -88,6 +88,10 @@ Ruby on Rails Guides
<dl>
+<%= guide("Active Support Core Extensions", 'active_support_core_extensions.html') do %>
+ <p>This guide documents the Ruby core extensions defined in Active Support.</p>
+<% end %>
+
<%= guide("Rails Internationalization API", 'i18n.html') do %>
<p>This guide covers how to add internationalization to your applications. Your application will be able to translate content to different languages, change pluralization rules, use correct date formats for each country and so on.</p>
<% end %>
diff --git a/railties/guides/source/layout.html.erb b/railties/guides/source/layout.html.erb
index c4758316ea..cc7d54c256 100644
--- a/railties/guides/source/layout.html.erb
+++ b/railties/guides/source/layout.html.erb
@@ -62,6 +62,7 @@
</dl>
<dl class="R">
<dt>Digging Deeper</dt>
+ <dd><a href="active_support_core_extensions.html">Active Support Core Extensions</a></dd>
<dd><a href="i18n.html">Rails Internationalization API</a></dd>
<dd><a href="action_mailer_basics.html">Action Mailer Basics</a></dd>
<dd><a href="testing.html">Testing Rails Applications</a></dd>
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 6622cfdd2f..5b26333486 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -205,7 +205,7 @@ module Rails
middleware.use ::ActionDispatch::ParamsParser
middleware.use ::Rack::MethodOverride
middleware.use ::ActionDispatch::Head
- middleware.use ::ActionDispatch::BestStandardsSupport if config.action_dispatch.best_standards_support
+ middleware.use ::ActionDispatch::BestStandardsSupport, config.action_dispatch.best_standards_support if config.action_dispatch.best_standards_support
end
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 1980684a94..3a8a63a2f9 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -13,7 +13,7 @@ gem 'rails', '<%= Rails::VERSION::STRING %>'
# gem 'rails', :git => 'git://github.com/rails/rails.git'
<%- end -%>
-<% unless options[:skip_activerecord] -%>
+<% unless options[:skip_active_record] -%>
gem '<%= gem_for_database %>'<% if require_for_database %>, :require => '<%= require_for_database %>'<% end %>
<% end -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
index 99758dfcf7..7616614aff 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/environments/development.rb.tt
@@ -19,4 +19,8 @@
# Print deprecation notices to the Rails logger
config.active_support.deprecation = :log
+
+ # Only use best-standards-support built into browsers
+ config.action_dispatch.best_standards_support = :builtin
end
+
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
index a10a39ef40..febc53bac9 100644
--- a/railties/test/application/routing_test.rb
+++ b/railties/test/application/routing_test.rb
@@ -11,19 +11,19 @@ module ApplicationTests
extend Rack::Test::Methods
end
- def app
+ def app(env = "production")
+ old_env = ENV["RAILS_ENV"]
+
@app ||= begin
+ ENV["RAILS_ENV"] = env
require "#{app_path}/config/environment"
Rails.application
end
+ ensure
+ ENV["RAILS_ENV"] = old_env
end
- test "rails/info/properties" do
- get "/rails/info/properties"
- assert_equal 200, last_response.status
- end
-
- test "simple controller" do
+ def simple_controller
controller :foo, <<-RUBY
class FooController < ApplicationController
def index
@@ -37,12 +37,42 @@ module ApplicationTests
match ':controller(/:action)'
end
RUBY
+ end
+
+ test "rails/info/properties in development" do
+ app("development")
+ get "/rails/info/properties"
+ assert_equal 200, last_response.status
+ end
+
+ test "rails/info/properties in production" do
+ app("production")
+ get "/rails/info/properties"
+ assert_equal 404, last_response.status
+ end
+
+ test "simple controller" do
+ simple_controller
get '/foo'
assert_equal 'foo', last_response.body
+ end
+
+ test "simple controller in production mode returns best standards" do
+ simple_controller
+
+ get '/foo'
assert_equal "IE=Edge,chrome=1", last_response.headers["X-UA-Compatible"]
end
+ test "simple controller in development mode leaves out Chrome" do
+ simple_controller
+ app("development")
+
+ get "/foo"
+ assert_equal "IE=Edge", last_response.headers["X-UA-Compatible"]
+ end
+
test "simple controller with helper" do
controller :foo, <<-RUBY
class FooController < ApplicationController
@@ -147,38 +177,42 @@ module ApplicationTests
assert_equal 'admin::foo', last_response.body
end
- test "reloads routes when configuration is changed" do
- controller :foo, <<-RUBY
- class FooController < ApplicationController
- def bar
- render :text => "bar"
+ {"development" => "baz", "production" => "bar"}.each do |mode, expected|
+ test "reloads routes when configuration is changed in #{mode}" do
+ controller :foo, <<-RUBY
+ class FooController < ApplicationController
+ def bar
+ render :text => "bar"
+ end
+
+ def baz
+ render :text => "baz"
+ end
end
+ RUBY
- def baz
- render :text => "baz"
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match 'foo', :to => 'foo#bar'
end
- end
- RUBY
+ RUBY
- app_file 'config/routes.rb', <<-RUBY
- AppTemplate::Application.routes.draw do |map|
- match 'foo', :to => 'foo#bar'
- end
- RUBY
+ app(mode)
- get '/foo'
- assert_equal 'bar', last_response.body
+ get '/foo'
+ assert_equal 'bar', last_response.body
- app_file 'config/routes.rb', <<-RUBY
- AppTemplate::Application.routes.draw do |map|
- match 'foo', :to => 'foo#baz'
- end
- RUBY
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match 'foo', :to => 'foo#baz'
+ end
+ RUBY
- sleep 0.1
+ sleep 0.1
- get '/foo'
- assert_equal 'baz', last_response.body
+ get '/foo'
+ assert_equal expected, last_response.body
+ end
end
test 'resource routing with irrigular inflection' do