aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/CHANGELOG.md11
-rw-r--r--actionpack/CHANGELOG.md16
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb3
-rw-r--r--actionpack/lib/action_controller/test_case.rb5
-rw-r--r--actionpack/lib/action_view/helpers/form_tag_helper.rb15
-rw-r--r--actionpack/test/controller/base_test.rb5
-rw-r--r--actionpack/test/controller/request_forgery_protection_test.rb22
-rw-r--r--activemodel/CHANGELOG.md13
-rw-r--r--activemodel/lib/active_model/mass_assignment_security.rb18
-rw-r--r--activerecord/CHANGELOG.md29
-rw-r--r--activerecord/lib/active_record/associations.rb4
-rw-r--r--activerecord/lib/active_record/associations/has_many_through_association.rb4
-rw-r--r--activerecord/lib/active_record/associations/through_association.rb10
-rw-r--r--activerecord/lib/active_record/base.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb54
-rw-r--r--activerecord/lib/active_record/dynamic_finder_match.rb12
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_through_associations_test.rb24
-rw-r--r--activerecord/test/cases/connection_pool_test.rb70
-rw-r--r--activerecord/test/cases/dynamic_finder_match_test.rb8
-rw-r--r--activerecord/test/cases/finder_respond_to_test.rb10
-rw-r--r--activerecord/test/cases/finder_test.rb26
-rw-r--r--activerecord/test/cases/multiple_db_test.rb8
-rw-r--r--activerecord/test/cases/relations_test.rb12
-rw-r--r--activerecord/test/models/person.rb2
-rw-r--r--activerecord/test/models/post.rb2
-rw-r--r--activerecord/test/models/reader.rb9
-rw-r--r--activeresource/CHANGELOG.md10
-rw-r--r--activesupport/CHANGELOG.md9
-rw-r--r--railties/CHANGELOG.md34
-rw-r--r--railties/guides/source/active_record_querying.textile4
-rw-r--r--railties/guides/source/asset_pipeline.textile2
-rw-r--r--railties/guides/source/association_basics.textile2
-rw-r--r--railties/guides/source/configuring.textile2
-rw-r--r--railties/guides/source/routing.textile18
-rw-r--r--railties/lib/rails/engine.rb2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb5
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb21
-rw-r--r--railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb4
-rw-r--r--railties/test/generators/scaffold_controller_generator_test.rb25
-rw-r--r--railties/test/generators/scaffold_generator_test.rb30
42 files changed, 485 insertions, 84 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md
index 41a97823ed..a073018b42 100644
--- a/actionmailer/CHANGELOG.md
+++ b/actionmailer/CHANGELOG.md
@@ -1,3 +1,13 @@
+## Rails 3.2.3 (unreleased) ##
+
+* Upgrade mail version to 2.4.3 *ML*
+
+
+## Rails 3.2.2 (March 1, 2012) ##
+
+* No changes.
+
+
## Rails 3.2.1 (January 26, 2012) ##
* No changes.
@@ -88,6 +98,7 @@
* Mail does not have "quoted_body", "quoted_subject" etc. All of these are accessed via body.encoded, subject.encoded etc
* Every object in a Mail object returns an object, never a string. So Mail.body returns a Mail::Body class object, need to call #encoded or #decoded to get the string you want.
+
* Mail::Message#set_content_type does not exist, it is simply Mail::Message#content_type
* Every mail message gets a unique message_id unless you specify one, had to change all the tests that check for equality with expected.encoded == actual.encoded to first replace their message_ids with control values
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index d7552e74e1..465d19e50d 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,12 +1,26 @@
## Rails 3.2.3 (unreleased) ##
+* Do not include the authenticity token in forms where remote: true as ajax forms use the meta-tag value *DHH*
+
* Turn off verbose mode of rack-cache, we still have X-Rack-Cache to
check that info. Closes #5245. *Santiago Pastorino*
* Fix #5238, rendered_format is not set when template is not rendered. *Piotr Sarnacki*
+* Upgrade rack-cache to 1.2. *José Valim*
+
+* ActionController::SessionManagement is deprecated. *Santiago Pastorino*
+
+* Since the router holds references to many parts of the system like engines, controllers and the application itself, inspecting the route set can actually be really slow, therefore we default alias inspect to to_s. *José Valim*
+
+* Add a new line after the textarea opening tag. Closes #393 *Rafael Mendonça França*
+
+* Always pass a respond block from to responder. We should let the responder to decide what to do with the given overridden response block, and not short circuit it. *sikachu*
+
+* Fixes layout rendering regression from 3.2.2. *José Valim*
+
-## Rails 3.2.2 (unreleased) ##
+## Rails 3.2.2 (March 1, 2012) ##
* Format lookup for partials is derived from the format in which the template is being rendered. Closes #5025 part 2 *Santiago Pastorino*
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index cb3b793418..c482062592 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -237,8 +237,7 @@ module AbstractController
#
# If the specified layout is a:
# String:: the String is the template name
- # Symbol:: call the method specified by the symbol, which will return
- # the template name
+ # Symbol:: call the method specified by the symbol, which will return the template name
# false:: There is no layout
# true:: raise an ArgumentError
# nil:: Force default layout behavior with inheritance
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 7470897659..c985a8ca10 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -483,11 +483,6 @@ module ActionController
end
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
-
included do
include ActionController::TemplateAssertions
include ActionDispatch::Assertions
diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb
index e3ad96ec1b..4ce878f26a 100644
--- a/actionpack/lib/action_view/helpers/form_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb
@@ -27,7 +27,9 @@ module ActionView
# is added to simulate the verb over post.
# * <tt>:authenticity_token</tt> - Authenticity token to use in the form. Use only if you need to
# pass custom authenticity token string, or to not add authenticity_token field at all
- # (by passing <tt>false</tt>).
+ # (by passing <tt>false</tt>). If this is a remote form, the authenticity_token will by default
+ # not be included as the ajax handler will get it from the meta-tag (but you can force it to be
+ # rendered anyway in that case by passing <tt>true</tt>).
# * A list of parameters to feed to the URL the form will be posted to.
# * <tt>:remote</tt> - If set to true, will allow the Unobtrusive JavaScript drivers to control the
# submit behavior. By default this behavior is an ajax submit.
@@ -609,8 +611,17 @@ module ActionView
# responsibility of the caller to escape all the values.
html_options["action"] = url_for(url_for_options)
html_options["accept-charset"] = "UTF-8"
+
html_options["data-remote"] = true if html_options.delete("remote")
- html_options["authenticity_token"] = html_options.delete("authenticity_token") if html_options.has_key?("authenticity_token")
+
+ if html_options["data-remote"] && html_options["authenticity_token"] == true
+ # Include the default authenticity_token, which is only generated when its set to nil,
+ # but we needed the true value to override the default of no authenticity_token on data-remote.
+ html_options["authenticity_token"] = nil
+ elsif html_options["data-remote"]
+ # The authenticity token is taken from the meta tag in this case
+ html_options["authenticity_token"] = false
+ end
end
end
diff --git a/actionpack/test/controller/base_test.rb b/actionpack/test/controller/base_test.rb
index 6f76ab9596..145ef12b94 100644
--- a/actionpack/test/controller/base_test.rb
+++ b/actionpack/test/controller/base_test.rb
@@ -153,8 +153,6 @@ class PerformActionTest < ActionController::TestCase
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
@request.host = "www.nextangle.com"
-
- rescue_action_in_public!
end
def test_process_should_be_precise
@@ -206,7 +204,6 @@ class UrlOptionsTest < ActionController::TestCase
def setup
super
@request.host = 'www.example.com'
- rescue_action_in_public!
end
##
@@ -306,7 +303,6 @@ class DefaultUrlOptionsTest < ActionController::TestCase
def setup
super
@request.host = 'www.example.com'
- rescue_action_in_public!
end
def test_default_url_options_override
@@ -357,7 +353,6 @@ class EmptyUrlOptionsTest < ActionController::TestCase
def setup
super
@request.host = 'www.example.com'
- rescue_action_in_public!
end
def test_ensure_url_for_works_as_expected_when_called_with_no_options_if_default_url_options_is_not_set
diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb
index fd5a41a0bb..37b9de350b 100644
--- a/actionpack/test/controller/request_forgery_protection_test.rb
+++ b/actionpack/test/controller/request_forgery_protection_test.rb
@@ -37,6 +37,14 @@ module RequestForgeryProtectionActions
render :inline => "<%= form_for(:some_resource, :authenticity_token => false ) {} %>"
end
+ def form_for_remote
+ render :inline => "<%= form_for(:some_resource, :remote => true ) {} %>"
+ end
+
+ def form_for_remote_with_token
+ render :inline => "<%= form_for(:some_resource, :remote => true, :authenticity_token => true ) {} %>"
+ end
+
def rescue_action(e) raise e end
end
@@ -103,6 +111,20 @@ module RequestForgeryProtectionTests
assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token
end
+ def test_should_render_form_without_token_tag_if_remote
+ assert_not_blocked do
+ get :form_for_remote
+ end
+ assert_no_match /authenticity_token/, response.body
+ end
+
+ def test_should_render_form_with_token_tag_if_remote_and_authenticity_token_requested
+ assert_not_blocked do
+ get :form_for_remote_with_token
+ end
+ assert_select 'form>div>input[name=?][value=?]', 'custom_authenticity_token', @token
+ end
+
def test_should_allow_get
assert_not_blocked { get :index }
end
diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md
index 52d488a4ce..d3ea4c85dc 100644
--- a/activemodel/CHANGELOG.md
+++ b/activemodel/CHANGELOG.md
@@ -1,3 +1,13 @@
+## Rails 3.2.3 (unreleased) ##
+
+* No changes.
+
+
+## Rails 3.2.2 (March 1, 2012) ##
+
+* No changes.
+
+
## Rails 3.2.1 (January 26, 2012) ##
* No changes.
@@ -16,6 +26,7 @@
* Provide mass_assignment_sanitizer as an easy API to replace the sanitizer behavior. Also support both :logger (default) and :strict sanitizer behavior *Bogdan Gusiev*
+
## Rails 3.1.0 (August 30, 2011) ##
* Alternate I18n namespace lookup is no longer supported.
@@ -44,7 +55,7 @@
* No changes.
-* Rails 3.0.6 (April 5, 2011)
+## Rails 3.0.6 (April 5, 2011) ##
* Fix when database column name has some symbolic characters (e.g. Oracle CASE# VARCHAR2(20)) #5818 #6850 *Robert Pankowecki, Santiago Pastorino*
diff --git a/activemodel/lib/active_model/mass_assignment_security.rb b/activemodel/lib/active_model/mass_assignment_security.rb
index e1fb1e3231..f0041f5fee 100644
--- a/activemodel/lib/active_model/mass_assignment_security.rb
+++ b/activemodel/lib/active_model/mass_assignment_security.rb
@@ -83,7 +83,7 @@ module ActiveModel
# end
# end
#
- # When using the :default role :
+ # When using the :default role:
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
@@ -94,7 +94,7 @@ module ActiveModel
# customer.credit_rating = "Average"
# customer.credit_rating # => "Average"
#
- # And using the :admin role :
+ # And using the :admin role:
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
@@ -105,8 +105,9 @@ module ActiveModel
# To start from an all-closed default and enable attributes as needed,
# have a look at +attr_accessible+.
#
- # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_protected+
- # to sanitize attributes won't provide sufficient protection.
+ # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of
+ # +attr_protected+ to sanitize attributes provides basically the same
+ # functionality, but it makes a bit tricky to deal with nested attributes.
def attr_protected(*args)
options = args.extract_options!
role = options[:as] || :default
@@ -150,7 +151,7 @@ module ActiveModel
# end
# end
#
- # When using the :default role :
+ # When using the :default role:
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
@@ -160,15 +161,16 @@ module ActiveModel
# customer.credit_rating = "Average"
# customer.credit_rating # => "Average"
#
- # And using the :admin role :
+ # And using the :admin role:
#
# customer = Customer.new
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
# customer.name # => "David"
# customer.credit_rating # => "Excellent"
#
- # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of +attr_accessible+
- # to sanitize attributes won't provide sufficient protection.
+ # Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of
+ # +attr_accessible+ to sanitize attributes provides basically the same
+ # functionality, but it makes a bit tricky to deal with nested attributes.
def attr_accessible(*args)
options = args.extract_options!
role = options[:as] || :default
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 3cf2f6a4e9..16c525d211 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,25 @@
+## Rails 3.2.3 (unreleased) ##
+
+* Added find_or_create_by_{attribute}! dynamic method. *Andrew White*
+
+* Whitelist all attribute assignment by default. Change the default for newly generated applications to whitelist all attribute assignment. Also update the generated model classes so users are reminded of the importance of attr_accessible. *NZKoz*
+
+* Update ActiveRecord::AttributeMethods#attribute_present? to return false for empty strings. *Jacobkg*
+
+* Fix associations when using per class databases. *larskanis*
+
+* Revert setting NOT NULL constraints in add_timestamps *fxn*
+
+* Fix mysql to use proper text types. Fixes #3931. *kennyj*
+
+* Fix #5069 - Protect foreign key from mass assignment through association builder. *byroot*
+
+
+## Rails 3.2.2 (March 1, 2012) ##
+
+* No changes.
+
+
## Rails 3.2.1 (January 26, 2012) ##
* The threshold for auto EXPLAIN is ignored if there's no logger. *fxn*
@@ -192,7 +214,8 @@
*Brian Durand*
-## Rails 3.1.3 (unreleased) ##
+
+## Rails 3.1.3 (November 20, 2011) ##
* Perf fix: If we're deleting all records in an association, don't add a IN(..) clause
to the query. *GH 3672*
@@ -205,7 +228,8 @@
*Christos Zisopoulos and Kenny J*
-## Rails 3.1.2 (unreleased) ##
+
+## Rails 3.1.2 (November 18, 2011) ##
* Fix bug with PostgreSQLAdapter#indexes. When the search path has multiple schemas, spaces
were not being stripped from the schema names after the first.
@@ -252,6 +276,7 @@
*Kenny J*
+
## Rails 3.1.1 (October 7, 2011) ##
* Add deprecation for the preload_associations method. Fixes #3022.
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 0efa111d12..8ebb27b682 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1513,8 +1513,8 @@ module ActiveRecord
# * <tt>Developer#projects.size</tt>
# * <tt>Developer#projects.find(id)</tt>
# * <tt>Developer#projects.exists?(...)</tt>
- # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("project_id" => id)</tt>)
- # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("project_id" => id); c.save; c</tt>)
+ # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
+ # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
# The declaration may include an options hash to specialize the behavior of the association.
#
# === Options
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 9657cb081d..53d49fef2e 100644
--- a/activerecord/lib/active_record/associations/has_many_through_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_through_association.rb
@@ -73,7 +73,9 @@ module ActiveRecord
# association
def build_through_record(record)
@through_records[record.object_id] ||= begin
- through_record = through_association.build(construct_join_attributes(record))
+ ensure_mutable
+
+ through_record = through_association.build
through_record.send("#{source_reflection.name}=", record)
through_record
end
diff --git a/activerecord/lib/active_record/associations/through_association.rb b/activerecord/lib/active_record/associations/through_association.rb
index f95e5337c2..fd0e90aaf0 100644
--- a/activerecord/lib/active_record/associations/through_association.rb
+++ b/activerecord/lib/active_record/associations/through_association.rb
@@ -37,9 +37,7 @@ module ActiveRecord
# situation it is more natural for the user to just create or modify their join records
# directly as required.
def construct_join_attributes(*records)
- if source_reflection.macro != :belongs_to
- raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
- end
+ ensure_mutable
join_attributes = {
source_reflection.foreign_key =>
@@ -73,6 +71,12 @@ module ActiveRecord
!owner[through_reflection.foreign_key].nil?
end
+ def ensure_mutable
+ if source_reflection.macro != :belongs_to
+ raise HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(owner, reflection)
+ end
+ end
+
def ensure_not_nested
if reflection.nested?
raise HasManyThroughNestedAssociationsAreReadonly.new(owner, reflection)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 9c4d4cb274..9746efc7d1 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -208,6 +208,9 @@ module ActiveRecord #:nodoc:
# # Now 'Bob' exist and is an 'admin'
# User.find_or_create_by_name('Bob', :age => 40) { |u| u.admin = true }
#
+ # Adding an exclamation point (!) on to the end of <tt>find_or_create_by_</tt> will
+ # raise an <tt>ActiveRecord::RecordInvalid</tt> error if the new record is invalid.
+ #
# Use the <tt>find_or_initialize_by_</tt> finder if you want to return a new record without
# saving it first. Protected attributes won't be set unless they are given in a block.
#
@@ -439,7 +442,7 @@ module ActiveRecord #:nodoc:
if self == ActiveRecord::Base
ActiveRecord::Base
else
- connection_handler.connection_pools[name] ? self : superclass.arel_engine
+ connection_handler.retrieve_connection_pool(self) ? self : superclass.arel_engine
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
index 698da34d26..3af285c7c8 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb
@@ -95,10 +95,11 @@ module ActiveRecord
@reserved_connections[current_connection_id] ||= checkout
end
- # Check to see if there is an active connection in this connection
- # pool.
+ # Is there an open connection that is being used for the current thread?
def active_connection?
- active_connections.any?
+ @reserved_connections.fetch(current_connection_id) {
+ return false
+ }.in_use?
end
# Signal that the thread is finished with the current connection.
@@ -225,8 +226,9 @@ connection. For example: ActiveRecord::Base.connection.close
# - ConnectionTimeoutError: no connection can be obtained from the pool
# within the timeout period.
def checkout
- # Checkout an available connection
synchronize do
+ waited_time = 0
+
loop do
conn = @connections.find { |c| c.lease }
@@ -242,17 +244,25 @@ connection. For example: ActiveRecord::Base.connection.close
return conn
end
- @queue.wait(@timeout)
+ if waited_time >= @timeout
+ raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout} (waited #{waited_time} seconds). The max pool size is currently #{@size}; consider increasing it."
+ end
- if(active_connections.size < @connections.size)
- next
- else
+ # Sometimes our wait can end because a connection is available,
+ # but another thread can snatch it up first. If timeout hasn't
+ # passed but no connection is avail, looks like that happened --
+ # loop and wait again, for the time remaining on our timeout.
+ before_wait = Time.now
+ @queue.wait( [@timeout - waited_time, 0].max )
+ waited_time += (Time.now - before_wait)
+
+ # Will go away in Rails 4, when we don't clean up
+ # after leaked connections automatically anymore. Right now, clean
+ # up after we've returned from a 'wait' if it looks like it's
+ # needed, then loop and try again.
+ if(active_connections.size >= @connections.size)
clear_stale_cached_connections!
- if @size == active_connections.size
- raise ConnectionTimeoutError, "could not obtain a database connection#{" within #{@timeout} seconds" if @timeout}. The max pool size is currently #{@size}; consider increasing it."
- end
end
-
end
end
end
@@ -268,11 +278,27 @@ connection. For example: ActiveRecord::Base.connection.close
conn.expire
@queue.signal
end
+
+ release conn
end
end
private
+ def release(conn)
+ thread_id = nil
+
+ if @reserved_connections[current_connection_id] == conn
+ thread_id = current_connection_id
+ else
+ thread_id = @reserved_connections.keys.find { |k|
+ @reserved_connections[k] == conn
+ }
+ end
+
+ @reserved_connections.delete thread_id if thread_id
+ end
+
def new_connection
ActiveRecord::Base.send(spec.adapter_method, spec.config)
end
@@ -344,9 +370,7 @@ connection. For example: ActiveRecord::Base.connection.close
connection_pools.values.any? { |pool| pool.active_connection? }
end
- # Returns any connections in use by the current thread back to the pool,
- # and also returns connections to the pool cached by threads that are no
- # longer alive.
+ # Returns any connections in use by the current thread back to the pool.
def clear_active_connections!
@connection_pools.each_value {|pool| pool.release_connection }
end
diff --git a/activerecord/lib/active_record/dynamic_finder_match.rb b/activerecord/lib/active_record/dynamic_finder_match.rb
index b309df9b1b..80b17a27df 100644
--- a/activerecord/lib/active_record/dynamic_finder_match.rb
+++ b/activerecord/lib/active_record/dynamic_finder_match.rb
@@ -18,6 +18,10 @@ module ActiveRecord
when /^find_by_([_a-zA-Z]\w*)\!$/
bang = true
names = $1
+ when /^find_or_create_by_([_a-zA-Z]\w*)\!$/
+ bang = true
+ instantiator = :create
+ names = $1
when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
instantiator = $1 == 'initialize' ? :new : :create
names = $2
@@ -52,5 +56,13 @@ module ActiveRecord
def bang?
@bang
end
+
+ def save_record?
+ @instantiator == :create
+ end
+
+ def save_method
+ bang? ? :save! : :save
+ end
end
end
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 0305e561c8..9a34927857 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -290,7 +290,7 @@ module ActiveRecord
r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
end
yield(record) if block_given?
- record.save if match.instantiator == :create
+ record.send(match.save_method) if match.save_record?
end
record
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index fab2cd77f0..f5bfa3603a 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -270,7 +270,7 @@ module ActiveRecord
arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?
arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
- arel.skip(@offset_value) if @offset_value
+ arel.skip(@offset_value.to_i) if @offset_value
arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty?
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 6836a2b4d0..4489c3e638 100644
--- a/activerecord/test/cases/associations/has_many_through_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb
@@ -44,17 +44,33 @@ class HasManyThroughAssociationsTest < ActiveRecord::TestCase
end
def test_associate_existing
- posts(:thinking); people(:david) # Warm cache
+ post = posts(:thinking)
+ person = people(:david)
assert_queries(1) do
- posts(:thinking).people << people(:david)
+ post.people << person
end
assert_queries(1) do
- assert posts(:thinking).people.include?(people(:david))
+ assert post.people.include?(person)
end
- assert posts(:thinking).reload.people(true).include?(people(:david))
+ assert post.reload.people(true).include?(person)
+ end
+
+ def test_associate_existing_with_strict_mass_assignment_sanitizer
+ SecureReader.mass_assignment_sanitizer = :strict
+
+ SecureReader.new
+
+ post = posts(:thinking)
+ person = people(:david)
+
+ assert_queries(1) do
+ post.secure_people << person
+ end
+ ensure
+ SecureReader.mass_assignment_sanitizer = :logger
end
def test_associate_existing_record_twice_should_add_to_target_twice
diff --git a/activerecord/test/cases/connection_pool_test.rb b/activerecord/test/cases/connection_pool_test.rb
index d170a13b23..5cecfa90e7 100644
--- a/activerecord/test/cases/connection_pool_test.rb
+++ b/activerecord/test/cases/connection_pool_test.rb
@@ -3,7 +3,11 @@ require "cases/helper"
module ActiveRecord
module ConnectionAdapters
class ConnectionPoolTest < ActiveRecord::TestCase
+ attr_reader :pool
+
def setup
+ super
+
# Keep a duplicate pool so we do not bother others
@pool = ConnectionPool.new ActiveRecord::Base.connection_pool.spec
@@ -18,6 +22,72 @@ module ActiveRecord
end
end
+ def teardown
+ super
+ @pool.disconnect!
+ end
+
+ def active_connections(pool)
+ pool.connections.find_all(&:in_use?)
+ end
+
+ def test_checkout_after_close
+ connection = pool.connection
+ assert connection.in_use?
+
+ connection.close
+ assert !connection.in_use?
+
+ assert pool.connection.in_use?
+ end
+
+ def test_released_connection_moves_between_threads
+ thread_conn = nil
+
+ Thread.new {
+ pool.with_connection do |conn|
+ thread_conn = conn
+ end
+ }.join
+
+ assert thread_conn
+
+ Thread.new {
+ pool.with_connection do |conn|
+ assert_equal thread_conn, conn
+ end
+ }.join
+ end
+
+ def test_with_connection
+ assert_equal 0, active_connections(pool).size
+
+ main_thread = pool.connection
+ assert_equal 1, active_connections(pool).size
+
+ Thread.new {
+ pool.with_connection do |conn|
+ assert conn
+ assert_equal 2, active_connections(pool).size
+ end
+ assert_equal 1, active_connections(pool).size
+ }.join
+
+ main_thread.close
+ assert_equal 0, active_connections(pool).size
+ end
+
+ def test_active_connection_in_use
+ assert !pool.active_connection?
+ main_thread = pool.connection
+
+ assert pool.active_connection?
+
+ main_thread.close
+
+ assert !pool.active_connection?
+ end
+
def test_active_connection?
assert !@pool.active_connection?
assert @pool.connection
diff --git a/activerecord/test/cases/dynamic_finder_match_test.rb b/activerecord/test/cases/dynamic_finder_match_test.rb
index e576870317..db619faa83 100644
--- a/activerecord/test/cases/dynamic_finder_match_test.rb
+++ b/activerecord/test/cases/dynamic_finder_match_test.rb
@@ -83,6 +83,14 @@ module ActiveRecord
assert_equal :create, m.instantiator
end
+ def test_find_or_create!
+ m = DynamicFinderMatch.match(:find_or_create_by_foo!)
+ assert_equal :first, m.finder
+ assert m.bang?, 'should be banging'
+ assert_equal %w{ foo }, m.attribute_names
+ assert_equal :create, m.instantiator
+ end
+
def test_find_or_initialize
m = DynamicFinderMatch.match(:find_or_initialize_by_foo)
assert_equal :first, m.finder
diff --git a/activerecord/test/cases/finder_respond_to_test.rb b/activerecord/test/cases/finder_respond_to_test.rb
index 235805a67c..810c1500cc 100644
--- a/activerecord/test/cases/finder_respond_to_test.rb
+++ b/activerecord/test/cases/finder_respond_to_test.rb
@@ -56,6 +56,16 @@ class FinderRespondToTest < ActiveRecord::TestCase
assert_respond_to Topic, :find_or_create_by_title_and_author_name
end
+ def test_should_respond_to_find_or_create_from_one_attribute_bang
+ ensure_topic_method_is_not_cached(:find_or_create_by_title!)
+ assert_respond_to Topic, :find_or_create_by_title!
+ end
+
+ def test_should_respond_to_find_or_create_from_two_attributes_bang
+ ensure_topic_method_is_not_cached(:find_or_create_by_title_and_author_name!)
+ assert_respond_to Topic, :find_or_create_by_title_and_author_name!
+ end
+
def test_should_not_respond_to_find_by_one_missing_attribute
assert !Topic.respond_to?(:find_by_undertitle)
end
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index 5a67fcdc0a..4705252c05 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -862,6 +862,28 @@ class FinderTest < ActiveRecord::TestCase
assert another.persisted?
end
+ def test_find_or_create_from_one_attribute_bang
+ number_of_companies = Company.count
+ assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name!("") }
+ assert_equal number_of_companies, Company.count
+ sig38 = Company.find_or_create_by_name!("38signals")
+ assert_equal number_of_companies + 1, Company.count
+ assert_equal sig38, Company.find_or_create_by_name!("38signals")
+ assert sig38.persisted?
+ end
+
+ def test_find_or_create_from_two_attributes_bang
+ number_of_companies = Company.count
+ assert_raises(ActiveRecord::RecordInvalid) { Company.find_or_create_by_name_and_firm_id!("", 17) }
+ assert_equal number_of_companies, Company.count
+ sig38 = Company.find_or_create_by_name_and_firm_id!("38signals", 17)
+ assert_equal number_of_companies + 1, Company.count
+ assert_equal sig38, Company.find_or_create_by_name_and_firm_id!("38signals", 17)
+ assert sig38.persisted?
+ assert_equal "38signals", sig38.name
+ assert_equal 17, sig38.firm_id
+ end
+
def test_find_or_create_from_two_attributes_with_one_being_an_aggregate
number_of_customers = Customer.count
created_customer = Customer.find_or_create_by_balance_and_name(Money.new(123), "Elizabeth")
@@ -1182,6 +1204,10 @@ class FinderTest < ActiveRecord::TestCase
end
end
+ def test_finder_with_offset_string
+ assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.find(:all, :offset => "3") }
+ end
+
protected
def bind(statement, *vars)
if vars.first.is_a?(Hash)
diff --git a/activerecord/test/cases/multiple_db_test.rb b/activerecord/test/cases/multiple_db_test.rb
index e704322b5d..b31d971309 100644
--- a/activerecord/test/cases/multiple_db_test.rb
+++ b/activerecord/test/cases/multiple_db_test.rb
@@ -85,6 +85,12 @@ class MultipleDbTest < ActiveRecord::TestCase
end
def test_arel_table_engines
- assert_equal Entrant.arel_engine, Bird.arel_engine
+ assert_not_equal Entrant.arel_engine, Bird.arel_engine
+ assert_not_equal Entrant.arel_engine, Course.arel_engine
+ end
+
+ def test_connection
+ assert_equal Entrant.arel_engine.connection, Bird.arel_engine.connection
+ assert_not_equal Entrant.arel_engine.connection, Course.arel_engine.connection
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index bf1eb6386a..5e0caf5fce 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -449,6 +449,18 @@ class RelationTest < ActiveRecord::TestCase
assert_equal authors(:david), authors.find_or_create_by_name(:name => 'David')
end
+ def test_dynamic_find_or_create_by_attributes_bang
+ authors = Author.scoped
+
+ assert_raises(ActiveRecord::RecordInvalid) { authors.find_or_create_by_name!('') }
+
+ lifo = authors.find_or_create_by_name!('Lifo')
+ assert_equal "Lifo", lifo.name
+ assert lifo.persisted?
+
+ assert_equal authors(:david), authors.find_or_create_by_name!(:name => 'David')
+ end
+
def test_find_id
authors = Author.scoped
diff --git a/activerecord/test/models/person.rb b/activerecord/test/models/person.rb
index 36eb08d02f..dcfea3170c 100644
--- a/activerecord/test/models/person.rb
+++ b/activerecord/test/models/person.rb
@@ -1,8 +1,10 @@
class Person < ActiveRecord::Base
has_many :readers
+ has_many :secure_readers
has_one :reader
has_many :posts, :through => :readers
+ has_many :secure_posts, :through => :secure_readers
has_many :posts_with_no_comments, :through => :readers, :source => :post, :include => :comments, :conditions => 'comments.id is null'
has_many :references
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 1cab78d8c7..0fc22ac6a3 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -115,8 +115,10 @@ class Post < ActiveRecord::Base
has_many :named_categories, :through => :standard_categorizations
has_many :readers
+ has_many :secure_readers
has_many :readers_with_person, :include => :person, :class_name => "Reader"
has_many :people, :through => :readers
+ has_many :secure_people, :through => :secure_readers
has_many :single_people, :through => :readers
has_many :people_with_callbacks, :source=>:person, :through => :readers,
:before_add => lambda {|owner, reader| log(:added, :before, reader.first_name) },
diff --git a/activerecord/test/models/reader.rb b/activerecord/test/models/reader.rb
index 0207a2bd92..59005ac604 100644
--- a/activerecord/test/models/reader.rb
+++ b/activerecord/test/models/reader.rb
@@ -3,3 +3,12 @@ class Reader < ActiveRecord::Base
belongs_to :person, :inverse_of => :readers
belongs_to :single_person, :class_name => 'Person', :foreign_key => :person_id, :inverse_of => :reader
end
+
+class SecureReader < ActiveRecord::Base
+ self.table_name = "readers"
+
+ belongs_to :secure_post, :class_name => "Post", :foreign_key => "post_id"
+ belongs_to :secure_person, :inverse_of => :secure_readers, :class_name => "Person", :foreign_key => "person_id"
+
+ attr_accessible nil
+end
diff --git a/activeresource/CHANGELOG.md b/activeresource/CHANGELOG.md
index 53afc56ee0..ef957c68ed 100644
--- a/activeresource/CHANGELOG.md
+++ b/activeresource/CHANGELOG.md
@@ -1,3 +1,13 @@
+## Rails 3.2.3 (unreleased) ##
+
+* No changes.
+
+
+## Rails 3.2.2 (March 1, 2012) ##
+
+* No changes.
+
+
## Rails 3.2.1 (January 26, 2012) ##
* Documentation fixes.
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index bdae96e7f2..f35c147e60 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,11 @@
+## Rails 3.2.3 (unreleased) ##
+
+* No changes.
+
+## Rails 3.2.2 (March 1, 2012) ##
+
+* No changes.
+
## Rails 3.2.1 (January 26, 2012) ##
* Documentation fixes and improvements.
@@ -81,6 +89,7 @@
* ActiveSupport::BufferedLogger#flush is deprecated. Set sync on your
filehandle, or tune your filesystem.
+
## Rails 3.1.0 (August 30, 2011) ##
* ActiveSupport::Dependencies#load and ActiveSupport::Dependencies#require now
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 4ac2f942e1..b02e952671 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -1,3 +1,13 @@
+## Rails 3.2.3 (unreleased) ##
+
+* No changes.
+
+
+## Rails 3.2.2 (March 1, 2012) ##
+
+* No changes.
+
+
## Rails 3.2.1 (January 26, 2012) ##
* Documentation fixes.
@@ -46,7 +56,19 @@
* Remove old 'config.paths.app.controller' API in favor of 'config.paths["app/controller"]' API *Guillermo Iguaran*
-* Rails 3.1.1
+## Rails 3.1.2 (November 18, 2011) ##
+
+* Engines: don't blow up if db/seeds.rb is missing.
+
+ *Jeremy Kemper*
+
+* `rails new foo --skip-test-unit` should not add the `:test` task to the rake default task.
+ *GH 2564*
+
+ *José Valim*
+
+
+## Rails 3.1.1 (October 7, 2011) ##
* Add jquery-rails to Gemfile of plugins, test/dummy app needs it. Closes #3091. *Santiago Pastorino*
@@ -59,16 +81,6 @@
Plugins developers need to special case their initializers that are
meant to be run in the assets group by adding :group => :assets.
-## Rails 3.1.2 (unreleased) ##
-
-* Engines: don't blow up if db/seeds.rb is missing.
-
- *Jeremy Kemper*
-
-* `rails new foo --skip-test-unit` should not add the `:test` task to the rake default task.
- *GH 2564*
-
- *José Valim*
## Rails 3.1.0 (August 30, 2011) ##
diff --git a/railties/guides/source/active_record_querying.textile b/railties/guides/source/active_record_querying.textile
index e46410ce59..47392c1851 100644
--- a/railties/guides/source/active_record_querying.textile
+++ b/railties/guides/source/active_record_querying.textile
@@ -94,7 +94,7 @@ client = Client.find(10)
The SQL equivalent of the above is:
<sql>
-SELECT * FROM clients WHERE (clients.id = 10)
+SELECT * FROM clients WHERE (clients.id = 10) LIMIT 1
</sql>
<tt>Model.find(primary_key)</tt> will raise an +ActiveRecord::RecordNotFound+ exception if no matching record is found.
@@ -1109,6 +1109,8 @@ Client.where(:first_name => 'Andy').first_or_create!(:locked => false)
# => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
</ruby>
+As with +first_or_create+ there is a +find_or_create_by!+ method but the +first_or_create!+ method is preferred for clarity.
+
h4. +first_or_initialize+
The +first_or_initialize+ method will work just like +first_or_create+ but it will not call +create+ but +new+. This means that a new model instance will be created in memory but won't be saved to the database. Continuing with the +first_or_create+ example, we now want the client named 'Nick':
diff --git a/railties/guides/source/asset_pipeline.textile b/railties/guides/source/asset_pipeline.textile
index ff2bd08602..08adedb23f 100644
--- a/railties/guides/source/asset_pipeline.textile
+++ b/railties/guides/source/asset_pipeline.textile
@@ -128,7 +128,7 @@ For example, these files:
<plain>
app/assets/javascripts/home.js
lib/assets/javascripts/moovinator.js
-vendor/assets/javascript/slider.js
+vendor/assets/javascripts/slider.js
</plain>
would be referenced in a manifest like this:
diff --git a/railties/guides/source/association_basics.textile b/railties/guides/source/association_basics.textile
index 9e22fc4588..6f0d985cac 100644
--- a/railties/guides/source/association_basics.textile
+++ b/railties/guides/source/association_basics.textile
@@ -1319,7 +1319,7 @@ If you need to evaluate conditions dynamically at runtime, use a proc:
<ruby>
class Customer < ActiveRecord::Base
has_many :latest_orders, :class_name => "Order",
- :conditions => proc { ["orders.created_at > ?, 10.hours.ago] }
+ :conditions => proc { ["orders.created_at > ?", 10.hours.ago] }
end
</ruby>
diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile
index 98582946b4..11dbba0e3d 100644
--- a/railties/guides/source/configuring.textile
+++ b/railties/guides/source/configuring.textile
@@ -481,7 +481,7 @@ Rails has 5 initialization events which can be hooked into (listed in the order
* +after_initialize+: Run directly after the initialization of the application, but before the application initializers are run.
-To define an event for these hooks, use the block syntax within a +Rails::Aplication+, +Rails::Railtie+ or +Rails::Engine+ subclass:
+To define an event for these hooks, use the block syntax within a +Rails::Application+, +Rails::Railtie+ or +Rails::Engine+ subclass:
<ruby>
module YourApp
diff --git a/railties/guides/source/routing.textile b/railties/guides/source/routing.textile
index 0823fb14e3..851d1bef69 100644
--- a/railties/guides/source/routing.textile
+++ b/railties/guides/source/routing.textile
@@ -235,14 +235,14 @@ end
In addition to the routes for magazines, this declaration will also route ads to an +AdsController+. The ad URLs require a magazine:
-|_.HTTP Verb |_.Path |_.action |_.used for |
-|GET |/magazines/:id/ads |index |display a list of all ads for a specific magazine |
-|GET |/magazines/:id/ads/new |new |return an HTML form for creating a new ad belonging to a specific magazine |
-|POST |/magazines/:id/ads |create |create a new ad belonging to a specific magazine |
-|GET |/magazines/:id/ads/:id |show |display a specific ad belonging to a specific magazine |
-|GET |/magazines/:id/ads/:id/edit |edit |return an HTML form for editing an ad belonging to a specific magazine |
-|PUT |/magazines/:id/ads/:id |update |update a specific ad belonging to a specific magazine |
-|DELETE |/magazines/:id/ads/:id |destroy |delete a specific ad belonging to a specific magazine |
+|_.HTTP Verb |_.Path |_.action |_.used for |
+|GET |/magazines/:magazine_id/ads |index |display a list of all ads for a specific magazine |
+|GET |/magazines/:magazine_id/ads/new |new |return an HTML form for creating a new ad belonging to a specific magazine |
+|POST |/magazines/:magazine_id/ads |create |create a new ad belonging to a specific magazine |
+|GET |/magazines/:magazine_id/ads/:id |show |display a specific ad belonging to a specific magazine |
+|GET |/magazines/:magazine_id/ads/:id/edit |edit |return an HTML form for editing an ad belonging to a specific magazine |
+|PUT |/magazines/:magazine_id/ads/:id |update |update a specific ad belonging to a specific magazine |
+|DELETE |/magazines/:magazine_id/ads/:id |destroy |delete a specific ad belonging to a specific magazine |
This will also create routing helpers such as +magazine_ads_url+ and +edit_magazine_ad_path+. These helpers take an instance of Magazine as the first parameter (+magazine_ads_url(@magazine)+).
@@ -385,7 +385,7 @@ match ':controller/:action/:id/:user_id'
An incoming path of +/photos/show/1/2+ will be dispatched to the +show+ action of the +PhotosController+. +params[:id]+ will be +"1"+, and +params[:user_id]+ will be +"2"+.
-NOTE: You can't use +namespace+ or +:module+ with a +:controller+ path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g:
+NOTE: You can't use +:namespace+ or +:module+ with a +:controller+ path segment. If you need to do this then use a constraint on :controller that matches the namespace you require. e.g:
<ruby>
match ':controller(/:action(/:id))', :controller => /admin\/[^\/]+/
diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb
index 20321a502d..993dfe43ee 100644
--- a/railties/lib/rails/engine.rb
+++ b/railties/lib/rails/engine.rb
@@ -245,7 +245,7 @@ module Rails
#
# Additionally, an isolated engine will set its name according to namespace, so
# MyEngine::Engine.engine_name will be "my_engine". It will also set MyEngine.table_name_prefix
- # to "my_engine_", changing the MyEngine::Article model to use the my_engine_article table.
+ # to "my_engine_", changing the MyEngine::Article model to use the my_engine_articles table.
#
# == Using Engine's routes outside Engine
#
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
index dcd3b276e3..1e26a313cd 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/test/test_helper.rb
@@ -8,3 +8,8 @@ Rails.backtrace_cleaner.remove_silencers!
# Load support files
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
+
+# Load fixtures from the engine
+if ActiveSupport::TestCase.method_defined?(:fixture_path=)
+ ActiveSupport::TestCase.fixture_path = File.expand_path("../fixtures", __FILE__)
+end
diff --git a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
index f7e907a017..8e796aada9 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/scaffold_generator.rb
@@ -8,10 +8,31 @@ module TestUnit
check_class_collision :suffix => "ControllerTest"
+ argument :attributes, :type => :array, :default => [], :banner => "field:type field:type"
+
def create_test_files
template 'functional_test.rb',
File.join('test/functional', controller_class_path, "#{controller_file_name}_controller_test.rb")
end
+
+ private
+
+ def resource_attributes
+ key_value singular_table_name, "{ #{attributes_hash} }"
+ end
+
+ def attributes_hash
+ return if accessible_attributes.empty?
+
+ accessible_attributes.map do |a|
+ name = a.name
+ key_value name, "@#{singular_table_name}.#{name}"
+ end.sort.join(', ')
+ end
+
+ def accessible_attributes
+ attributes.reject(&:reference?)
+ end
end
end
end
diff --git a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
index 9ec2e34545..19894443d5 100644
--- a/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
+++ b/railties/lib/rails/generators/test_unit/scaffold/templates/functional_test.rb
@@ -19,7 +19,7 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase
test "should create <%= singular_table_name %>" do
assert_difference('<%= class_name %>.count') do
- post :create, <%= key_value singular_table_name, "@#{singular_table_name}.attributes" %>
+ post :create, <%= resource_attributes %>
end
assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>))
@@ -36,7 +36,7 @@ class <%= controller_class_name %>ControllerTest < ActionController::TestCase
end
test "should update <%= singular_table_name %>" do
- put :update, <%= key_value :id, "@#{singular_table_name}" %>, <%= key_value singular_table_name, "@#{singular_table_name}.attributes" %>
+ put :update, <%= key_value :id, "@#{singular_table_name}" %>, <%= resource_attributes %>
assert_redirected_to <%= singular_table_name %>_path(assigns(:<%= singular_table_name %>))
end
diff --git a/railties/test/generators/scaffold_controller_generator_test.rb b/railties/test/generators/scaffold_controller_generator_test.rb
index 65b30b9fbd..7c28f5914f 100644
--- a/railties/test/generators/scaffold_controller_generator_test.rb
+++ b/railties/test/generators/scaffold_controller_generator_test.rb
@@ -75,6 +75,31 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
assert_file "test/functional/users_controller_test.rb" do |content|
assert_match(/class UsersControllerTest < ActionController::TestCase/, content)
assert_match(/test "should get index"/, content)
+
+ if RUBY_VERSION < "1.9"
+ assert_match(/post :create, :user => \{ :age => @user.age, :name => @user.name \}/, content)
+ assert_match(/put :update, :id => @user, :user => \{ :age => @user.age, :name => @user.name \}/, content)
+ else
+ assert_match(/post :create, user: \{ age: @user.age, name: @user.name \}/, content)
+ assert_match(/put :update, id: @user, user: \{ age: @user.age, name: @user.name \}/, content)
+ end
+ end
+ end
+
+ def test_functional_tests_without_attributes
+ run_generator ["User"]
+
+ assert_file "test/functional/users_controller_test.rb" do |content|
+ assert_match(/class UsersControllerTest < ActionController::TestCase/, content)
+ assert_match(/test "should get index"/, content)
+
+ if RUBY_VERSION < "1.9"
+ assert_match(/post :create, :user => \{ \}/, content)
+ assert_match(/put :update, :id => @user, :user => \{ \}/, content)
+ else
+ assert_match(/post :create, user: \{ \}/, content)
+ assert_match(/put :update, id: @user, user: \{ \}/, content)
+ end
end
end
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index 2db8090621..2710ef7dfd 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -62,8 +62,17 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
end
end
- assert_file "test/functional/product_lines_controller_test.rb",
- /class ProductLinesControllerTest < ActionController::TestCase/
+ assert_file "test/functional/product_lines_controller_test.rb" do |test|
+ assert_match(/class ProductLinesControllerTest < ActionController::TestCase/, test)
+
+ if RUBY_VERSION < "1.9"
+ assert_match(/post :create, :product_line => \{ :title => @product_line.title \}/, test)
+ assert_match(/put :update, :id => @product_line, :product_line => \{ :title => @product_line.title \}/, test)
+ else
+ assert_match(/post :create, product_line: \{ title: @product_line.title \}/, test)
+ assert_match(/put :update, id: @product_line, product_line: \{ title: @product_line.title \}/, test)
+ end
+ end
# Views
%w(
@@ -85,6 +94,23 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
assert_file "app/assets/stylesheets/product_lines.css"
end
+ def test_functional_tests_without_attributes
+ run_generator ["product_line"]
+
+ assert_file "test/functional/product_lines_controller_test.rb" do |content|
+ assert_match(/class ProductLinesControllerTest < ActionController::TestCase/, content)
+ assert_match(/test "should get index"/, content)
+
+ if RUBY_VERSION < "1.9"
+ assert_match(/post :create, :product_line => \{ \}/, content)
+ assert_match(/put :update, :id => @product_line, :product_line => \{ \}/, content)
+ else
+ assert_match(/post :create, product_line: \{ \}/, content)
+ assert_match(/put :update, id: @product_line, product_line: \{ \}/, content)
+ end
+ end
+ end
+
def test_scaffold_on_revoke
run_generator
run_generator ["product_line"], :behavior => :revoke