aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb20
-rw-r--r--actionpack/test/abstract_unit.rb1
-rw-r--r--actionpack/test/template/form_helper_test.rb125
-rw-r--r--actionpack/test/template/sprockets_helper_test.rb9
-rw-r--r--activemodel/test/cases/helper.rb1
-rw-r--r--activerecord/lib/active_record/associations/association_scope.rb20
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb10
-rw-r--r--activerecord/lib/active_record/reflection.rb9
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb7
-rw-r--r--activerecord/test/cases/reflection_test.rb4
-rw-r--r--activeresource/test/abstract_unit.rb6
-rw-r--r--activesupport/activesupport.gemspec7
-rw-r--r--activesupport/lib/active_support/i18n.rb2
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb4
-rw-r--r--activesupport/lib/active_support/xml_mini.rb6
-rw-r--r--railties/test/isolation/abstract_unit.rb2
-rw-r--r--railties/test/rails_info_controller_test.rb1
17 files changed, 197 insertions, 37 deletions
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 07e2c8d341..cb1c13912a 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -555,6 +555,19 @@ module ActionView
# ...
# <% end %>
#
+ # In addition, you may want to have access to the current iteration index.
+ # In that case, you can use a similar method called fields_for_with_index
+ # which receives a block with an extra parameter:
+ #
+ # <%= form_for @person do |person_form| %>
+ # ...
+ # <%= person_form.fields_for_with_index :projects do |project_fields, index| %>
+ # Position: <%= index %>
+ # Name: <%= project_fields.text_field :name %>
+ # <% end %>
+ # ...
+ # <% end %>
+ #
# When projects is already an association on Person you can use
# +accepts_nested_attributes_for+ to define the writer method for you:
#
@@ -1216,6 +1229,13 @@ module ActionView
RUBY_EVAL
end
+ # Check +fields_for+ for docs and examples.
+ def fields_for_with_index(record_name, record_object = nil, fields_options = {}, &block)
+ index = fields_options[:index] || options[:child_index] || nested_child_index(@object_name)
+ block_with_index = Proc.new{ |obj| block.call(obj, index) }
+ fields_for(record_name, record_object, fields_options, &block_with_index)
+ end
+
def fields_for(record_name, record_object = nil, fields_options = {}, &block)
fields_options, record_object = record_object, nil if record_object.is_a?(Hash)
fields_options[:builder] ||= options[:builder]
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index 60534a9746..ad0ad807db 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -1,4 +1,5 @@
require File.expand_path('../../../load_paths', __FILE__)
+require File.expand_path('../../../version', __FILE__)
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 286bfb4d04..f2a49f7a68 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -974,6 +974,22 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_nested_fields_for_with_index_with_index_and_parent_fields
+ form_for(@post, :index => 1) do |c|
+ concat c.text_field(:title)
+ concat c.fields_for_with_index('comment', @comment, :index => 1) { |r, comment_index|
+ concat r.text_field(:name, "data-index" => comment_index)
+ }
+ end
+
+ expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', 'put') do
+ "<input name='post[1][title]' size='30' type='text' id='post_1_title' value='Hello World' />" +
+ "<input name='post[1][comment][1][name]' size='30' type='text' id='post_1_comment_1_name' value='new comment' data-index='1' />"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_form_for_with_index_and_nested_fields_for
output_buffer = form_for(@post, :index => 1) do |f|
concat f.fields_for(:comment, @post) { |c|
@@ -1030,6 +1046,20 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_nested_fields_for_with_index_with_index_radio_button
+ form_for(@post) do |f|
+ concat f.fields_for_with_index(:comment, @post, :index => 5) { |c, index|
+ concat c.radio_button(:title, "hello", "data-index" => index)
+ }
+ end
+
+ expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', 'put') do
+ "<input name='post[comment][5][title]' type='radio' id='post_comment_5_title_hello' value='hello' data-index='5' />"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_nested_fields_for_with_auto_index_on_both
form_for(@post, :as => "post[]") do |f|
concat f.fields_for("comment[]", @post) { |c|
@@ -1229,6 +1259,29 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_nested_fields_for_with_index_with_existing_records_on_a_nested_attributes_collection_association
+ @post.comments = Array.new(2) { |id| Comment.new(id + 1) }
+
+ form_for(@post) do |f|
+ concat f.text_field(:title)
+ @post.comments.each do |comment|
+ concat f.fields_for_with_index(:comments, comment) { |cf, index|
+ concat cf.text_field(:name, "data-index" => index)
+ }
+ end
+ end
+
+ expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', :method => 'put') do
+ '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #1" data-index="0" />' +
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="1" />' +
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="comment #2" data-index="1" />' +
+ '<input id="post_comments_attributes_1_id" name="post[comments_attributes][1][id]" type="hidden" value="2" />'
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_with_disabled_hidden_id
@post.comments = Array.new(2) { |id| Comment.new(id + 1) }
@post.author = Author.new(321)
@@ -1256,6 +1309,33 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_nested_fields_for_with_index_with_existing_records_on_a_nested_attributes_collection_association_with_disabled_hidden_id
+ @post.comments = Array.new(2) { |id| Comment.new(id + 1) }
+ @post.author = Author.new(321)
+
+ form_for(@post) do |f|
+ concat f.text_field(:title)
+ concat f.fields_for(:author) { |af|
+ concat af.text_field(:name)
+ }
+ @post.comments.each do |comment|
+ concat f.fields_for_with_index(:comments, comment, :include_id => false) { |cf, index|
+ concat cf.text_field(:name, 'data-index' => index)
+ }
+ end
+ end
+
+ expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', :method => 'put') do
+ '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
+ '<input id="post_author_attributes_name" name="post[author_attributes][name]" size="30" type="text" value="author #321" />' +
+ '<input id="post_author_attributes_id" name="post[author_attributes][id]" type="hidden" value="321" />' +
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #1" data-index="0" />' +
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="comment #2" data-index="1" />'
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_with_disabled_hidden_id_inherited
@post.comments = Array.new(2) { |id| Comment.new(id + 1) }
@post.author = Author.new(321)
@@ -1377,6 +1457,28 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_nested_fields_for_with_index_with_new_records_on_a_nested_attributes_collection_association
+ @post.comments = [Comment.new, Comment.new]
+
+ form_for(@post) do |f|
+ concat f.text_field(:title)
+ @post.comments.each do |comment|
+ concat f.fields_for_with_index(:comments, comment) { |cf, index|
+ concat cf.text_field(:name, "data-index" => index)
+ }
+ end
+ end
+
+ expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', :method => 'put') do
+ '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="new comment" data-index="0" />' +
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="new comment" data-index="1" />'
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
+
def test_nested_fields_for_with_existing_and_new_records_on_a_nested_attributes_collection_association
@post.comments = [Comment.new(321), Comment.new]
@@ -1399,6 +1501,29 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_nested_fields_for_with_index_with_existing_and_new_records_on_a_nested_attributes_collection_association
+ @post.comments = [Comment.new(321), Comment.new]
+
+ form_for(@post) do |f|
+ concat f.text_field(:title)
+ @post.comments.each do |comment|
+ concat f.fields_for_with_index(:comments, comment) { |cf, index|
+ concat cf.text_field(:name, "data-index" => index)
+ }
+ end
+ end
+
+ expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', :method => 'put') do
+ '<input name="post[title]" size="30" type="text" id="post_title" value="Hello World" />' +
+ '<input id="post_comments_attributes_0_name" name="post[comments_attributes][0][name]" size="30" type="text" value="comment #321" data-index="0" />' +
+ '<input id="post_comments_attributes_0_id" name="post[comments_attributes][0][id]" type="hidden" value="321" />' +
+ '<input id="post_comments_attributes_1_name" name="post[comments_attributes][1][name]" size="30" type="text" value="new comment" data-index="1" />'
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
+
def test_nested_fields_for_with_an_empty_supplied_attributes_collection
form_for(@post) do |f|
concat f.text_field(:title)
diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb
index 4ce8c672cd..23288a242c 100644
--- a/actionpack/test/template/sprockets_helper_test.rb
+++ b/actionpack/test/template/sprockets_helper_test.rb
@@ -1,9 +1,14 @@
require 'abstract_unit'
+
+module Rails
+ class Engine
+ def self.initializer(*args); end
+ end
+end
+
require 'sprockets'
require 'mocha'
-module Rails; end
-
class SprocketsHelperTest < ActionView::TestCase
tests ActionView::Helpers::SprocketsHelper
diff --git a/activemodel/test/cases/helper.rb b/activemodel/test/cases/helper.rb
index 01f0158678..2e860272a4 100644
--- a/activemodel/test/cases/helper.rb
+++ b/activemodel/test/cases/helper.rb
@@ -10,5 +10,4 @@ require 'active_support/core_ext/string/access'
# Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true
-require 'rubygems'
require 'test/unit'
diff --git a/activerecord/lib/active_record/associations/association_scope.rb b/activerecord/lib/active_record/associations/association_scope.rb
index ab102b2b8f..94847bc2ae 100644
--- a/activerecord/lib/active_record/associations/association_scope.rb
+++ b/activerecord/lib/active_record/associations/association_scope.rb
@@ -75,10 +75,16 @@ module ActiveRecord
foreign_key = reflection.active_record_primary_key
end
+ conditions = self.conditions[i]
+
if reflection == chain.last
scope = scope.where(table[key].eq(owner[foreign_key]))
- conditions[i].each do |condition|
+ if reflection.type
+ scope = scope.where(table[reflection.type].eq(owner.class.base_class.name))
+ end
+
+ conditions.each do |condition|
if options[:through] && condition.is_a?(Hash)
condition = { table.name => condition }
end
@@ -87,12 +93,16 @@ module ActiveRecord
end
else
constraint = table[key].eq(foreign_table[foreign_key])
- join = join(foreign_table, constraint)
- scope = scope.joins(join)
+ if reflection.type
+ type = chain[i + 1].klass.base_class.name
+ constraint = constraint.and(table[reflection.type].eq(type))
+ end
+
+ scope = scope.joins(join(foreign_table, constraint))
- unless conditions[i].empty?
- scope = scope.where(sanitize(conditions[i], table))
+ unless conditions.empty?
+ scope = scope.where(sanitize(conditions, table))
end
end
end
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index c32753782f..03963ab060 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -62,6 +62,7 @@ module ActiveRecord
def join_to(relation)
tables = @tables.dup
foreign_table = parent_table
+ foreign_klass = parent.active_record
# The chain starts with the target table, but we want to end with it here (makes
# more sense in this context), so we reverse
@@ -91,14 +92,17 @@ module ActiveRecord
constraint = build_constraint(reflection, table, key, foreign_table, foreign_key)
- unless conditions[i].empty?
- constraint = constraint.and(sanitize(conditions[i], table))
+ conditions = self.conditions[i].dup
+ conditions << { reflection.type => foreign_klass.base_class.name } if reflection.type
+
+ unless conditions.empty?
+ constraint = constraint.and(sanitize(conditions, table))
end
relation.from(join(table, constraint))
# The current table in this iteration becomes the foreign table in the next
- foreign_table = table
+ foreign_table, foreign_klass = table, reflection.klass
end
relation
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index bcba85d7a4..b1bb1b0f7f 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -212,7 +212,7 @@ module ActiveRecord
end
def type
- @type ||= "#{options[:as]}_type"
+ @type ||= options[:as] && "#{options[:as]}_type"
end
def primary_key_column
@@ -280,9 +280,7 @@ module ActiveRecord
# in the #chain. The inside arrays are simply conditions (and each condition may itself be
# a hash, array, arel predicate, etc...)
def conditions
- conditions = [options[:conditions]].compact
- conditions << { type => active_record.base_class.name } if options[:as]
- [conditions]
+ [[options[:conditions]].compact]
end
alias :source_macro :macro
@@ -378,7 +376,8 @@ module ActiveRecord
# Holds all the meta-data about a :through association as it was specified
# in the Active Record class.
class ThroughReflection < AssociationReflection #:nodoc:
- delegate :foreign_key, :foreign_type, :association_foreign_key, :active_record_primary_key, :to => :source_reflection
+ delegate :foreign_key, :foreign_type, :association_foreign_key,
+ :active_record_primary_key, :type, :to => :source_reflection
# Gets the source of the through reflection. It checks both a singularized
# and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index 522ac56d82..43974fd895 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -11,6 +11,7 @@ require 'models/comment'
require 'models/person'
require 'models/reader'
require 'models/tagging'
+require 'models/tag'
require 'models/invoice'
require 'models/line_item'
require 'models/car'
@@ -1468,4 +1469,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
bulb = car.bulbs.build({ :bulb_type => :custom }, :as => :admin)
assert_equal CustomBulb, bulb.class
end
+
+ def test_abstract_class_with_polymorphic_has_many
+ post = SubStiPost.create! :title => "fooo", :body => "baa"
+ tagging = Tagging.create! :taggable => post
+ assert_equal [tagging], post.taggings
+ end
end
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index 97d9669483..7e4ae1ea8d 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -216,7 +216,7 @@ class ReflectionTest < ActiveRecord::TestCase
def test_conditions
expected = [
[{ :tags => { :name => 'Blue' } }],
- [{ :taggings => { :comment => 'first' } }, { "taggable_type" => "Post" }],
+ [{ :taggings => { :comment => 'first' } }],
[{ :posts => { :title => ['misc post by bob', 'misc post by mary'] } }]
]
actual = Author.reflect_on_association(:misc_post_first_blue_tags).conditions
@@ -224,7 +224,7 @@ class ReflectionTest < ActiveRecord::TestCase
expected = [
[{ :tags => { :name => 'Blue' } }, { :taggings => { :comment => 'first' } }, { :posts => { :title => ['misc post by bob', 'misc post by mary'] } }],
- [{ "taggable_type" => "Post" }],
+ [],
[]
]
actual = Author.reflect_on_association(:misc_post_first_blue_tags_2).conditions
diff --git a/activeresource/test/abstract_unit.rb b/activeresource/test/abstract_unit.rb
index 948dd94a1d..9c1e9a526d 100644
--- a/activeresource/test/abstract_unit.rb
+++ b/activeresource/test/abstract_unit.rb
@@ -3,7 +3,6 @@ require File.expand_path('../../../load_paths', __FILE__)
lib = File.expand_path("#{File.dirname(__FILE__)}/../lib")
$:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
-require 'rubygems'
require 'test/unit'
require 'active_resource'
require 'active_support'
@@ -14,11 +13,6 @@ require 'setter_trap'
require 'logger'
ActiveResource::Base.logger = Logger.new("#{File.dirname(__FILE__)}/debug.log")
-begin
- require 'ruby-debug'
-rescue LoadError
-end
-
def setup_response
matz_hash = { 'person' => { :id => 1, :name => 'Matz' } }
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index f6eb2be5ae..738a10a18f 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -9,12 +9,13 @@ Gem::Specification.new do |s|
s.required_ruby_version = '>= 1.8.7'
- s.author = 'David Heinemeier Hansson'
- s.email = 'david@loudthinking.com'
- s.homepage = 'http://www.rubyonrails.org'
+ s.author = 'David Heinemeier Hansson'
+ s.email = 'david@loudthinking.com'
+ s.homepage = 'http://www.rubyonrails.org'
s.files = Dir['CHANGELOG', 'README.rdoc', 'lib/**/*']
s.require_path = 'lib'
+ s.add_dependency('i18n', '~> 0.6')
s.add_dependency('multi_json', '~> 1.0')
end
diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb
index 00ea8813dd..f9c5e5e2f8 100644
--- a/activesupport/lib/active_support/i18n.rb
+++ b/activesupport/lib/active_support/i18n.rb
@@ -2,7 +2,7 @@ begin
require 'i18n'
require 'active_support/lazy_load_hooks'
rescue LoadError => e
- $stderr.puts "You don't have i18n installed in your application. Please add it to your Gemfile and run bundle install"
+ $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
raise e
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index abd585b64f..728921a069 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -315,10 +315,8 @@ module ActiveSupport
tzinfo.period_for_local(time, dst)
end
- # TODO: Preload instead of lazy load for thread safety
def self.find_tzinfo(name)
- require 'active_support/tzinfo' unless defined?(::TZInfo)
- ::TZInfo::TimezoneProxy.new(MAPPING[name] || name)
+ TZInfo::TimezoneProxy.new(MAPPING[name] || name)
end
class << self
diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb
index 6e12404ad4..1ea9a9d7e1 100644
--- a/activesupport/lib/active_support/xml_mini.rb
+++ b/activesupport/lib/active_support/xml_mini.rb
@@ -1,3 +1,4 @@
+require 'time'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/string/inflections'
@@ -51,13 +52,12 @@ module ActiveSupport
"yaml" => Proc.new { |yaml| yaml.to_yaml }
} unless defined?(FORMATTING)
- # TODO: use Time.xmlschema instead of Time.parse;
- # use regexp instead of Date.parse
+ # TODO use regexp instead of Date.parse
unless defined?(PARSING)
PARSING = {
"symbol" => Proc.new { |symbol| symbol.to_sym },
"date" => Proc.new { |date| ::Date.parse(date) },
- "datetime" => Proc.new { |time| ::Time.parse(time).utc rescue ::DateTime.parse(time).utc },
+ "datetime" => Proc.new { |time| Time.xmlschema(time).utc rescue ::DateTime.parse(time).utc },
"integer" => Proc.new { |integer| integer.to_i },
"float" => Proc.new { |float| float.to_f },
"decimal" => Proc.new { |number| BigDecimal(number) },
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index f2261540ca..17a4131158 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -8,8 +8,6 @@
# Rails booted up.
require 'fileutils'
-# TODO: Remove rubygems when possible
-require 'rubygems'
require 'test/unit'
# TODO: Remove setting this magic constant
diff --git a/railties/test/rails_info_controller_test.rb b/railties/test/rails_info_controller_test.rb
index 9d194f41a6..8a9363fb80 100644
--- a/railties/test/rails_info_controller_test.rb
+++ b/railties/test/rails_info_controller_test.rb
@@ -1,5 +1,4 @@
require 'abstract_unit'
-require 'action_controller'
module ActionController
class Base