aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--actionpack/CHANGELOG.md10
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb26
-rw-r--r--actionpack/lib/action_view/helpers/atom_feed_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb15
-rw-r--r--actionpack/test/dispatch/show_exceptions_test.rb7
-rw-r--r--actionpack/test/fixtures/test/_label_with_block.erb4
-rw-r--r--actionpack/test/template/form_helper_test.rb83
-rw-r--r--activerecord/lib/active_record/associations/collection_association.rb2
-rw-r--r--activerecord/lib/active_record/associations/has_many_association.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb2
-rw-r--r--activerecord/test/cases/associations/has_many_associations_test.rb29
-rwxr-xr-xci/travis.rb2
-rw-r--r--railties/lib/rails/application.rb3
-rw-r--r--railties/lib/rails/application/finisher.rb1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/public/index.html2
-rw-r--r--railties/lib/rails/railtie.rb2
-rw-r--r--railties/test/application/configuration_test.rb9
-rw-r--r--railties/test/generators/app_generator_test.rb1
19 files changed, 176 insertions, 30 deletions
diff --git a/Gemfile b/Gemfile
index b0fbb3b310..65950cdc2e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -62,7 +62,7 @@ platforms :ruby do
group :db do
gem "pg", ">= 0.11.0" unless ENV['TRAVIS'] # once pg is on travis this can be removed
gem "mysql", ">= 2.8.1"
- gem "mysql2", ">= 0.3.6"
+ gem "mysql2", ">= 0.3.10"
end
end
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index fe422f71d5..314aa7181c 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,5 +1,15 @@
## Rails 3.2.0 (unreleased) ##
+* You can provide a namespace for your form to ensure uniqueness of id attributes on form elements.
+ The namespace attribute will be prefixed with underscore on the generate HTML id. *Vasiliy Ermolovich*
+
+ Example:
+
+ <%= form_for(@offer, :namespace => 'namespace') do |f| %>
+ <%= f.label :version, 'Version' %>:
+ <%= f.text_field :version %>
+ <% end %>
+
* Refactor ActionDispatch::ShowExceptions. Controller is responsible for choice to show exceptions. *Sergey Nartimov*
It's possible to override +show_detailed_exceptions?+ in controllers to specify which requests should provide debugging information on errors.
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 8dc2820d37..c850e25507 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -82,9 +82,9 @@ module ActionDispatch
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
:request => Request.new(env),
:exception => exception,
- :application_trace => application_trace(exception),
- :framework_trace => framework_trace(exception),
- :full_trace => full_trace(exception)
+ :application_trace => application_trace(env, exception),
+ :framework_trace => framework_trace(env, exception),
+ :full_trace => full_trace(env, exception)
)
file = "rescues/#{@@rescue_templates[exception.class.name]}"
body = template.render(:template => file, :layout => 'rescues/layout')
@@ -130,26 +130,26 @@ module ActionDispatch
ActiveSupport::Deprecation.silence do
message = "\n#{exception.class} (#{exception.message}):\n"
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
- message << " " << application_trace(exception).join("\n ")
+ message << " " << application_trace(env, exception).join("\n ")
logger(env).fatal("#{message}\n\n")
end
end
- def application_trace(exception)
- clean_backtrace(exception, :silent)
+ def application_trace(env, exception)
+ clean_backtrace(env, exception, :silent)
end
- def framework_trace(exception)
- clean_backtrace(exception, :noise)
+ def framework_trace(env, exception)
+ clean_backtrace(env, exception, :noise)
end
- def full_trace(exception)
- clean_backtrace(exception, :all)
+ def full_trace(env, exception)
+ clean_backtrace(env, exception, :all)
end
- def clean_backtrace(exception, *args)
- defined?(Rails) && Rails.respond_to?(:backtrace_cleaner) ?
- Rails.backtrace_cleaner.clean(exception.backtrace, *args) :
+ def clean_backtrace(env, exception, *args)
+ env['action_dispatch.backtrace_cleaner'] ?
+ env['action_dispatch.backtrace_cleaner'].clean(exception.backtrace, *args) :
exception.backtrace
end
diff --git a/actionpack/lib/action_view/helpers/atom_feed_helper.rb b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
index 90589d2238..73824dc1f8 100644
--- a/actionpack/lib/action_view/helpers/atom_feed_helper.rb
+++ b/actionpack/lib/action_view/helpers/atom_feed_helper.rb
@@ -32,7 +32,7 @@ module ActionView
# app/views/posts/index.atom.builder:
# atom_feed do |feed|
# feed.title("My great blog!")
- # feed.updated(@posts.first.created_at) if @posts.any?
+ # feed.updated(@posts[0].created_at) if @posts.length > 0
#
# @posts.each do |post|
# feed.entry(post) do |entry|
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index d687866d0d..6c97d75922 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -158,6 +158,9 @@ module ActionView
# * <tt>:url</tt> - The URL the form is submitted to. It takes the same
# fields you pass to +url_for+ or +link_to+. In particular you may pass
# here a named route directly as well. Defaults to the current action.
+ # * <tt>:namespace</tt> - A namespace for your form to ensure uniqueness of
+ # id attributes on form elements. The namespace attribute will be prefixed
+ # with underscore on the generate HTML id.
# * <tt>:html</tt> - Optional HTML attributes for the form tag.
#
# Also note that +form_for+ doesn't create an exclusive scope. It's still
@@ -385,7 +388,7 @@ module ActionView
action, method = object.respond_to?(:persisted?) && object.persisted? ? [:edit, :put] : [:new, :post]
options[:html].reverse_merge!(
:class => as ? "#{as}_#{action}" : dom_class(object, action),
- :id => as ? "#{as}_#{action}" : dom_id(object, action),
+ :id => as ? "#{as}_#{action}" : [options[:namespace], dom_id(object, action)].compact.join("_").presence,
:method => method
)
@@ -960,7 +963,7 @@ module ActionView
end
class InstanceTag
- include Helpers::CaptureHelper, Context, Helpers::TagHelper, Helpers::FormTagHelper
+ include Helpers::TagHelper, Helpers::FormTagHelper
attr_reader :object, :method_name, :object_name
@@ -971,6 +974,7 @@ module ActionView
def initialize(object_name, method_name, template_object, object = nil)
@object_name, @method_name = object_name.to_s.dup, method_name.to_s.dup
@template_object = template_object
+
@object_name.sub!(/\[\]$/,"") || @object_name.sub!(/\[\]\]$/,"]")
@object = retrieve_object(object)
@auto_index = retrieve_autoindex(Regexp.last_match.pre_match) if Regexp.last_match
@@ -989,10 +993,11 @@ module ActionView
add_default_name_and_id_for_value(tag_value, name_and_id)
options.delete("index")
+ options.delete("namespace")
options["for"] ||= name_and_id["id"]
if block_given?
- label_tag(name_and_id["id"], options, &block)
+ @template_object.label_tag(name_and_id["id"], options, &block)
else
content = if text.blank?
object_name.gsub!(/\[(.*)_attributes\]\[\d\]/, '.\1')
@@ -1195,6 +1200,7 @@ module ActionView
options["name"] ||= tag_name + (options['multiple'] ? '[]' : '')
options["id"] = options.fetch("id"){ tag_id }
end
+ options["id"] = [options.delete('namespace'), options["id"]].compact.join("_").presence
end
def tag_name
@@ -1253,7 +1259,7 @@ module ActionView
@nested_child_index = {}
@object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
@parent_builder = options[:parent_builder]
- @default_options = @options ? @options.slice(:index) : {}
+ @default_options = @options ? @options.slice(:index, :namespace) : {}
if @object_name.to_s.match(/\[\]$/)
if object ||= @template.instance_variable_get("@#{Regexp.last_match.pre_match}") and object.respond_to?(:to_param)
@auto_index = object.to_param
@@ -1280,6 +1286,7 @@ module ActionView
fields_options, record_object = record_object, nil if record_object.is_a?(Hash) && record_object.extractable_options?
fields_options[:builder] ||= options[:builder]
fields_options[:parent_builder] = self
+ fields_options[:namespace] = fields_options[:parent_builder].options[:namespace]
case record_name
when String, Symbol
diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb
index 5875725b5d..90f13a3bb9 100644
--- a/actionpack/test/dispatch/show_exceptions_test.rb
+++ b/actionpack/test/dispatch/show_exceptions_test.rb
@@ -135,4 +135,11 @@ class ShowExceptionsTest < ActionDispatch::IntegrationTest
get "/", {}, {'action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => Logger.new(output)}
assert_match(/puke/, output.rewind && output.read)
end
+
+ test 'uses backtrace cleaner from env' do
+ @app = DevelopmentApp
+ cleaner = stub(:clean => ['passed backtrace cleaner'])
+ get "/", {}, {'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => cleaner}
+ assert_match(/passed backtrace cleaner/, body)
+ end
end
diff --git a/actionpack/test/fixtures/test/_label_with_block.erb b/actionpack/test/fixtures/test/_label_with_block.erb
new file mode 100644
index 0000000000..40117e594e
--- /dev/null
+++ b/actionpack/test/fixtures/test/_label_with_block.erb
@@ -0,0 +1,4 @@
+<%= label 'post', 'message' do %>
+ Message
+ <%= text_field 'post', 'message' %>
+<% end %>
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index ccedcd7dac..ad876df65d 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -230,6 +230,13 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal('<label for="post_title">The title, please:</label>', label(:post, :title) { "The title, please:" })
end
+ def test_label_with_block_in_erb
+ path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
+ view_paths = ActionView::PathSet.new([path])
+ view = ActionView::Base.new(view_paths)
+ assert_equal "<label for=\"post_message\">\n Message\n <input id=\"post_message\" name=\"post[message]\" size=\"30\" type=\"text\" />\n</label>", view.render("test/label_with_block")
+ end
+
def test_text_field
assert_dom_equal(
'<input id="post_title" name="post[title]" size="30" type="text" value="Hello World" />', text_field("post", "title")
@@ -928,6 +935,82 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_form_for_with_namespace
+ form_for(@post, :namespace => 'namespace') do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.check_box(:secret)
+ end
+
+ expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do
+ "<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='namespace_post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[secret]' type='hidden' value='0' />" +
+ "<input name='post[secret]' checked='checked' type='checkbox' id='namespace_post_secret' value='1' />"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_form_for_with_namespace_with_label
+ form_for(@post, :namespace => 'namespace') do |f|
+ concat f.label(:title)
+ concat f.text_field(:title)
+ end
+
+ expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do
+ "<label for='namespace_post_title'>Title</label>" +
+ "<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
+ def test_two_form_for_with_namespace
+ form_for(@post, :namespace => 'namespace_1') do |f|
+ concat f.label(:title)
+ concat f.text_field(:title)
+ end
+
+ expected_1 = whole_form('/posts/123', 'namespace_1_edit_post_123', 'edit_post', 'put') do
+ "<label for='namespace_1_post_title'>Title</label>" +
+ "<input name='post[title]' size='30' type='text' id='namespace_1_post_title' value='Hello World' />"
+ end
+
+ assert_dom_equal expected_1, output_buffer
+
+ form_for(@post, :namespace => 'namespace_2') do |f|
+ concat f.label(:title)
+ concat f.text_field(:title)
+ end
+
+ expected_2 = whole_form('/posts/123', 'namespace_2_edit_post_123', 'edit_post', 'put') do
+ "<label for='namespace_2_post_title'>Title</label>" +
+ "<input name='post[title]' size='30' type='text' id='namespace_2_post_title' value='Hello World' />"
+ end
+
+ assert_dom_equal expected_2, output_buffer
+ end
+
+ def test_fields_for_with_namespace
+ @comment.body = 'Hello World'
+ form_for(@post, :namespace => 'namespace') do |f|
+ concat f.text_field(:title)
+ concat f.text_area(:body)
+ concat f.fields_for(@comment) { |c|
+ concat c.text_field(:body)
+ }
+ end
+
+ expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', 'put') do
+ "<input name='post[title]' size='30' type='text' id='namespace_post_title' value='Hello World' />" +
+ "<textarea name='post[body]' id='namespace_post_body' rows='20' cols='40'>Back to the hill and over it again!</textarea>" +
+ "<input name='post[comment][body]' size='30' type='text' id='namespace_post_comment_body' value='Hello World' />"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_submit_with_object_as_new_record_and_locale_strings
old_locale, I18n.locale = I18n.locale, :submit
diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb
index 362f1053cd..af37909c89 100644
--- a/activerecord/lib/active_record/associations/collection_association.rb
+++ b/activerecord/lib/active_record/associations/collection_association.rb
@@ -235,7 +235,7 @@ module ActiveRecord
# This method is abstract in the sense that it relies on
# +count_records+, which is a method descendants have to provide.
def size
- if owner.new_record? || (loaded? && !options[:uniq])
+ if !find_target? || (loaded? && !options[:uniq])
target.size
elsif !loaded? && options[:group]
load_target.size
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb
index 3353cdf1ef..c5b90e873a 100644
--- a/activerecord/lib/active_record/associations/has_many_association.rb
+++ b/activerecord/lib/active_record/associations/has_many_association.rb
@@ -103,6 +103,10 @@ module ActiveRecord
end
end
end
+
+ def foreign_key_present?
+ owner.attribute_present?(reflection.association_primary_key)
+ end
end
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
index 971f3c35f3..95f254ddd2 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb
@@ -1,6 +1,6 @@
require 'active_record/connection_adapters/abstract_mysql_adapter'
-gem 'mysql2', '~> 0.3.6'
+gem 'mysql2', '~> 0.3.10'
require 'mysql2'
module ActiveRecord
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb
index a60af7c046..88d7d47aea 100644
--- a/activerecord/test/cases/associations/has_many_associations_test.rb
+++ b/activerecord/test/cases/associations/has_many_associations_test.rb
@@ -8,6 +8,7 @@ require 'models/reply'
require 'models/category'
require 'models/post'
require 'models/author'
+require 'models/essay'
require 'models/comment'
require 'models/person'
require 'models/reader'
@@ -61,7 +62,7 @@ end
class HasManyAssociationsTest < ActiveRecord::TestCase
fixtures :accounts, :categories, :companies, :developers, :projects,
:developers_projects, :topics, :authors, :comments,
- :people, :posts, :readers, :taggings, :cars
+ :people, :posts, :readers, :taggings, :cars, :essays
def setup
Client.destroyed_client_ids.clear
@@ -1390,6 +1391,32 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
firm.clients.last
end
end
+
+ def test_custom_primary_key_on_new_record_should_fetch_with_query
+ author = Author.new(:name => "David")
+ assert !author.essays.loaded?
+
+ assert_queries 1 do
+ assert_equal 1, author.essays.size
+ end
+
+ assert_equal author.essays, Essay.find_all_by_writer_id("David")
+
+ end
+
+ def test_has_many_custom_primary_key
+ david = authors(:david)
+ assert_equal david.essays, Essay.find_all_by_writer_id("David")
+ end
+
+ def test_blank_custom_primary_key_on_new_record_should_not_run_queries
+ author = Author.new
+ assert !author.essays.loaded?
+
+ assert_queries 0 do
+ assert_equal 0, author.essays.size
+ end
+ end
def test_calling_first_or_last_with_find_options_on_loaded_association_should_fetch_with_query
firm = companies(:first_firm)
diff --git a/ci/travis.rb b/ci/travis.rb
index 8087c72f90..52e146df70 100755
--- a/ci/travis.rb
+++ b/ci/travis.rb
@@ -132,7 +132,7 @@ failures = results.select { |key, value| value == false }
if failures.empty?
puts
- puts "Rails build finished sucessfully"
+ puts "Rails build finished successfully"
exit(true)
else
puts
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 25ff74506a..2a62446a04 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -124,7 +124,8 @@ module Rails
"action_dispatch.parameter_filter" => config.filter_parameters,
"action_dispatch.secret_token" => config.secret_token,
"action_dispatch.show_exceptions" => config.action_dispatch.show_exceptions,
- "action_dispatch.logger" => Rails.logger
+ "action_dispatch.logger" => Rails.logger,
+ "action_dispatch.backtrace_cleaner" => Rails.backtrace_cleaner
})
end
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index 028c8814c4..fc7d205a6f 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -2,6 +2,7 @@ module Rails
class Application
module Finisher
include Initializable
+ $rails_rake_task = nil
initializer :add_generator_templates do
config.generators.templates.unshift(*paths["lib/templates"].existent)
diff --git a/railties/lib/rails/generators/rails/app/templates/public/index.html b/railties/lib/rails/generators/rails/app/templates/public/index.html
index 9d9811a5bf..a1d50995c5 100644
--- a/railties/lib/rails/generators/rails/app/templates/public/index.html
+++ b/railties/lib/rails/generators/rails/app/templates/public/index.html
@@ -59,7 +59,7 @@
#header {
- background-image: url("/assets/rails.png");
+ background-image: url("assets/rails.png");
background-repeat: no-repeat;
background-position: top left;
height: 64px;
diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb
index f0991b99af..07a122e7d0 100644
--- a/railties/lib/rails/railtie.rb
+++ b/railties/lib/rails/railtie.rb
@@ -181,7 +181,7 @@ module Rails
def load_tasks(app=self)
extend Rake::DSL if defined? Rake::DSL
- self.class.rake_tasks.each { |block| block.call(app) }
+ self.class.rake_tasks.each { |block| self.instance_exec(app, &block) }
# load also tasks from all superclasses
klass = self.class.superclass
diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb
index f37a024a0b..28ffff58ca 100644
--- a/railties/test/application/configuration_test.rb
+++ b/railties/test/application/configuration_test.rb
@@ -521,10 +521,11 @@ module ApplicationTests
make_basic_app
assert_respond_to app, :env_config
- assert_equal app.env_config['action_dispatch.parameter_filter'], app.config.filter_parameters
- assert_equal app.env_config['action_dispatch.secret_token'], app.config.secret_token
- assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions
- assert_equal app.env_config['action_dispatch.logger'], Rails.logger
+ assert_equal app.env_config['action_dispatch.parameter_filter'], app.config.filter_parameters
+ assert_equal app.env_config['action_dispatch.secret_token'], app.config.secret_token
+ assert_equal app.env_config['action_dispatch.show_exceptions'], app.config.action_dispatch.show_exceptions
+ assert_equal app.env_config['action_dispatch.logger'], Rails.logger
+ assert_equal app.env_config['action_dispatch.backtrace_cleaner'], Rails.backtrace_cleaner
end
end
end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index a1bd2fbaa5..235c08e38e 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -55,6 +55,7 @@ class AppGeneratorTest < Rails::Generators::TestCase
assert_file "app/views/layouts/application.html.erb", /javascript_include_tag\s+"application"/
assert_file "app/assets/stylesheets/application.css"
assert_file "config/application.rb", /config\.assets\.enabled = true/
+ assert_file "public/index.html", /url\("assets\/rails.png"\);/
end
def test_invalid_application_name_raises_an_error