aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile4
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/node.rb4
-rw-r--r--actionpack/lib/action_dispatch/railtie.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb16
-rw-r--r--actionpack/lib/action_view.rb35
-rw-r--r--actionpack/lib/action_view/base.rb5
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb10
-rw-r--r--actionpack/lib/action_view/helpers/prototype_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/url_helper.rb9
-rw-r--r--actionpack/test/dispatch/routing_test.rb30
-rw-r--r--actionpack/test/template/form_helper_test.rb20
-rw-r--r--actionpack/test/template/render_test.rb2
-rw-r--r--actionpack/test/template/url_helper_test.rb7
-rw-r--r--activemodel/lib/active_model/observing.rb16
-rw-r--r--activemodel/lib/active_model/serializers/xml.rb2
-rw-r--r--activemodel/lib/active_model/validations/confirmation.rb6
-rw-r--r--activerecord/Rakefile4
-rw-r--r--activerecord/lib/active_record/base.rb8
-rw-r--r--activerecord/lib/rails/generators/active_record.rb12
-rw-r--r--activerecord/lib/rails/generators/active_record/migration.rb15
-rw-r--r--activerecord/test/cases/base_test.rb15
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb121
-rw-r--r--activerecord/test/cases/relations_test.rb2
-rw-r--r--activerecord/test/schema/schema.rb6
-rw-r--r--activeresource/test/cases/base_test.rb6
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support/core_ext/module/delegation.rb2
-rw-r--r--activesupport/lib/active_support/dependencies.rb8
-rw-r--r--activesupport/lib/active_support/duration.rb2
-rw-r--r--activesupport/test/core_ext/duration_test.rb8
-rw-r--r--activesupport/test/core_ext/module_test.rb13
-rw-r--r--activesupport/test/dependencies_test.rb11
-rw-r--r--railties/lib/rails/application/finisher.rb7
-rw-r--r--railties/lib/rails/commands/console.rb2
-rw-r--r--railties/lib/rails/generators/generated_attribute.rb1
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile3
-rw-r--r--railties/test/application/rackup_test.rb7
-rw-r--r--railties/test/application/routing_test.rb17
-rw-r--r--railties/test/generators/generated_attribute_test.rb12
-rw-r--r--railties/test/generators/model_generator_test.rb6
-rw-r--r--railties/test/generators/scaffold_generator_test.rb6
42 files changed, 316 insertions, 155 deletions
diff --git a/Gemfile b/Gemfile
index dce0c107f2..124fbf5d24 100644
--- a/Gemfile
+++ b/Gemfile
@@ -24,6 +24,10 @@ platforms :mri_18 do
gem "ruby-debug", ">= 0.10.3"
end
+platforms :mri_19 do
+ gem "ruby-debug19"
+end
+
platforms :ruby do
gem 'json'
gem 'yajl-ruby'
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index 8fd77aeb17..5b219540f4 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
s.add_dependency('i18n', '~> 0.4.1')
s.add_dependency('rack', '~> 1.2.1')
s.add_dependency('rack-test', '~> 0.5.4')
- s.add_dependency('rack-mount', '~> 0.6.12')
+ s.add_dependency('rack-mount', '~> 0.6.13')
s.add_dependency('tzinfo', '~> 0.3.23')
s.add_dependency('erubis', '~> 2.6.6')
end
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb
index d581399514..0eaad2b911 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/node.rb
@@ -77,9 +77,7 @@ module HTML #:nodoc:
# Return a textual representation of the node.
def to_s
- s = ""
- @children.each { |child| s << child.to_s }
- s
+ @children.join()
end
# Return false (subclasses must override this to provide specific matching
diff --git a/actionpack/lib/action_dispatch/railtie.rb b/actionpack/lib/action_dispatch/railtie.rb
index a3af37947a..ed066ad75e 100644
--- a/actionpack/lib/action_dispatch/railtie.rb
+++ b/actionpack/lib/action_dispatch/railtie.rb
@@ -8,10 +8,5 @@ module ActionDispatch
config.action_dispatch.ip_spoofing_check = true
config.action_dispatch.show_exceptions = true
config.action_dispatch.best_standards_support = true
-
- # Prepare dispatcher callbacks and run 'prepare' callbacks
- initializer "action_dispatch.prepare_dispatcher" do |app|
- ActionDispatch::Callbacks.to_prepare { app.routes_reloader.execute_if_updated }
- end
end
end
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index a3bd4771c2..a2570cb877 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -909,6 +909,11 @@ module ActionDispatch
return true
end
+ if resource_scope?
+ nested { send(method, resources.pop, options, &block) }
+ return true
+ end
+
options.keys.each do |k|
(options[:constraints] ||= {})[k] = options.delete(k) if options[k].is_a?(Regexp)
end
@@ -925,13 +930,6 @@ module ActionDispatch
options.merge!(scope_action_options) if scope_action_options?
end
- if resource_scope?
- nested do
- send(method, resources.pop, options, &block)
- end
- return true
- end
-
false
end
@@ -1017,11 +1015,11 @@ module ActionDispatch
end
def id_constraint?
- @scope[:id].is_a?(Regexp) || (@scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp))
+ @scope[:constraints] && @scope[:constraints][:id].is_a?(Regexp)
end
def id_constraint
- @scope[:id] || @scope[:constraints][:id]
+ @scope[:constraints][:id]
end
def canonical_action?(action, flag)
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb
index c0d7423682..5f9dc70766 100644
--- a/actionpack/lib/action_view.rb
+++ b/actionpack/lib/action_view.rb
@@ -36,6 +36,10 @@ module ActionView
autoload :Context
autoload :Template
autoload :Helpers
+ autoload :Base
+ autoload :LookupContext
+ autoload :PathSet, "action_view/paths"
+ autoload :TestCase, "action_view/test_case"
autoload_under "render" do
autoload :Layouts
@@ -43,25 +47,26 @@ module ActionView
autoload :Rendering
end
- autoload :Base
- autoload :LookupContext
- autoload :Resolver, 'action_view/template/resolver'
- autoload :PathResolver, 'action_view/template/resolver'
- autoload :FileSystemResolver, 'action_view/template/resolver'
- autoload :PathSet, 'action_view/paths'
+ autoload_at "action_view/template/resolver" do
+ autoload :Resolver
+ autoload :PathResolver
+ autoload :FileSystemResolver
+ end
- autoload :MissingTemplate, 'action_view/template/error'
- autoload :ActionViewError, 'action_view/template/error'
- autoload :EncodingError, 'action_view/template/error'
- autoload :TemplateError, 'action_view/template/error'
- autoload :WrongEncodingError, 'action_view/template/error'
+ autoload_at "action_view/template/error" do
+ autoload :MissingTemplate
+ autoload :ActionViewError
+ autoload :EncodingError
+ autoload :TemplateError
+ autoload :WrongEncodingError
+ end
- autoload :TemplateHandler, 'action_view/template'
- autoload :TemplateHandlers, 'action_view/template'
+ autoload_at "action_view/template" do
+ autoload :TemplateHandler
+ autoload :TemplateHandlers
+ end
end
- autoload :TestCase, 'action_view/test_case'
-
ENCODING_FLAG = '#.*coding[:=]\s*(\S+)[ \t]*'
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index ff25c36fcd..b0a57f47d3 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -188,11 +188,6 @@ module ActionView #:nodoc:
delegate :logger, :to => :controller, :allow_nil => true
- # TODO: HACK FOR RJS
- def view_context
- self
- end
-
def self.xss_safe? #:nodoc:
true
end
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index 6c3d2cf1b8..94dc25eb85 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -202,6 +202,12 @@ module ActionView
# ...
# <% end %>
#
+ # You can also set the answer format, like this:
+ #
+ # <%= form_for(@post, :format => :json) do |f| %>
+ # ...
+ # <% end %>
+ #
# If you have an object that needs to be represented as a different
# parameter, like a Client that acts as a Person:
#
@@ -332,7 +338,9 @@ module ActionView
options[:html] ||= {}
options[:html].reverse_merge!(html_options)
- options[:url] ||= polymorphic_path(object_or_array)
+ options[:url] ||= options[:format] ? \
+ polymorphic_path(object_or_array, :format => options.delete(:format)) : \
+ polymorphic_path(object_or_array)
end
# Creates a scope around a specific model object like form_for, but
diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb
index 99f9363a9a..b600666536 100644
--- a/actionpack/lib/action_view/helpers/prototype_helper.rb
+++ b/actionpack/lib/action_view/helpers/prototype_helper.rb
@@ -579,7 +579,7 @@ module ActionView
# page.hide 'spinner'
# end
def update_page(&block)
- JavaScriptGenerator.new(view_context, &block).to_s.html_safe
+ JavaScriptGenerator.new(self, &block).to_s.html_safe
end
# Works like update_page but wraps the generated JavaScript in a <script>
diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb
index 4f14bfe221..b8df2d9a69 100644
--- a/actionpack/lib/action_view/helpers/url_helper.rb
+++ b/actionpack/lib/action_view/helpers/url_helper.rb
@@ -235,13 +235,8 @@ module ActionView
html_options = convert_options_to_data_attributes(options, html_options)
url = url_for(options)
- if html_options
- html_options = html_options.stringify_keys
- href = html_options['href']
- tag_options = tag_options(html_options)
- else
- tag_options = nil
- end
+ href = html_options['href']
+ tag_options = tag_options(html_options)
href_attr = "href=\"#{html_escape(url)}\"" unless href
"<a #{href_attr}#{tag_options}>#{html_escape(name || url)}</a>".html_safe
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index a4b8fafa78..c90c1041ed 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -442,6 +442,16 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get :preview, :on => :member
end
+ match '/purchases/:token/:filename',
+ :to => 'purchases#fetch',
+ :token => /[[:alnum:]]{10}/,
+ :filename => /(.+)/,
+ :as => :purchase
+
+ resources :lists, :id => /([A-Za-z0-9]{25})|default/ do
+ resources :todos, :id => /\d+/
+ end
+
scope '/countries/:country', :constraints => lambda { |params, req| %[all France].include?(params[:country]) } do
match '/', :to => 'countries#index'
match '/cities', :to => 'countries#cities'
@@ -2098,6 +2108,26 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/customers/1/export', customer_export_path(:customer_id => '1')
end
+ def test_named_character_classes_in_regexp_constraints
+ get '/purchases/315004be7e/Ruby_on_Rails_3.pdf'
+ assert_equal 'purchases#fetch', @response.body
+ assert_equal '/purchases/315004be7e/Ruby_on_Rails_3.pdf', purchase_path(:token => '315004be7e', :filename => 'Ruby_on_Rails_3.pdf')
+ end
+
+ def test_nested_resource_constraints
+ get '/lists/01234012340123401234fffff'
+ assert_equal 'lists#show', @response.body
+ assert_equal '/lists/01234012340123401234fffff', list_path(:id => '01234012340123401234fffff')
+
+ get '/lists/01234012340123401234fffff/todos/1'
+ assert_equal 'todos#show', @response.body
+ assert_equal '/lists/01234012340123401234fffff/todos/1', list_todo_path(:list_id => '01234012340123401234fffff', :id => '1')
+
+ get '/lists/2/todos/1'
+ assert_equal 'Not Found', @response.body
+ assert_raises(ActionController::RoutingError){ list_todo_path(:list_id => '2', :id => '1') }
+ end
+
private
def with_test_routes
yield
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index fd801e2a9e..9a1fe01872 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -641,6 +641,18 @@ class FormHelperTest < ActionView::TestCase
assert_dom_equal expected, output_buffer
end
+ def test_form_for_with_format
+ form_for(@post, :format => :json, :html => { :id => "edit_post_123", :class => "edit_post" }) do |f|
+ concat f.label(:title)
+ end
+
+ expected = whole_form("/posts/123.json", "edit_post_123" , "edit_post", :method => "put") do
+ "<label for='post_title'>Title</label>"
+ end
+
+ assert_dom_equal expected, output_buffer
+ end
+
def test_form_for_with_symbol_object_name
form_for(@post, :as => "other_name", :html => { :id => 'create-post' }) do |f|
concat f.label(:title, :class => 'post_title')
@@ -1761,8 +1773,12 @@ class FormHelperTest < ActionView::TestCase
"/posts"
end
- def post_path(post)
- "/posts/#{post.id}"
+ def post_path(post, options = {})
+ if options[:format]
+ "/posts/#{post.id}.#{options[:format]}"
+ else
+ "/posts/#{post.id}"
+ end
end
def protect_against_forgery?
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb
index 229766612f..c17bec891b 100644
--- a/actionpack/test/template/render_test.rb
+++ b/actionpack/test/template/render_test.rb
@@ -69,8 +69,6 @@ module RenderTestCases
end
def test_render_update
- # TODO: You should not have to stub out template because template is self!
- @view.instance_variable_set(:@template, @view)
assert_equal 'alert("Hello, World!");', @view.render(:update) { |page| page.alert('Hello, World!') }
end
diff --git a/actionpack/test/template/url_helper_test.rb b/actionpack/test/template/url_helper_test.rb
index 19effbc82f..b76813c554 100644
--- a/actionpack/test/template/url_helper_test.rb
+++ b/actionpack/test/template/url_helper_test.rb
@@ -24,13 +24,6 @@ class UrlHelperTest < ActiveSupport::TestCase
include ActionView::Context
include RenderERBUtils
- # self.default_url_options = {:host => "www.example.com"}
-
- # TODO: This shouldn't be needed (see template.rb:53)
- def assigns
- {}
- end
-
def hash_for(opts = [])
ActiveSupport::OrderedHash[*([:controller, "foo", :action, "bar"].concat(opts))]
end
diff --git a/activemodel/lib/active_model/observing.rb b/activemodel/lib/active_model/observing.rb
index 2c2ff8f5d5..0d2dd36e59 100644
--- a/activemodel/lib/active_model/observing.rb
+++ b/activemodel/lib/active_model/observing.rb
@@ -34,6 +34,11 @@ module ActiveModel
@observers ||= []
end
+ # Gets the current observer instances.
+ def observer_instances
+ @observer_instances ||= []
+ end
+
# Instantiate the global Active Record observers.
def instantiate_observers
observers.each { |o| instantiate_observer(o) }
@@ -43,20 +48,17 @@ module ActiveModel
unless observer.respond_to? :update
raise ArgumentError, "observer needs to respond to `update'"
end
- @observer_instances ||= []
- @observer_instances << observer
+ observer_instances << observer
end
def notify_observers(*arg)
- if defined? @observer_instances
- for observer in @observer_instances
- observer.update(*arg)
- end
+ for observer in observer_instances
+ observer.update(*arg)
end
end
def count_observers
- @observer_instances.size
+ observer_instances.size
end
protected
diff --git a/activemodel/lib/active_model/serializers/xml.rb b/activemodel/lib/active_model/serializers/xml.rb
index 16ab8e7928..e89385e7e5 100644
--- a/activemodel/lib/active_model/serializers/xml.rb
+++ b/activemodel/lib/active_model/serializers/xml.rb
@@ -17,7 +17,7 @@ module ActiveModel
def initialize(name, serializable, raw_value=nil)
@name, @serializable = name, serializable
- @value = value || @serializable.send(name)
+ @value = raw_value || @serializable.send(name)
@type = compute_type
end
diff --git a/activemodel/lib/active_model/validations/confirmation.rb b/activemodel/lib/active_model/validations/confirmation.rb
index a31966d0c2..2c8a840124 100644
--- a/activemodel/lib/active_model/validations/confirmation.rb
+++ b/activemodel/lib/active_model/validations/confirmation.rb
@@ -4,9 +4,9 @@ module ActiveModel
module Validations
class ConfirmationValidator < EachValidator
def validate_each(record, attribute, value)
- confirmed = record.send(:"#{attribute}_confirmation")
- return if confirmed.nil? || value == confirmed
- record.errors.add(attribute, :confirmation, options)
+ if (confirmed = record.send("#{attribute}_confirmation")) && (value != confirmed)
+ record.errors.add(attribute, :confirmation, options)
+ end
end
def setup(klass)
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index c2d63cda23..395c72dfbc 100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -75,8 +75,8 @@ end
namespace :mysql do
desc 'Build the MySQL test databases'
task :build_databases do
- %x( echo "create DATABASE activerecord_unittest DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci " | mysql --user=#{MYSQL_DB_USER})
- %x( echo "create DATABASE activerecord_unittest2 DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci " | mysql --user=#{MYSQL_DB_USER})
+ %x( mysql --user=#{MYSQL_DB_USER} -e "create DATABASE activerecord_unittest DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci ")
+ %x( mysql --user=#{MYSQL_DB_USER} -e "create DATABASE activerecord_unittest2 DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci ")
end
desc 'Drop the MySQL test databases'
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index f465a38dbe..c3a34ae104 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -890,6 +890,10 @@ module ActiveRecord #:nodoc:
Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup
end
+ def before_remove_const #:nodoc:
+ reset_scoped_methods
+ end
+
private
def relation #:nodoc:
@@ -1174,6 +1178,10 @@ MSG
scoped_methods.last
end
+ def reset_scoped_methods #:nodoc:
+ Thread.current[:"#{self}_scoped_methods"] = nil
+ end
+
# Returns the class type of the record using the current module as a prefix. So descendants of
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
diff --git a/activerecord/lib/rails/generators/active_record.rb b/activerecord/lib/rails/generators/active_record.rb
index 5d8a8e81bc..26bc977e19 100644
--- a/activerecord/lib/rails/generators/active_record.rb
+++ b/activerecord/lib/rails/generators/active_record.rb
@@ -1,27 +1,19 @@
require 'rails/generators/named_base'
require 'rails/generators/migration'
require 'rails/generators/active_model'
+require 'rails/generators/active_record/migration'
require 'active_record'
module ActiveRecord
module Generators
class Base < Rails::Generators::NamedBase #:nodoc:
include Rails::Generators::Migration
+ extend ActiveRecord::Generators::Migration
# Set the current directory as base for the inherited generators.
def self.base_root
File.dirname(__FILE__)
end
-
- # Implement the required interface for Rails::Generators::Migration.
- def self.next_migration_number(dirname) #:nodoc:
- next_migration_number = current_migration_number(dirname) + 1
- if ActiveRecord::Base.timestamped_migrations
- [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
- else
- "%.3d" % next_migration_number
- end
- end
end
end
end
diff --git a/activerecord/lib/rails/generators/active_record/migration.rb b/activerecord/lib/rails/generators/active_record/migration.rb
new file mode 100644
index 0000000000..7f2f2e06a5
--- /dev/null
+++ b/activerecord/lib/rails/generators/active_record/migration.rb
@@ -0,0 +1,15 @@
+module ActiveRecord
+ module Generators
+ module Migration
+ # Implement the required interface for Rails::Generators::Migration.
+ def next_migration_number(dirname) #:nodoc:
+ next_migration_number = current_migration_number(dirname) + 1
+ if ActiveRecord::Base.timestamped_migrations
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
+ else
+ "%.3d" % next_migration_number
+ end
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 55f0b1ce21..d58e302cb2 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1415,6 +1415,21 @@ class BasicsTest < ActiveRecord::TestCase
end
end
+ def test_default_scope_is_reset
+ Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
+ UnloadablePost.table_name = 'posts'
+ UnloadablePost.class_eval do
+ default_scope order('posts.comments_count ASC')
+ end
+
+ UnloadablePost.unloadable
+ assert_not_nil Thread.current[:UnloadablePost_scoped_methods]
+ ActiveSupport::Dependencies.remove_unloadable_constants!
+ assert_nil Thread.current[:UnloadablePost_scoped_methods]
+ ensure
+ Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
+ end
+
protected
def with_env_tz(new_tz = 'US/Eastern')
old_tz, ENV['TZ'] = ENV['TZ'], new_tz
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index 01152b074f..9823d7aa0e 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -74,9 +74,9 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
ship = pirate.create_ship(:name => 'Nights Dirty Lightning')
- assert_no_difference('Ship.count') do
- pirate.update_attributes(:ship_attributes => { '_destroy' => true, :id => ship.id })
- end
+ pirate.update_attributes(:ship_attributes => { '_destroy' => true, :id => ship.id })
+
+ assert_nothing_raised(ActiveRecord::RecordNotFound) { pirate.ship.reload }
end
def test_a_model_should_respond_to_underscore_destroy_and_return_if_it_is_marked_for_destruction
@@ -194,28 +194,30 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
@pirate.ship.destroy
+
[1, '1', true, 'true'].each do |truth|
- @pirate.reload.create_ship(:name => 'Mister Pablo')
- assert_difference('Ship.count', -1) do
- @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => truth })
- end
+ ship = @pirate.reload.create_ship(:name => 'Mister Pablo')
+ @pirate.update_attributes(:ship_attributes => { :id => ship.id, :_destroy => truth })
+
+ assert_nil @pirate.reload.ship
+ assert_raise(ActiveRecord::RecordNotFound) { Ship.find(ship.id) }
end
end
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
[nil, '0', 0, 'false', false].each do |not_truth|
- assert_no_difference('Ship.count') do
- @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => not_truth })
- end
+ @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => not_truth })
+
+ assert_equal @ship, @pirate.reload.ship
end
end
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
- assert_no_difference('Ship.count') do
- @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => '1' })
- end
+ @pirate.update_attributes(:ship_attributes => { :id => @pirate.ship.id, :_destroy => '1' })
+
+ assert_equal @ship, @pirate.reload.ship
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
end
@@ -236,12 +238,15 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
end
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
- assert_no_difference('Ship.count') do
- @pirate.attributes = { :ship_attributes => { :id => @ship.id, :_destroy => '1' } }
- end
- assert_difference('Ship.count', -1) do
- @pirate.save
- end
+ @pirate.attributes = { :ship_attributes => { :id => @ship.id, :_destroy => '1' } }
+
+ assert !@pirate.ship.destroyed?
+ assert @pirate.ship.marked_for_destruction?
+
+ @pirate.save
+
+ assert @pirate.ship.destroyed?
+ assert_nil @pirate.reload.ship
end
def test_should_automatically_enable_autosave_on_the_association
@@ -254,29 +259,30 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true
@ship.delete
- assert_difference('Ship.count', 1) do
- @pirate.reload.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower' })
- end
+
+ @pirate.reload.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower' })
+
+ assert_not_nil @pirate.ship
end
def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
@ship.delete
@ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
- assert_no_difference('Ship.count') do
- @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower' })
- end
+ @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower' })
+
assert_equal 'Mayflower', @ship.reload.name
+ assert_equal @ship, @pirate.reload.ship
end
def test_should_update_existing_when_update_only_is_true_and_id_is_given
@ship.delete
@ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
- assert_no_difference('Ship.count') do
- @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id })
- end
+ @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id })
+
assert_equal 'Mayflower', @ship.reload.name
+ assert_equal @ship, @pirate.reload.ship
end
def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction
@@ -284,9 +290,11 @@ class TestNestedAttributesOnAHasOneAssociation < ActiveRecord::TestCase
@ship.delete
@ship = @pirate.create_update_only_ship(:name => 'Nights Dirty Lightning')
- assert_difference('Ship.count', -1) do
- @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id, :_destroy => true })
- end
+ @pirate.update_attributes(:update_only_ship_attributes => { :name => 'Mayflower', :id => @ship.id, :_destroy => true })
+
+ assert_nil @pirate.reload.ship
+ assert_raise(ActiveRecord::RecordNotFound) { Ship.find(@ship.id) }
+
Pirate.accepts_nested_attributes_for :update_only_ship, :update_only => true, :allow_destroy => false
end
@@ -375,27 +383,24 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy
@ship.pirate.destroy
[1, '1', true, 'true'].each do |truth|
- @ship.reload.create_pirate(:catchphrase => 'Arr')
- assert_difference('Pirate.count', -1) do
- @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => truth })
- end
+ pirate = @ship.reload.create_pirate(:catchphrase => 'Arr')
+ @ship.update_attributes(:pirate_attributes => { :id => pirate.id, :_destroy => truth })
+ assert_raise(ActiveRecord::RecordNotFound) { pirate.reload }
end
end
def test_should_not_destroy_an_existing_record_if_destroy_is_not_truthy
[nil, '0', 0, 'false', false].each do |not_truth|
- assert_no_difference('Pirate.count') do
- @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => not_truth })
- end
+ @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => not_truth })
+ assert_nothing_raised(ActiveRecord::RecordNotFound) { @ship.pirate.reload }
end
end
def test_should_not_destroy_an_existing_record_if_allow_destroy_is_false
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => false, :reject_if => proc { |attributes| attributes.empty? }
- assert_no_difference('Pirate.count') do
- @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => '1' })
- end
+ @ship.update_attributes(:pirate_attributes => { :id => @ship.pirate.id, :_destroy => '1' })
+ assert_nothing_raised(ActiveRecord::RecordNotFound) { @ship.pirate.reload }
Ship.accepts_nested_attributes_for :pirate, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
end
@@ -409,10 +414,12 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
end
def test_should_not_destroy_the_associated_model_until_the_parent_is_saved
- assert_no_difference('Pirate.count') do
- @ship.attributes = { :pirate_attributes => { :id => @ship.pirate.id, '_destroy' => true } }
- end
- assert_difference('Pirate.count', -1) { @ship.save }
+ pirate = @ship.pirate
+
+ @ship.attributes = { :pirate_attributes => { :id => pirate.id, '_destroy' => true } }
+ assert_nothing_raised(ActiveRecord::RecordNotFound) { Pirate.find(pirate.id) }
+ @ship.save
+ assert_raise(ActiveRecord::RecordNotFound) { Pirate.find(pirate.id) }
end
def test_should_automatically_enable_autosave_on_the_association
@@ -421,29 +428,28 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
def test_should_create_new_model_when_nothing_is_there_and_update_only_is_true
@pirate.delete
- assert_difference('Pirate.count', 1) do
- @ship.reload.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr' })
- end
+ @ship.reload.attributes = { :update_only_pirate_attributes => { :catchphrase => 'Arr' } }
+
+ assert @ship.update_only_pirate.new_record?
end
def test_should_update_existing_when_update_only_is_true_and_no_id_is_given
@pirate.delete
@pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
- assert_no_difference('Pirate.count') do
- @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr' })
- end
+ @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr' })
assert_equal 'Arr', @pirate.reload.catchphrase
+ assert_equal @pirate, @ship.reload.update_only_pirate
end
def test_should_update_existing_when_update_only_is_true_and_id_is_given
@pirate.delete
@pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
- assert_no_difference('Pirate.count') do
- @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id })
- end
+ @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id })
+
assert_equal 'Arr', @pirate.reload.catchphrase
+ assert_equal @pirate, @ship.reload.update_only_pirate
end
def test_should_destroy_existing_when_update_only_is_true_and_id_is_given_and_is_marked_for_destruction
@@ -451,9 +457,10 @@ class TestNestedAttributesOnABelongsToAssociation < ActiveRecord::TestCase
@pirate.delete
@pirate = @ship.create_update_only_pirate(:catchphrase => 'Aye')
- assert_difference('Pirate.count', -1) do
- @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id, :_destroy => true })
- end
+ @ship.update_attributes(:update_only_pirate_attributes => { :catchphrase => 'Arr', :id => @pirate.id, :_destroy => true })
+
+ assert_raise(ActiveRecord::RecordNotFound) { @pirate.reload }
+
Ship.accepts_nested_attributes_for :update_only_pirate, :update_only => true, :allow_destroy => false
end
end
diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb
index aa75aa27d4..be038bfa74 100644
--- a/activerecord/test/cases/relations_test.rb
+++ b/activerecord/test/cases/relations_test.rb
@@ -521,7 +521,7 @@ class RelationTest < ActiveRecord::TestCase
posts = Post.scoped
assert_equal [0], posts.select('comments_count').where('id is not null').group('id').order('id').count.values.uniq
- assert_equal 7, posts.where('id is not null').select('comments_count').count
+ assert_equal 0, posts.where('id is not null').select('comments_count').count
assert_equal 7, posts.select('comments_count').count('id')
assert_equal 0, posts.select('comments_count').count
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 7657e00800..ea62833d81 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -233,7 +233,7 @@ ActiveRecord::Schema.define do
end
create_table :items, :force => true do |t|
- t.column :name, :integer
+ t.column :name, :string
end
create_table :inept_wizards, :force => true do |t|
@@ -343,8 +343,8 @@ ActiveRecord::Schema.define do
t.decimal :my_house_population, :precision => 2, :scale => 0
t.decimal :decimal_number_with_default, :precision => 3, :scale => 2, :default => 2.78
t.float :temperature
- # Oracle supports precision up to 38
- if current_adapter?(:OracleAdapter)
+ # Oracle/SQLServer supports precision up to 38
+ if current_adapter?(:OracleAdapter,:SQLServerAdapter)
t.decimal :atoms_in_universe, :precision => 38, :scale => 0
else
t.decimal :atoms_in_universe, :precision => 55, :scale => 0
diff --git a/activeresource/test/cases/base_test.rb b/activeresource/test/cases/base_test.rb
index 91b375681b..77135be146 100644
--- a/activeresource/test/cases/base_test.rb
+++ b/activeresource/test/cases/base_test.rb
@@ -1041,6 +1041,12 @@ class BaseTest < Test::Unit::TestCase
ensure
Person.element_name = old_elem_name
end
+
+ def test_to_xml_with_private_method_name_as_attribute
+ assert_nothing_raised(ArgumentError) {
+ Customer.new(:test => true).to_xml
+ }
+ end
def test_to_json
Person.include_root_in_json = true
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 84cdc22e40..383cdbb52f 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,6 +1,6 @@
*Rails 3.1.0 (unreleased)*
-* No changes
+* Added before_remove_const callback to ActiveSupport::Dependencies.remove_unloadable_constants! [Andrew White]
*Rails 3.0.0 (August 29, 2010)*
diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb
index 40a1866428..3a7652f5bf 100644
--- a/activesupport/lib/active_support/core_ext/module/delegation.rb
+++ b/activesupport/lib/active_support/core_ext/module/delegation.rb
@@ -113,7 +113,7 @@ class Module
raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
end
- prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"
+ prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" || ''
file, line = caller.first.split(':', 2)
line = line.to_i
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index e6170b2daf..4bd97d3ee3 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -511,7 +511,12 @@ module ActiveSupport #:nodoc:
end
# Remove the constants that have been autoloaded, and those that have been
- # marked for unloading.
+ # marked for unloading. Before each constant is removed a callback is sent
+ # to its class/module if it implements +before_remove_const+.
+ #
+ # The callback implementation should be restricted to cleaning up caches, etc.
+ # as the enviroment will be in an inconsistent state, e.g. other constants
+ # may have already been unloaded and not accessible.
def remove_unloadable_constants!
autoloaded_constants.each { |const| remove_constant const }
autoloaded_constants.clear
@@ -636,6 +641,7 @@ module ActiveSupport #:nodoc:
parent = Inflector.constantize(names * '::')
log "removing constant #{const}"
+ constantize(const).before_remove_const if constantize(const).respond_to?(:before_remove_const)
parent.instance_eval { remove_const to_remove }
return true
diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb
index a535e2b668..de3ded1e1f 100644
--- a/activesupport/lib/active_support/duration.rb
+++ b/activesupport/lib/active_support/duration.rb
@@ -99,7 +99,7 @@ module ActiveSupport
private
def method_missing(method, *args, &block) #:nodoc:
- value.send(method, *args)
+ value.send(method, *args, &block)
end
end
end
diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb
index 8469f78566..b6456f0a30 100644
--- a/activesupport/test/core_ext/duration_test.rb
+++ b/activesupport/test/core_ext/duration_test.rb
@@ -129,6 +129,14 @@ class DurationTest < ActiveSupport::TestCase
assert_equal Time.local(2009,3,29,0,0,0) + 1.day, Time.local(2009,3,30,0,0,0)
end
end
+
+ def test_delegation_with_block_works
+ counter = 0
+ assert_nothing_raised do
+ 1.minute.times {counter += 1}
+ end
+ assert_equal counter, 60
+ end
protected
def with_env_tz(new_tz = 'US/Eastern')
diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb
index 5d9cdf22c2..75404ec0e1 100644
--- a/activesupport/test/core_ext/module_test.rb
+++ b/activesupport/test/core_ext/module_test.rb
@@ -47,6 +47,14 @@ Project = Struct.new(:description, :person) do
delegate :to_f, :to => :description, :allow_nil => true
end
+Developer = Struct.new(:client) do
+ delegate :name, :to => :client, :prefix => nil
+end
+
+Tester = Struct.new(:client) do
+ delegate :name, :to => :client, :prefix => false
+end
+
class Name
delegate :upcase, :to => :@full_name
@@ -97,6 +105,11 @@ class ModuleTest < Test::Unit::TestCase
assert_equal invoice.customer_city, "Chicago"
end
+ def test_delegation_prefix_with_nil_or_false
+ assert_equal Developer.new(@david).name, "David"
+ assert_equal Tester.new(@david).name, "David"
+ end
+
def test_delegation_prefix_with_instance_variable
assert_raise ArgumentError do
Class.new do
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index 77b885dc3d..bc7f597f1d 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -574,6 +574,17 @@ class DependenciesTest < Test::Unit::TestCase
end
end
+ def test_unloadable_constants_should_receive_callback
+ Object.const_set :C, Class.new
+ C.unloadable
+ C.expects(:before_remove_const).once
+ assert C.respond_to?(:before_remove_const)
+ ActiveSupport::Dependencies.clear
+ assert !defined?(C)
+ ensure
+ Object.class_eval { remove_const :C } if defined?(C)
+ end
+
def test_new_contants_in_without_constants
assert_equal [], (ActiveSupport::Dependencies.new_constants_in(Object) { })
assert ActiveSupport::Dependencies.constant_watch_stack.all? {|k,v| v.empty? }
diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb
index 855467227b..8fd2aa0bce 100644
--- a/railties/lib/rails/application/finisher.rb
+++ b/railties/lib/rails/application/finisher.rb
@@ -46,6 +46,13 @@ module Rails
ActiveSupport.run_load_hooks(:after_initialize, self)
end
+ # Force routes to be loaded just at the end and add it to to_prepare callbacks
+ initializer :set_routes_reloader do |app|
+ reloader = lambda { app.routes_reloader.execute_if_updated }
+ reloader.call
+ ActionDispatch::Callbacks.to_prepare(&reloader)
+ end
+
# Disable dependency loading during request cycle
initializer :disable_dependency_loading do
if config.cache_classes && !config.dependency_loading
diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb
index 834a120c01..de2f190ad5 100644
--- a/railties/lib/rails/commands/console.rb
+++ b/railties/lib/rails/commands/console.rb
@@ -48,5 +48,5 @@ end
# Has to set the RAILS_ENV before config/application is required
if ARGV.first && !ARGV.first.index("-") && env = ARGV.pop # has to pop the env ARGV so IRB doesn't freak
- ENV['RAILS_ENV'] = %w(production development test).find { |e| e.index(env) } || env
+ ENV['RAILS_ENV'] = %w(production development test).detect {|e| e =~ /^#{env}/} || env
end
diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb
index 3b9fff2f4a..64273e4ca4 100644
--- a/railties/lib/rails/generators/generated_attribute.rb
+++ b/railties/lib/rails/generators/generated_attribute.rb
@@ -6,6 +6,7 @@ module Rails
attr_accessor :name, :type
def initialize(name, type)
+ raise Thor::Error, "Missing type for attribute '#{name}'.\nExample: '#{name}:string' where string is the type." if type.blank?
@name, @type = name, type.to_sym
end
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 3a8a63a2f9..d553c09484 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -23,8 +23,9 @@ gem '<%= gem_for_database %>'<% if require_for_database %>, :require => '<%= req
# Deploy with Capistrano
# gem 'capistrano'
-# To use debugger
+# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+)
# gem 'ruby-debug'
+# gem 'ruby-debug19'
# Bundle the extra gems:
# gem 'bj'
diff --git a/railties/test/application/rackup_test.rb b/railties/test/application/rackup_test.rb
index 863950c04f..b0a9925890 100644
--- a/railties/test/application/rackup_test.rb
+++ b/railties/test/application/rackup_test.rb
@@ -31,13 +31,6 @@ module ApplicationTests
assert_kind_of Rails::Application, Rails.application
end
- # Passenger still uses AC::Dispatcher, so we need to
- # keep it working for now
- test "deprecated ActionController::Dispatcher still works" do
- rackup
- assert_kind_of Rails::Application, ActionController::Dispatcher.new
- end
-
test "the config object is available on the application object" do
rackup
assert_equal 'UTC', Rails.application.config.time_zone
diff --git a/railties/test/application/routing_test.rb b/railties/test/application/routing_test.rb
index febc53bac9..53bb7868da 100644
--- a/railties/test/application/routing_test.rb
+++ b/railties/test/application/routing_test.rb
@@ -215,6 +215,23 @@ module ApplicationTests
end
end
+ test 'routes are loaded just after initialization' do
+ require "#{app_path}/config/application"
+
+ ActiveSupport.on_load(:after_initialize) do
+ ::InitializeRackApp = lambda { |env| [200, {}, ["InitializeRackApp"]] }
+ end
+
+ app_file 'config/routes.rb', <<-RUBY
+ AppTemplate::Application.routes.draw do |map|
+ match 'foo', :to => ::InitializeRackApp
+ end
+ RUBY
+
+ get '/foo'
+ assert_equal "InitializeRackApp", last_response.body
+ end
+
test 'resource routing with irrigular inflection' do
app_file 'config/initializers/inflection.rb', <<-RUBY
ActiveSupport::Inflector.inflections do |inflect|
diff --git a/railties/test/generators/generated_attribute_test.rb b/railties/test/generators/generated_attribute_test.rb
index de7e4de2a6..272e179fe3 100644
--- a/railties/test/generators/generated_attribute_test.rb
+++ b/railties/test/generators/generated_attribute_test.rb
@@ -108,4 +108,16 @@ class GeneratedAttributeTest < Rails::Generators::TestCase
)
end
end
+
+ def test_nil_type_raises_exception
+ assert_raise Thor::Error do
+ create_generated_attribute(nil, 'title')
+ end
+ end
+
+ def test_missing_type_raises_exception
+ assert_raise Thor::Error do
+ create_generated_attribute(:'', 'title')
+ end
+ end
end
diff --git a/railties/test/generators/model_generator_test.rb b/railties/test/generators/model_generator_test.rb
index ef415a4fed..f4a9a152c9 100644
--- a/railties/test/generators/model_generator_test.rb
+++ b/railties/test/generators/model_generator_test.rb
@@ -11,6 +11,12 @@ class ModelGeneratorTest < Rails::Generators::TestCase
assert_match /TestUnit options:/, content
end
+ def test_model_with_missing_attribute_type
+ content = capture(:stderr) { run_generator ["post", "title:string", "body"] }
+ assert_match /Missing type for attribute 'body'/, content
+ assert_match /Example: 'body:string' where string is the type/, content
+ end
+
def test_invokes_default_orm
run_generator
assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/
diff --git a/railties/test/generators/scaffold_generator_test.rb b/railties/test/generators/scaffold_generator_test.rb
index f12445ae35..446bed3269 100644
--- a/railties/test/generators/scaffold_generator_test.rb
+++ b/railties/test/generators/scaffold_generator_test.rb
@@ -231,4 +231,10 @@ class ScaffoldGeneratorTest < Rails::Generators::TestCase
assert_file "config/routes.rb", /\.routes\.draw do\s*\|map\|\s*$/
end
+
+ def test_scaffold_generator_outputs_error_message_on_missing_attribute_type
+ content = capture(:stderr) { run_generator ["post", "title:string", "body"]}
+ assert_match /Missing type for attribute 'body'/, content
+ assert_match /Example: 'body:string' where string is the type/, content
+ end
end