aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.yardopts1
-rw-r--r--Gemfile6
-rw-r--r--actionmailer/actionmailer.gemspec2
-rw-r--r--actionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/metal/redirecting.rb6
-rw-r--r--actionpack/lib/action_dispatch/http/url.rb10
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb10
-rw-r--r--actionpack/lib/action_view/helpers/asset_tag_helper.rb64
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb31
-rw-r--r--actionpack/test/dispatch/request_test.rb5
-rw-r--r--activemodel/lib/active_model/attribute_methods.rb35
-rw-r--r--activerecord/examples/performance.rb19
-rw-r--r--activerecord/lib/active_record/attribute_methods.rb4
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb24
-rw-r--r--activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb5
-rw-r--r--activerecord/lib/active_record/base.rb24
-rw-r--r--activerecord/lib/active_record/relation/batches.rb2
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb5
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb2
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder.rb4
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb51
-rw-r--r--activerecord/lib/active_record/relation/spawn_methods.rb43
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb27
-rw-r--r--activerecord/test/cases/method_scoping_test.rb2
-rw-r--r--activerecord/test/cases/relations_test.rb17
-rw-r--r--activerecord/test/models/subject.rb10
-rw-r--r--railties/guides/source/plugins.textile16
-rw-r--r--railties/test/application/initializers/frameworks_test.rb7
28 files changed, 251 insertions, 183 deletions
diff --git a/.yardopts b/.yardopts
index 4f89247bbb..25ec38658f 100644
--- a/.yardopts
+++ b/.yardopts
@@ -1,3 +1,4 @@
--exclude /templates/
--quiet
act*/lib/**/*.rb
+railties/lib/**/*.rb
diff --git a/Gemfile b/Gemfile
index 124fbf5d24..d9f089f7ab 100644
--- a/Gemfile
+++ b/Gemfile
@@ -13,6 +13,11 @@ gem "mocha", ">= 0.9.8"
gem "rdoc", ">= 2.5.10"
gem "horo", ">= 1.0.2"
+# for perf tests
+gem "faker"
+gem "rbench"
+gem "addressable"
+
# AS
gem "memcache-client", ">= 1.8.5"
@@ -22,6 +27,7 @@ gem "text-format", "~> 1.0.0"
platforms :mri_18 do
gem "system_timer"
gem "ruby-debug", ">= 0.10.3"
+ gem 'ruby-prof'
end
platforms :mri_19 do
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index daf30e434a..6cdf10e255 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -20,5 +20,5 @@ Gem::Specification.new do |s|
s.has_rdoc = true
s.add_dependency('actionpack', version)
- s.add_dependency('mail', '~> 2.2.5')
+ s.add_dependency('mail', '~> 2.2.6')
end
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index b37bc02127..631a0f2945 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -148,6 +148,8 @@ module ActionController
#
# In this case, after saving our new entry to the database, the user is redirected to the <tt>show</tt> method which is then executed.
#
+ # Learn more about <tt>redirect_to</tt> and what options you have in ActionController::Redirecting.
+ #
# == Calling multiple redirects or renders
#
# An action may contain only a single render or a single redirect. Attempting to try to do either again will result in a DoubleRenderError:
diff --git a/actionpack/lib/action_controller/metal/redirecting.rb b/actionpack/lib/action_controller/metal/redirecting.rb
index b5f1d23ef0..10d7794b57 100644
--- a/actionpack/lib/action_controller/metal/redirecting.rb
+++ b/actionpack/lib/action_controller/metal/redirecting.rb
@@ -38,6 +38,9 @@ module ActionController
# redirect_to :action=>'atom', :status => :moved_permanently
# redirect_to post_url(@post), :status => 301
# redirect_to :action=>'atom', :status => 302
+ #
+ # The status code can either be a standard {HTTP Status code}[http://www.iana.org/assignments/http-status-codes] as an
+ # integer, or a symbol representing the downcased, underscored and symbolized description.
#
# It is also possible to assign a flash message as part of the redirection. There are two special accessors for commonly used the flash names
# +alert+ and +notice+ as well as a general purpose +flash+ bucket.
@@ -48,8 +51,7 @@ module ActionController
# redirect_to post_url(@post), :status => 301, :flash => { :updated_post_id => @post.id }
# redirect_to { :action=>'atom' }, :alert => "Something serious happened"
#
- # When using <tt>redirect_to :back</tt>, if there is no referrer,
- # RedirectBackError will be raised. You may specify some fallback
+ # When using <tt>redirect_to :back</tt>, if there is no referrer, RedirectBackError will be raised. You may specify some fallback
# behavior for this case by rescuing RedirectBackError.
def redirect_to(options = {}, response_status = {}) #:doc:
raise ActionControllerError.new("Cannot redirect to nil!") if options.nil?
diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb
index 38f46fa120..2e39d0dbc2 100644
--- a/actionpack/lib/action_dispatch/http/url.rb
+++ b/actionpack/lib/action_dispatch/http/url.rb
@@ -1,7 +1,9 @@
module ActionDispatch
module Http
module URL
- # Returns the complete \URL used for this request.
+ mattr_accessor :tld_length
+
+ # Returns the complete URL used for this request.
def url
protocol + host_with_port + fullpath
end
@@ -85,13 +87,13 @@ module ActionDispatch
# returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
# such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
# in "www.rubyonrails.co.uk".
- def subdomains(tld_length = 1)
+ def subdomains(tld_length = @@tld_length)
return [] unless named_host?(host)
parts = host.split('.')
parts[0..-(tld_length+2)]
end
- def subdomain(tld_length = 1)
+ def subdomain(tld_length = @@tld_length)
subdomains(tld_length).join('.')
end
@@ -102,4 +104,4 @@ module ActionDispatch
end
end
end
-end
+end \ No newline at end of file
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index ed066ad75e..c202fee990 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -8,5 +8,15 @@ module ActionDispatch
config.action_dispatch.ip_spoofing_check = true
config.action_dispatch.show_exceptions = true
config.action_dispatch.best_standards_support = true
+ config.action_dispatch.tld_length = 1
+
+ # Prepare dispatcher callbacks and run 'prepare' callbacks
+ initializer "action_dispatch.prepare_dispatcher" do |app|
+ ActionDispatch::Callbacks.to_prepare { app.routes_reloader.execute_if_updated }
+ end
+
+ initializer "action_dispatch.configure" do |app|
+ ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
+ end
end
end
diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
index 3329a8b368..fdc40c8f2e 100644
--- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb
@@ -257,53 +257,53 @@ module ActionView
end
alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route
- # Returns an html script tag for each of the +sources+ provided. You
- # can pass in the filename (.js extension is optional) of javascript files
- # that exist in your public/javascripts directory for inclusion into the
+ # Returns an HTML script tag for each of the +sources+ provided. You
+ # can pass in the filename (.js extension is optional) of JavaScript files
+ # that exist in your <tt>public/javascripts</tt> directory for inclusion into the
# current page or you can pass the full path relative to your document
- # root. To include the Prototype and Scriptaculous javascript libraries in
+ # root. To include the Prototype and Scriptaculous JavaScript libraries in
# your application, pass <tt>:defaults</tt> as the source. When using
- # <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.
+ # <tt>:defaults</tt>, if an <tt>application.js</tt> file exists in
+ # <tt>public/javascripts</tt> it will be included as well. You can modify the
+ # HTML attributes of the script tag by passing a hash as the last argument.
#
# ==== Examples
# javascript_include_tag "xmlhr" # =>
- # <script type="text/javascript" src="/javascripts/xmlhr.js"></script>
+ # <script type="text/javascript" src="/javascripts/xmlhr.js?1284139606"></script>
#
# javascript_include_tag "xmlhr.js" # =>
- # <script type="text/javascript" src="/javascripts/xmlhr.js"></script>
+ # <script type="text/javascript" src="/javascripts/xmlhr.js?1284139606"></script>
#
# javascript_include_tag "common.javascript", "/elsewhere/cools" # =>
- # <script type="text/javascript" src="/javascripts/common.javascript"></script>
- # <script type="text/javascript" src="/elsewhere/cools.js"></script>
+ # <script type="text/javascript" src="/javascripts/common.javascript?1284139606"></script>
+ # <script type="text/javascript" src="/elsewhere/cools.js?1423139606"></script>
#
# javascript_include_tag "http://www.railsapplication.com/xmlhr" # =>
- # <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js"></script>
+ # <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js?1284139606"></script>
#
# javascript_include_tag "http://www.railsapplication.com/xmlhr.js" # =>
- # <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js"></script>
+ # <script type="text/javascript" src="http://www.railsapplication.com/xmlhr.js?1284139606"></script>
#
# javascript_include_tag :defaults # =>
- # <script type="text/javascript" src="/javascripts/prototype.js"></script>
- # <script type="text/javascript" src="/javascripts/effects.js"></script>
+ # <script type="text/javascript" src="/javascripts/prototype.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/effects.js?1284139606"></script>
# ...
- # <script type="text/javascript" src="/javascripts/application.js"></script>
+ # <script type="text/javascript" src="/javascripts/application.js?1284139606"></script>
#
# * = The application.js file is only referenced if it exists
#
# Though it's not really recommended practice, if you need to extend the default JavaScript set for any reason
# (e.g., you're going to be using a certain .js file in every action), then take a look at the register_javascript_include_default method.
#
- # You can also include all javascripts in the javascripts directory using <tt>:all</tt> as the source:
+ # You can also include all javascripts in the +javascripts+ directory using <tt>:all</tt> as the source:
#
# javascript_include_tag :all # =>
- # <script type="text/javascript" src="/javascripts/prototype.js"></script>
- # <script type="text/javascript" src="/javascripts/effects.js"></script>
+ # <script type="text/javascript" src="/javascripts/prototype.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/effects.js?1284139606"></script>
# ...
- # <script type="text/javascript" src="/javascripts/application.js"></script>
- # <script type="text/javascript" src="/javascripts/shop.js"></script>
- # <script type="text/javascript" src="/javascripts/checkout.js"></script>
+ # <script type="text/javascript" src="/javascripts/application.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/shop.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/checkout.js?1284139606"></script>
#
# Note that the default javascript files will be included first. So Prototype and Scriptaculous are available to
# all subsequently included files.
@@ -321,23 +321,23 @@ module ActionView
#
# ==== Examples
# javascript_include_tag :all, :cache => true # when config.perform_caching is false =>
- # <script type="text/javascript" src="/javascripts/prototype.js"></script>
- # <script type="text/javascript" src="/javascripts/effects.js"></script>
+ # <script type="text/javascript" src="/javascripts/prototype.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/effects.js?1284139606"></script>
# ...
- # <script type="text/javascript" src="/javascripts/application.js"></script>
- # <script type="text/javascript" src="/javascripts/shop.js"></script>
- # <script type="text/javascript" src="/javascripts/checkout.js"></script>
+ # <script type="text/javascript" src="/javascripts/application.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/shop.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/checkout.js?1284139606"></script>
#
# javascript_include_tag :all, :cache => true # when config.perform_caching is true =>
- # <script type="text/javascript" src="/javascripts/all.js"></script>
+ # <script type="text/javascript" src="/javascripts/all.js?1344139789"></script>
#
# javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is false =>
- # <script type="text/javascript" src="/javascripts/prototype.js"></script>
- # <script type="text/javascript" src="/javascripts/cart.js"></script>
- # <script type="text/javascript" src="/javascripts/checkout.js"></script>
+ # <script type="text/javascript" src="/javascripts/prototype.js?1284139606"></script>
+ # <script type="text/javascript" src="/javascripts/cart.js?1289139157"></script>
+ # <script type="text/javascript" src="/javascripts/checkout.js?1299139816"></script>
#
# javascript_include_tag "prototype", "cart", "checkout", :cache => "shop" # when config.perform_caching is true =>
- # <script type="text/javascript" src="/javascripts/shop.js"></script>
+ # <script type="text/javascript" src="/javascripts/shop.js?1299139816"></script>
#
# The <tt>:recursive</tt> option is also available for caching:
#
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 43dbedc448..6d70c63de9 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -293,31 +293,32 @@ module ActionView
#
# If you don't need to attach a form to a model instance, then check out
# FormTagHelper#form_tag.
- def form_for(record_or_name_or_array, *args, &proc)
+ def form_for(record, record_object = nil, options = nil, &proc)
raise ArgumentError, "Missing block" unless block_given?
- options = args.extract_options!
+ options, record_object = record_object, nil if record_object.is_a?(Hash)
+ options ||= {}
- case record_or_name_or_array
+ case record
when String, Symbol
- ActiveSupport::Deprecation.warn("Using form_for(:name, @resource) is deprecated. Please use form_for(@resource, :as => :name) instead.", caller) unless args.empty?
- object_name = record_or_name_or_array
+ ActiveSupport::Deprecation.warn("Using form_for(:name, @resource) is deprecated. Please use form_for(@resource, :as => :name) instead.", caller) if record_object
+ object_name = record
+ object = record_object
when Array
- object = record_or_name_or_array.last
- object_name = options[:as] || ActiveModel::Naming.param_key(object)
- apply_form_for_options!(record_or_name_or_array, options)
- args.unshift object
+ object = record.last
+ object_name = options[:as] || ActiveModel::Naming.singular(object)
+ apply_form_for_options!(record, options)
else
- object = record_or_name_or_array
- object_name = options[:as] || ActiveModel::Naming.param_key(object)
+ object = record
+ object_name = options[:as] || ActiveModel::Naming.singular(object)
apply_form_for_options!([object], options)
- args.unshift object
end
- (options[:html] ||= {})[:remote] = true if options.delete(:remote)
+ options[:html] ||= {}
+ options[:html][:remote] = options.delete(:remote)
- output = form_tag(options.delete(:url) || {}, options.delete(:html) || {})
- output << fields_for(object_name, *(args << options), &proc)
+ output = form_tag(options.delete(:url) || {}, options.delete(:html) || {})
+ output << fields_for(object_name, object, options, &proc)
output.safe_concat('</form>')
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 546c4cb253..a8b8f9377b 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -116,6 +116,9 @@ class RequestTest < ActiveSupport::TestCase
request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk"
assert_equal %w( dev www ), request.subdomains(2)
+ request = stub_request 'HTTP_HOST' => "dev.www.rubyonrails.co.uk", :tld_length => 2
+ assert_equal %w( dev www ), request.subdomains
+
request = stub_request 'HTTP_HOST' => "foobar.foobar.com"
assert_equal %w( foobar ), request.subdomains
@@ -472,7 +475,9 @@ protected
def stub_request(env = {})
ip_spoofing_check = env.key?(:ip_spoofing_check) ? env.delete(:ip_spoofing_check) : true
ip_app = ActionDispatch::RemoteIp.new(Proc.new { }, ip_spoofing_check, @trusted_proxies)
+ tld_length = env.key?(:tld_length) ? env.delete(:tld_length) : 1
ip_app.call(env)
+ ActionDispatch::Http::URL.tld_length = tld_length
ActionDispatch::Request.new(env)
end
diff --git a/activemodel/lib/active_model/attribute_methods.rb b/activemodel/lib/active_model/attribute_methods.rb
index b8126fb67e..44e3e64a9e 100644
--- a/activemodel/lib/active_model/attribute_methods.rb
+++ b/activemodel/lib/active_model/attribute_methods.rb
@@ -1,5 +1,5 @@
require 'active_support/core_ext/hash/keys'
-require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/class/attribute'
module ActiveModel
class MissingAttributeError < NoMethodError
@@ -56,6 +56,11 @@ module ActiveModel
module AttributeMethods
extend ActiveSupport::Concern
+ included do
+ class_attribute :attribute_method_matchers, :instance_writer => false
+ self.attribute_method_matchers = []
+ end
+
module ClassMethods
# Defines an "attribute" method (like +inheritance_column+ or +table_name+).
# A new (class) method will be created with the given name. If a value is
@@ -143,7 +148,7 @@ module ActiveModel
# person.clear_name
# person.name # => nil
def attribute_method_prefix(*prefixes)
- attribute_method_matchers.concat(prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix })
+ self.attribute_method_matchers += prefixes.map { |prefix| AttributeMethodMatcher.new :prefix => prefix }
undefine_attribute_methods
end
@@ -180,7 +185,7 @@ module ActiveModel
# person.name # => "Bob"
# person.name_short? # => true
def attribute_method_suffix(*suffixes)
- attribute_method_matchers.concat(suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix })
+ self.attribute_method_matchers += suffixes.map { |suffix| AttributeMethodMatcher.new :suffix => suffix }
undefine_attribute_methods
end
@@ -218,7 +223,7 @@ module ActiveModel
# person.reset_name_to_default!
# person.name # => 'Gemma'
def attribute_method_affix(*affixes)
- attribute_method_matchers.concat(affixes.map { |affix| AttributeMethodMatcher.new :prefix => affix[:prefix], :suffix => affix[:suffix] })
+ self.attribute_method_matchers += affixes.map { |affix| AttributeMethodMatcher.new :prefix => affix[:prefix], :suffix => affix[:suffix] }
undefine_attribute_methods
end
@@ -312,7 +317,7 @@ module ActiveModel
private
class AttributeMethodMatcher
- attr_reader :prefix, :suffix
+ attr_reader :prefix, :suffix, :method_missing_target
AttributeMethodMatch = Struct.new(:target, :attr_name)
@@ -320,28 +325,22 @@ module ActiveModel
options.symbolize_keys!
@prefix, @suffix = options[:prefix] || '', options[:suffix] || ''
@regex = /^(#{Regexp.escape(@prefix)})(.+?)(#{Regexp.escape(@suffix)})$/
+ @method_missing_target = :"#{@prefix}attribute#{@suffix}"
+ @method_name = "#{prefix}%s#{suffix}"
end
def match(method_name)
- if matchdata = @regex.match(method_name)
- AttributeMethodMatch.new(method_missing_target, matchdata[2])
+ if @regex =~ method_name
+ AttributeMethodMatch.new(method_missing_target, $2)
else
nil
end
end
def method_name(attr_name)
- "#{prefix}#{attr_name}#{suffix}"
- end
-
- def method_missing_target
- :"#{prefix}attribute#{suffix}"
+ @method_name % attr_name
end
end
-
- def attribute_method_matchers #:nodoc:
- read_inheritable_attribute(:attribute_method_matchers) || write_inheritable_attribute(:attribute_method_matchers, [])
- end
end
# Allows access to the object attributes, which are held in the
@@ -390,7 +389,7 @@ module ActiveModel
# Returns a struct representing the matching attribute method.
# The struct's attributes are prefix, base and suffix.
def match_attribute_method?(method_name)
- self.class.send(:attribute_method_matchers).each do |method|
+ self.class.attribute_method_matchers.each do |method|
if (match = method.match(method_name)) && attribute_method?(match.attr_name)
return match
end
@@ -401,7 +400,7 @@ module ActiveModel
# prevent method_missing from calling private methods with #send
def guard_private_attribute_method!(method_name, args)
if self.class.private_method_defined?(method_name)
- raise NoMethodError.new("Attempt to call private method", method_name, args)
+ raise NoMethodError.new("Attempt to call private method `#{method_name}'", method_name, args)
end
end
diff --git a/activerecord/examples/performance.rb b/activerecord/examples/performance.rb
index a985cfcb66..ccd60c6c69 100644
--- a/activerecord/examples/performance.rb
+++ b/activerecord/examples/performance.rb
@@ -25,7 +25,7 @@ conn[:socket] = Pathname.glob(%w[
/tmp/mysql.sock
/var/mysql/mysql.sock
/var/run/mysqld/mysqld.sock
-]).find { |path| path.socket? }
+]).find { |path| path.socket? }.to_s
ActiveRecord::Base.establish_connection(conn)
@@ -155,6 +155,23 @@ RBench.run(TIMES) do
ar { Exhibit.transaction { Exhibit.new } }
end
+ report 'Model.find(id)' do
+ id = Exhibit.first.id
+ ar { Exhibit.find(id) }
+ end
+
+ report 'Model.find_by_sql' do
+ ar { Exhibit.find_by_sql("SELECT * FROM exhibits WHERE id = #{(rand * 1000 + 1).to_i}").first }
+ end
+
+ report 'Model.log', (TIMES * 10) do
+ ar { Exhibit.connection.send(:log, "hello", "world") {} }
+ end
+
+ report 'AR.execute(query)', (TIMES / 2) do
+ ar { ActiveRecord::Base.connection.execute("Select * from exhibits where id = #{(rand * 1000 + 1).to_i}") }
+ end
+
summary 'Total'
end
diff --git a/activerecord/lib/active_record/attribute_methods.rb b/activerecord/lib/active_record/attribute_methods.rb
index 56e18eced0..7297af9f79 100644
--- a/activerecord/lib/active_record/attribute_methods.rb
+++ b/activerecord/lib/active_record/attribute_methods.rb
@@ -48,13 +48,13 @@ module ActiveRecord
end
def respond_to?(*args)
- self.class.define_attribute_methods
+ self.class.define_attribute_methods unless self.class.attribute_methods_generated?
super
end
protected
def attribute_method?(attr_name)
- attr_name == 'id' || attributes.include?(attr_name)
+ attr_name == 'id' || @attributes.include?(attr_name)
end
end
end
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 3da3d9d8cc..01699746d8 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -26,8 +26,7 @@ module ActiveRecord
# Returns the attributes which are cached. By default time related columns
# with datatype <tt>:datetime, :timestamp, :time, :date</tt> are cached.
def cached_attributes
- @cached_attributes ||=
- columns.select{|c| attribute_types_cached_by_default.include?(c.type)}.map{|col| col.name}.to_set
+ @cached_attributes ||= columns.select { |c| cacheable_column?(c) }.map { |col| col.name }.to_set
end
# Returns +true+ if the provided attribute is being cached.
@@ -37,7 +36,7 @@ module ActiveRecord
protected
def define_method_attribute(attr_name)
- if self.serialized_attributes[attr_name]
+ if serialized_attributes.include?(attr_name)
define_read_method_for_serialized_attribute(attr_name)
else
define_read_method(attr_name.to_sym, attr_name, columns_hash[attr_name])
@@ -49,9 +48,14 @@ module ActiveRecord
end
private
+ def cacheable_column?(column)
+ serialized_attributes.include?(column.name) || attribute_types_cached_by_default.include?(column.type)
+ end
+
# Define read method for serialized attribute.
def define_read_method_for_serialized_attribute(attr_name)
- generated_attribute_methods.module_eval("def #{attr_name}; unserialize_attribute('#{attr_name}'); end", __FILE__, __LINE__)
+ access_code = "@attributes_cache['#{attr_name}'] ||= unserialize_attribute('#{attr_name}')"
+ generated_attribute_methods.module_eval("def #{attr_name}; #{access_code}; end", __FILE__, __LINE__)
end
# Define an attribute reader method. Cope with nil column.
@@ -66,13 +70,19 @@ module ActiveRecord
if cache_attribute?(attr_name)
access_code = "@attributes_cache['#{attr_name}'] ||= (#{access_code})"
end
- generated_attribute_methods.module_eval("def #{symbol}; #{access_code}; end", __FILE__, __LINE__)
+ generated_attribute_methods.module_eval("def _#{symbol}; #{access_code}; end; alias #{symbol} _#{symbol}", __FILE__, __LINE__)
end
end
# Returns the value of the attribute identified by <tt>attr_name</tt> after it has been typecast (for example,
# "2004-12-12" in a data column is cast to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name)
+ send "_#{attr_name}"
+ rescue NoMethodError
+ _read_attribute attr_name
+ end
+
+ def _read_attribute(attr_name)
attr_name = attr_name.to_s
attr_name = self.class.primary_key if attr_name == 'id'
if !(value = @attributes[attr_name]).nil?
@@ -85,14 +95,12 @@ module ActiveRecord
else
value
end
- else
- nil
end
end
# Returns true if the attribute is of a text column and marked for serialization.
def unserializable_attribute?(attr_name, column)
- column.text? && self.class.serialized_attributes[attr_name]
+ column.text? && self.class.serialized_attributes.include?(attr_name)
end
# Returns the unserialized object of the attribute.
diff --git a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
index a258b3f431..d640b26b74 100644
--- a/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
+++ b/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb
@@ -19,12 +19,13 @@ module ActiveRecord
def define_method_attribute(attr_name)
if create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
method_body, line = <<-EOV, __LINE__ + 1
- def #{attr_name}(reload = false)
+ def _#{attr_name}(reload = false)
cached = @attributes_cache['#{attr_name}']
return cached if cached && !reload
- time = read_attribute('#{attr_name}')
+ time = _read_attribute('#{attr_name}')
@attributes_cache['#{attr_name}'] = time.acts_like?(:time) ? time.in_time_zone : time
end
+ alias #{attr_name} _#{attr_name}
EOV
generated_attribute_methods.module_eval(method_body, __FILE__, line)
else
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index ef4834811c..5da4eb169b 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -415,6 +415,11 @@ module ActiveRecord #:nodoc:
class_inheritable_accessor :default_scoping, :instance_writer => false
self.default_scoping = []
+ # Returns a hash of all the attributes that have been specified for serialization as
+ # keys and their class restriction as values.
+ class_attribute :serialized_attributes
+ self.serialized_attributes = {}
+
class << self # Class methods
delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped
delegate :find_each, :find_in_batches, :to => :scoped
@@ -526,12 +531,6 @@ module ActiveRecord #:nodoc:
serialized_attributes[attr_name.to_s] = class_name
end
- # Returns a hash of all the attributes that have been specified for serialization as
- # keys and their class restriction as values.
- def serialized_attributes
- read_inheritable_attribute(:attr_serialized) or write_inheritable_attribute(:attr_serialized, {})
- end
-
# Guesses the table name (in forced lower-case) based on the name of the class in the
# inheritance hierarchy descending directly from ActiveRecord::Base. So if the hierarchy
# looks like: Reply < Message < ActiveRecord::Base, then Message is used
@@ -664,7 +663,7 @@ module ActiveRecord #:nodoc:
# Returns a hash of column objects for the table associated with this class.
def columns_hash
- @columns_hash ||= columns.inject({}) { |hash, column| hash[column.name] = column; hash }
+ @columns_hash ||= Hash[columns.map { |column| [column.name, column] }]
end
# Returns an array of column names as strings.
@@ -1080,9 +1079,9 @@ module ActiveRecord #:nodoc:
if method_scoping.is_a?(Hash)
# Dup first and second level of hash (method and params).
- method_scoping = method_scoping.inject({}) do |hash, (method, params)|
- hash[method] = (params == true) ? params : params.dup
- hash
+ method_scoping = method_scoping.dup
+ method_scoping.each do |method, params|
+ method_scoping[method] = params.dup unless params == true
end
method_scoping.assert_valid_keys([ :find, :create ])
@@ -1793,10 +1792,7 @@ MSG
end
def quote_columns(quoter, hash)
- hash.inject({}) do |quoted, (name, value)|
- quoted[quoter.quote_column_name(name)] = value
- quoted
- end
+ Hash[hash.map { |name, value| [quoter.quote_column_name(name), value] }]
end
def quoted_comma_pair_list(quoter, hash)
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index d7494ebb5a..5584397439 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -50,7 +50,7 @@ module ActiveRecord
def find_in_batches(options = {})
relation = self
- if orders.present? || taken.present?
+ unless arel.orders.blank? && arel.taken.blank?
ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size")
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index a80ac40a2c..398ab75b69 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -175,12 +175,11 @@ module ActiveRecord
end
distinct = options[:distinct] || distinct
- column_name = :all if column_name.blank? && operation == "count"
if @group_values.any?
- return execute_grouped_calculation(operation, column_name)
+ execute_grouped_calculation(operation, column_name)
else
- return execute_simple_calculation(operation, column_name, distinct)
+ execute_simple_calculation(operation, column_name, distinct)
end
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 4ffb552690..ede1c8821e 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -230,7 +230,7 @@ module ActiveRecord
end
def find_by_attributes(match, attributes, *args)
- conditions = attributes.inject({}) {|h, a| h[a] = args[attributes.index(a)]; h}
+ conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
result = where(conditions).send(match.finder)
if match.bang? && result.blank?
diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb
index 5cea2328e8..0d1307d87e 100644
--- a/activerecord/lib/active_record/relation/predicate_builder.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder.rb
@@ -24,7 +24,9 @@ module ActiveRecord
case value
when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::Relation
- values = value.to_a
+ values = value.to_a.map { |x|
+ x.respond_to?(:quoted_id) ? x.quoted_id : x
+ }
attribute.in(values)
when Range, Arel::Relation
attribute.in(value)
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index cee240e6a1..de57725af2 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -12,20 +12,22 @@ module ActiveRecord
def includes(*args)
args.reject! {|a| a.blank? }
+ return clone if args.empty?
+
relation = clone
- relation.includes_values = (relation.includes_values + args).flatten.uniq if args.present?
+ relation.includes_values = (relation.includes_values + args).flatten.uniq
relation
end
def eager_load(*args)
relation = clone
- relation.eager_load_values += args if args.present?
+ relation.eager_load_values += args unless args.blank?
relation
end
def preload(*args)
relation = clone
- relation.preload_values += args if args.present?
+ relation.preload_values += args unless args.blank?
relation
end
@@ -41,19 +43,19 @@ module ActiveRecord
def group(*args)
relation = clone
- relation.group_values += args.flatten if args.present?
+ relation.group_values += args.flatten unless args.blank?
relation
end
def order(*args)
relation = clone
- relation.order_values += args.flatten if args.present?
+ relation.order_values += args.flatten unless args.blank?
relation
end
def reorder(*args)
relation = clone
- if args.present?
+ unless args.blank?
relation.order_values = args
relation.reorder_flag = true
end
@@ -63,31 +65,21 @@ module ActiveRecord
def joins(*args)
relation = clone
- if args.present?
- args.flatten!
- relation.joins_values += args if args.present?
- end
+ args.flatten!
+ relation.joins_values += args unless args.blank?
relation
end
def where(opts, *rest)
relation = clone
-
- if opts.present? && value = build_where(opts, rest)
- relation.where_values += Array.wrap(value)
- end
-
+ relation.where_values += build_where(opts, rest) unless opts.blank?
relation
end
def having(*args)
relation = clone
-
- if args.present? && value = build_where(*args)
- relation.having_values += Array.wrap(value)
- end
-
+ relation.having_values += build_where(*args) unless args.blank?
relation
end
@@ -138,7 +130,7 @@ module ActiveRecord
modules << Module.new(&block) if block_given?
relation = clone
- relation.send(:apply_modules, *modules)
+ relation.send(:apply_modules, modules.flatten)
relation
end
@@ -196,14 +188,14 @@ module ActiveRecord
end
end
- arel = arel.having(*@having_values.uniq.select{|h| h.present?}) unless @having_values.empty?
+ arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
arel = arel.take(@limit_value) if @limit_value
arel = arel.skip(@offset_value) if @offset_value
- arel = arel.group(*@group_values.uniq.select{|g| g.present?}) unless @group_values.empty?
+ arel = arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty?
- arel = arel.order(*@order_values.uniq.select{|o| o.present?}) unless @order_values.empty?
+ arel = arel.order(*@order_values.uniq.reject{|o| o.blank?}) unless @order_values.empty?
arel = build_select(arel, @select_values.uniq)
@@ -216,12 +208,12 @@ module ActiveRecord
def build_where(opts, other = [])
case opts
when String, Array
- @klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))
+ [@klass.send(:sanitize_sql, other.empty? ? opts : ([opts] + other))]
when Hash
attributes = @klass.send(:expand_hash_conditions_for_aggregates, opts)
PredicateBuilder.new(table.engine).build_from_hash(attributes, table)
else
- opts
+ [opts]
end
end
@@ -284,9 +276,10 @@ module ActiveRecord
end
def apply_modules(modules)
- values = Array.wrap(modules)
- @extensions += values if values.present?
- values.each {|extension| extend(extension) }
+ unless modules.empty?
+ @extensions += modules
+ modules.each {|extension| extend(extension) }
+ end
end
def reverse_sql_order(order_query)
diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb
index a6cf59fbf1..9ecdb99bee 100644
--- a/activerecord/lib/active_record/relation/spawn_methods.rb
+++ b/activerecord/lib/active_record/relation/spawn_methods.rb
@@ -5,6 +5,7 @@ module ActiveRecord
def merge(r)
merged_relation = clone
return merged_relation unless r
+ return to_a & r if r.is_a?(Array)
Relation::ASSOCIATION_METHODS.each do |method|
value = r.send(:"#{method}_values")
@@ -64,12 +65,12 @@ module ActiveRecord
def except(*skips)
result = self.class.new(@klass, table)
- (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).each do |method|
- result.send(:"#{method}_values=", send(:"#{method}_values")) unless skips.include?(method)
+ ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) - skips).each do |method|
+ result.send(:"#{method}_values=", send(:"#{method}_values"))
end
- Relation::SINGLE_VALUE_METHODS.each do |method|
- result.send(:"#{method}_value=", send(:"#{method}_value")) unless skips.include?(method)
+ (Relation::SINGLE_VALUE_METHODS - skips).each do |method|
+ result.send(:"#{method}_value=", send(:"#{method}_value"))
end
result
@@ -78,14 +79,12 @@ module ActiveRecord
def only(*onlies)
result = self.class.new(@klass, table)
- onlies.each do |only|
- if (Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS).include?(only)
- result.send(:"#{only}_values=", send(:"#{only}_values"))
- elsif Relation::SINGLE_VALUE_METHODS.include?(only)
- result.send(:"#{only}_value=", send(:"#{only}_value"))
- else
- raise "Invalid argument : #{only}"
- end
+ ((Relation::ASSOCIATION_METHODS + Relation::MULTI_VALUE_METHODS) & onlies).each do |method|
+ result.send(:"#{method}_values=", send(:"#{method}_values"))
+ end
+
+ (Relation::SINGLE_VALUE_METHODS & onlies).each do |method|
+ result.send(:"#{method}_value=", send(:"#{method}_value"))
end
result
@@ -99,22 +98,16 @@ module ActiveRecord
return relation unless options
options.assert_valid_keys(VALID_FIND_OPTIONS)
+ finders = options.dup
+ finders.delete_if { |key, value| value.nil? }
- [:joins, :select, :group, :having, :limit, :offset, :from, :lock].each do |finder|
- if value = options[finder]
- relation = relation.send(finder, value)
- end
- end
-
- relation = relation.readonly(options[:readonly]) if options.key? :readonly
-
- [:group, :order].each do |finder|
- relation.send("#{finder}_values=", relation.send("#{finder}_values") + Array.wrap(options[finder])) if options.has_key?(finder)
+ ([:joins, :select, :group, :order, :having, :limit, :offset, :from, :lock, :readonly] & finders.keys).each do |finder|
+ relation = relation.send(finder, finders[finder])
end
- relation = relation.where(options[:conditions]) if options.has_key?(:conditions)
- relation = relation.includes(options[:include]) if options.has_key?(:include)
- relation = relation.extending(options[:extend]) if options.has_key?(:extend)
+ relation = relation.where(finders[:conditions]) if options.has_key?(:conditions)
+ relation = relation.includes(finders[:include]) if options.has_key?(:include)
+ relation = relation.extending(finders[:extend]) if options.has_key?(:extend)
relation
end
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index 9b3cc47c79..1750bf004a 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -419,12 +419,8 @@ class AttributeMethodsTest < ActiveRecord::TestCase
Topic.instance_variable_set "@cached_attributes", nil
end
- def test_time_related_columns_are_actually_cached
- column_types = %w(datetime timestamp time date).map(&:to_sym)
- column_names = Topic.columns.select{|c| column_types.include?(c.type) }.map(&:name)
-
- assert_equal column_names.sort, Topic.cached_attributes.sort
- assert_equal time_related_columns_on_topic.sort, Topic.cached_attributes.sort
+ def test_cacheable_columns_are_actually_cached
+ assert_equal cached_columns.sort, Topic.cached_attributes.sort
end
def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
@@ -435,8 +431,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert cache.empty?
all_columns = Topic.columns.map(&:name)
- cached_columns = time_related_columns_on_topic
- uncached_columns = all_columns - cached_columns
+ uncached_columns = all_columns - cached_columns
all_columns.each do |attr_name|
attribute_gets_cached = Topic.cache_attribute?(attr_name)
@@ -546,7 +541,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = @target.new(:title => "The pros and cons of programming naked.")
assert !topic.respond_to?(:title)
exception = assert_raise(NoMethodError) { topic.title }
- assert_equal "Attempt to call private method", exception.message
+ assert_match %r(^Attempt to call private method), exception.message
assert_equal "I'm private", topic.send(:title)
end
@@ -556,7 +551,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = @target.new
assert !topic.respond_to?(:title=)
exception = assert_raise(NoMethodError) { topic.title = "Pants"}
- assert_equal "Attempt to call private method", exception.message
+ assert_match %r(^Attempt to call private method), exception.message
topic.send(:title=, "Very large pants")
end
@@ -566,7 +561,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
topic = @target.new(:title => "Isaac Newton's pants")
assert !topic.respond_to?(:title?)
exception = assert_raise(NoMethodError) { topic.title? }
- assert_equal "Attempt to call private method", exception.message
+ assert_match %r(^Attempt to call private method), exception.message
assert topic.send(:title?)
end
@@ -594,8 +589,16 @@ class AttributeMethodsTest < ActiveRecord::TestCase
private
+ def cached_columns
+ @cached_columns ||= (time_related_columns_on_topic + serialized_columns_on_topic).map(&:name)
+ end
+
def time_related_columns_on_topic
- Topic.columns.select{|c| [:time, :date, :datetime, :timestamp].include?(c.type)}.map(&:name)
+ Topic.columns.select { |c| [:time, :date, :datetime, :timestamp].include?(c.type) }
+ end
+
+ def serialized_columns_on_topic
+ Topic.columns.select { |c| Topic.serialized_attributes.include?(c.name) }
end
def in_time_zone(zone)
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index 312628a3e3..ffe16ffdfa 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -400,7 +400,7 @@ class NestedScopingTest < ActiveRecord::TestCase
Developer.send(:with_scope, :find => { :conditions => "salary < 100000" }) do
Developer.send(:with_scope, :find => { :offset => 1, :order => 'id asc' }) do
# Oracle adapter does not generated space after asc therefore trailing space removed from regex
- assert_sql(/ORDER BY id asc/) do
+ assert_sql(/ORDER BY\s+id asc/) do
assert_equal(poor_jamis, Developer.find(:first, :order => 'id asc'))
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index b7112d0e37..649fe79fd3 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -647,6 +647,17 @@ class RelationTest < ActiveRecord::TestCase
assert_equal Post.all, all_posts.all
end
+ def test_only
+ relation = Post.where(:author_id => 1).order('id ASC').limit(1)
+ assert_equal [posts(:welcome)], relation.all
+
+ author_posts = relation.only(:where)
+ assert_equal Post.where(:author_id => 1).all, author_posts.all
+
+ all_posts = relation.only(:limit)
+ assert_equal Post.limit(1).all.first, all_posts.first
+ end
+
def test_anonymous_extension
relation = Post.where(:author_id => 1).order('id ASC').extending do
def author
@@ -688,5 +699,11 @@ class RelationTest < ActiveRecord::TestCase
assert_equal 'zyke', car.name
end
+ def test_intersection_with_array
+ relation = Author.where(:name => "David")
+ rails_author = relation.first
+ assert_equal [rails_author], [rails_author] & relation
+ assert_equal [rails_author], relation & [rails_author]
+ end
end
diff --git a/activerecord/test/models/subject.rb b/activerecord/test/models/subject.rb
index 1b9d8107f8..d4b8b91de8 100644
--- a/activerecord/test/models/subject.rb
+++ b/activerecord/test/models/subject.rb
@@ -1,12 +1,16 @@
# used for OracleSynonymTest, see test/synonym_test_oracle.rb
#
class Subject < ActiveRecord::Base
+
+ # added initialization of author_email_address in the same way as in Topic class
+ # as otherwise synonym test was failing
+ after_initialize :set_email_address
+
protected
- # added initialization of author_email_address in the same way as in Topic class
- # as otherwise synonym test was failing
- def after_initialize
+ def set_email_address
if self.new_record?
self.author_email_address = 'test@test.com'
end
end
+
end
diff --git a/railties/guides/source/plugins.textile b/railties/guides/source/plugins.textile
index 2300786791..677a8a3667 100644
--- a/railties/guides/source/plugins.textile
+++ b/railties/guides/source/plugins.textile
@@ -33,20 +33,20 @@ h3. Setup
h4. Create the Basic Application
-The examples in this guide require that you have a working rails application. To create a simple rails app execute:
+The examples in this guide require that you have a working rails application. To create a simple one execute:
<shell>
gem install rails
-rails yaffle_guide
+rails new yaffle_guide
cd yaffle_guide
rails generate scaffold bird name:string
rake db:migrate
rails server
</shell>
-Then navigate to http://localhost:3000/birds. Make sure you have a functioning rails app before continuing.
+Then navigate to http://localhost:3000/birds. Make sure you have a functioning rails application before continuing.
-NOTE: The aforementioned instructions will work for sqlite3. For more detailed instructions on how to create a rails app for other databases see the API docs.
+NOTE: The aforementioned instructions will work for sqlite3. For more detailed instructions on how to create a rails application for other databases see the API docs.
h4. Generate the Plugin Skeleton
@@ -277,7 +277,7 @@ Now you are ready to test-drive your plugin!
h3. Extending Core Classes
-This section will explain how to add a method to String that will be available anywhere in your rails app.
+This section will explain how to add a method to String that will be available anywhere in your rails application.
In this example you will add a method to String named +to_squawk+. To begin, create a new test file with a few assertions:
@@ -622,7 +622,7 @@ create_table :woodpeckers, :force => true do |t|
end
</ruby>
-Now your test should be passing, and you should be able to use the Woodpecker model from within your rails app, and any changes made to it are reflected immediately when running in development mode.
+Now your test should be passing, and you should be able to use the Woodpecker model from within your rails application, and any changes made to it are reflected immediately when running in development mode.
h3. Controllers
@@ -734,7 +734,7 @@ h3. Routes
In a standard 'routes.rb' file you use routes like 'map.connect' or 'map.resources'. You can add your own custom routes from a plugin. This section will describe how to add a custom method called that can be called with 'map.yaffles'.
-Testing routes from plugins is slightly different from testing routes in a standard rails app. To begin, add a test like this:
+Testing routes from plugins is slightly different from testing routes in a standard rails application. To begin, add a test like this:
* *vendor/plugins/yaffle/test/routing_test.rb*
@@ -1385,7 +1385,7 @@ rake gem
sudo gem install pkg/yaffle-0.0.1.gem
</shell>
-To test this, create a new rails app, add +config.gem "yaffle"+ to +config/environment.rb+ and all of your plugin's functionality will be available to you.
+To test this, create a new rails application, add +config.gem "yaffle"+ to +config/environment.rb+ and all of your plugin's functionality will be available to you.
h3. RDoc Documentation
diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb
index da8ae17518..6970ea7b7a 100644
--- a/railties/test/application/initializers/frameworks_test.rb
+++ b/railties/test/application/initializers/frameworks_test.rb
@@ -65,6 +65,13 @@ module ApplicationTests
assert_equal ["notify"], Foo.action_methods
end
+ # AD
+ test "action_dispatch extensions are applied to ActionDispatch" do
+ add_to_config "config.action_dispatch.tld_length = 2"
+ require "#{app_path}/config/environment"
+ assert_equal 2, ActionDispatch::Http::URL.tld_length
+ end
+
# AS
test "if there's no config.active_support.bare, all of ActiveSupport is required" do
use_frameworks []