diff options
54 files changed, 393 insertions, 222 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 1ffb7f32a0..0dafef90ae 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -26,6 +26,8 @@ This is a behavior change, previously the hidden tag had a value of the disabled checkbox. *Tadas Tamosauskas* +* `favicon_link_tag` helper will now use the favicon in app/assets by default. *Lucas Caton* + ## Rails 3.2.0 (January 20, 2012) ## * Add `config.action_dispatch.default_charset` to configure default charset for ActionDispatch::Response. *Carlos Antonio da Silva* diff --git a/actionpack/Rakefile b/actionpack/Rakefile index effb6badfc..bb1e704767 100755 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -55,15 +55,15 @@ end task :lines do lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 - for file_name in FileList["lib/**/*.rb"] + FileList["lib/**/*.rb"].each do |file_name| next if file_name =~ /vendor/ - f = File.open(file_name) - - while line = f.gets - lines += 1 - next if line =~ /^\s*$/ - next if line =~ /^\s*#/ - codelines += 1 + File.open(file_name, 'r') do |f| + while line = f.gets + lines += 1 + next if line =~ /^\s*$/ + next if line =~ /^\s*#/ + codelines += 1 + end end puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}" diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index f4eaa2fd1b..a0c54dbd84 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -40,7 +40,6 @@ module ActionController autoload :Integration, 'action_controller/deprecated/integration_test' autoload :IntegrationTest, 'action_controller/deprecated/integration_test' autoload :PerformanceTest, 'action_controller/deprecated/performance_test' - autoload :UrlWriter, 'action_controller/deprecated' autoload :Routing, 'action_controller/deprecated' autoload :TestCase, 'action_controller/test_case' autoload :TemplateAssertions, 'action_controller/test_case' diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb index 3da4f91051..a6b3aee5e7 100644 --- a/actionpack/lib/action_dispatch/http/mime_types.rb +++ b/actionpack/lib/action_dispatch/http/mime_types.rb @@ -9,7 +9,7 @@ Mime::Type.register "text/calendar", :ics Mime::Type.register "text/csv", :csv Mime::Type.register "image/png", :png, [], %w(png) -Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe) +Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg) Mime::Type.register "image/gif", :gif, [], %w(gif) Mime::Type.register "image/bmp", :bmp, [], %w(bmp) Mime::Type.register "image/tiff", :tiff, [], %w(tif tiff) diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index e2d7a29079..a17a39bed3 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -491,7 +491,7 @@ module ActionDispatch map_method(:put, args, &block) end - # Define a route that only recognizes HTTP PUT. + # Define a route that only recognizes HTTP DELETE. # For supported arguments, see <tt>Base#match</tt>. # # Example: diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb index 4d963803e6..33796008bd 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb @@ -417,8 +417,8 @@ module ActionDispatch deliveries = ActionMailer::Base.deliveries assert !deliveries.empty?, "No e-mail in delivery list" - for delivery in deliveries - for part in (delivery.parts.empty? ? [delivery] : delivery.parts) + deliveries.each do |delivery| + (delivery.parts.empty? ? [delivery] : delivery.parts).each do |part| if part["Content-Type"].to_s =~ /^text\/html\W/ root = HTML::Document.new(part.body.to_s).root assert_select root, ":root", &block diff --git a/actionpack/lib/action_view/helpers/asset_tag_helper.rb b/actionpack/lib/action_view/helpers/asset_tag_helper.rb index 280e51549e..40a950c644 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helper.rb @@ -234,7 +234,7 @@ module ActionView # # generates # - # <link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" /> + # <link href="/assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" /> # # You may specify a different file in the first argument: # @@ -252,7 +252,7 @@ module ActionView # # <%= favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png' %> # - def favicon_link_tag(source='/favicon.ico', options={}) + def favicon_link_tag(source='favicon.ico', options={}) tag('link', { :rel => 'shortcut icon', :type => 'image/vnd.microsoft.icon', diff --git a/actionpack/lib/action_view/helpers/date_helper.rb b/actionpack/lib/action_view/helpers/date_helper.rb index ea71889519..2d37923825 100644 --- a/actionpack/lib/action_view/helpers/date_helper.rb +++ b/actionpack/lib/action_view/helpers/date_helper.rb @@ -508,7 +508,7 @@ module ActionView # Returns a select tag with options for each of the days 1 through 31 with the current day selected. # The <tt>date</tt> can also be substituted for a day number. - # If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true. + # If you want to display days with a leading zero set the <tt>:use_two_digit_numbers</tt> key in +options+ to true. # Override the field name using the <tt>:field_name</tt> option, 'day' by default. # # ==== Examples @@ -854,7 +854,7 @@ module ActionView end def translated_date_order - date_order = I18n.translate(:'date.order', :locale => @options[:locale]) || [] + date_order = I18n.translate(:'date.order', :locale => @options[:locale], :default => []) forbidden_elements = date_order - [:year, :month, :day] if forbidden_elements.any? @@ -990,18 +990,12 @@ module ActionView # Returns the separator for a given datetime component. def separator(type) case type - when :year - @options[:discard_year] ? "" : @options[:date_separator] - when :month - @options[:discard_month] ? "" : @options[:date_separator] - when :day - @options[:discard_day] ? "" : @options[:date_separator] + when :year, :month, :day + @options[:"discard_#{type}"] ? "" : @options[:date_separator] when :hour (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator] - when :minute - @options[:discard_minute] ? "" : @options[:time_separator] - when :second - @options[:include_seconds] ? @options[:time_separator] : "" + when :minute, :second + @options[:"discard_#{type}"] ? "" : @options[:time_separator] end end end diff --git a/actionpack/lib/action_view/helpers/form_options_helper.rb b/actionpack/lib/action_view/helpers/form_options_helper.rb index c8811e3b10..c4cdfef4a2 100644 --- a/actionpack/lib/action_view/helpers/form_options_helper.rb +++ b/actionpack/lib/action_view/helpers/form_options_helper.rb @@ -334,7 +334,7 @@ module ActionView end.join("\n").html_safe end - # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning + # Returns a string of option tags that have been compiled by iterating over the +collection+ and assigning # the result of a call to the +value_method+ as the option value and the +text_method+ as the option text. # Example: # options_from_collection_for_select(@people, 'id', 'name') @@ -418,9 +418,9 @@ module ActionView # wrap the output in an appropriate <tt><select></tt> tag. def option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, selected_key = nil) collection.map do |group| - group_label_string = eval("group.#{group_label_method}") + group_label_string = group.send(group_label_method) "<optgroup label=\"#{ERB::Util.html_escape(group_label_string)}\">" + - options_from_collection_for_select(eval("group.#{group_method}"), option_key_method, option_value_method, selected_key) + + options_from_collection_for_select(group.send(group_method), option_key_method, option_value_method, selected_key) + '</optgroup>' end.join.html_safe end diff --git a/actionpack/lib/action_view/helpers/tags/collection_select.rb b/actionpack/lib/action_view/helpers/tags/collection_select.rb index f84140d8d0..ec78e6e5f9 100644 --- a/actionpack/lib/action_view/helpers/tags/collection_select.rb +++ b/actionpack/lib/action_view/helpers/tags/collection_select.rb @@ -12,9 +12,14 @@ module ActionView end def render - selected_value = @options.has_key?(:selected) ? @options[:selected] : value(@object) + option_tags_options = { + :selected => @options.fetch(:selected) { value(@object) }, + :disabled => @options[:disabled] + } + select_content_tag( - options_from_collection_for_select(@collection, @value_method, @text_method, :selected => selected_value, :disabled => @options[:disabled]), @options, @html_options + options_from_collection_for_select(@collection, @value_method, @text_method, option_tags_options), + @options, @html_options ) end end diff --git a/actionpack/lib/action_view/helpers/tags/select.rb b/actionpack/lib/action_view/helpers/tags/select.rb index 02b790db4e..53a108b7e6 100644 --- a/actionpack/lib/action_view/helpers/tags/select.rb +++ b/actionpack/lib/action_view/helpers/tags/select.rb @@ -11,21 +11,30 @@ module ActionView end def render - selected_value = @options.has_key?(:selected) ? @options[:selected] : value(@object) + option_tags_options = { + :selected => @options.fetch(:selected) { value(@object) }, + :disabled => @options[:disabled] + } - # Grouped choices look like this: - # - # [nil, []] - # { nil => [] } - # - if !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last - option_tags = grouped_options_for_select(@choices, :selected => selected_value, :disabled => @options[:disabled]) + option_tags = if grouped_choices? + grouped_options_for_select(@choices, option_tags_options) else - option_tags = options_for_select(@choices, :selected => selected_value, :disabled => @options[:disabled]) + options_for_select(@choices, option_tags_options) end select_content_tag(option_tags, @options, @html_options) end + + private + + # Grouped choices look like this: + # + # [nil, []] + # { nil => [] } + # + def grouped_choices? + !@choices.empty? && @choices.first.respond_to?(:last) && Array === @choices.first.last + end end end end diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index e231aade01..3033294883 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -85,8 +85,7 @@ module ActionView # == Rendering objects that respond to `to_partial_path` # # Instead of explicitly naming the location of a partial, you can also let PartialRenderer do the work - # and pick the proper path by checking `to_proper_path` method. If the object passed to render is a collection, - # all objects must return the same path. + # and pick the proper path by checking `to_partial_path` method. # # # @account.to_partial_path returns 'accounts/account', so it can be used to replace: # # <%= render :partial => "accounts/account", :locals => { :account => @account} %> diff --git a/actionpack/test/fixtures/developers.yml b/actionpack/test/fixtures/developers.yml index 308bf75de2..3656564f63 100644 --- a/actionpack/test/fixtures/developers.yml +++ b/actionpack/test/fixtures/developers.yml @@ -8,7 +8,7 @@ jamis: name: Jamis salary: 150000 -<% for digit in 3..10 %> +<% (3..10).each do |digit| %> dev_<%= digit %>: id: <%= digit %> name: fixture_<%= digit %> diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb index 3422a5efbd..90c2ca7a3d 100644 --- a/actionpack/test/template/asset_tag_helper_test.rb +++ b/actionpack/test/template/asset_tag_helper_test.rb @@ -168,7 +168,7 @@ class AssetTagHelperTest < ActionView::TestCase } FaviconLinkToTag = { - %(favicon_link_tag) => %(<link href="/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), + %(favicon_link_tag) => %(<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), %(favicon_link_tag 'favicon.ico') => %(<link href="/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon" />), %(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(<link href="/images/favicon.ico" rel="foo" type="image/vnd.microsoft.icon" />), %(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %(<link href="/images/favicon.ico" rel="foo" type="bar" />), diff --git a/actionpack/test/template/date_helper_i18n_test.rb b/actionpack/test/template/date_helper_i18n_test.rb index ef3d7d97ee..82b62e64f3 100644 --- a/actionpack/test/template/date_helper_i18n_test.rb +++ b/actionpack/test/template/date_helper_i18n_test.rb @@ -103,7 +103,7 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase I18n.expects(:translate).with(('datetime.prompts.' + key.to_s).to_sym, :locale => 'en').returns prompt end - I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:year, :month, :day] + I18n.expects(:translate).with(:'date.order', :locale => 'en', :default => []).returns [:year, :month, :day] datetime_select('post', 'updated_at', :locale => 'en', :include_seconds => true, :prompt => true) end @@ -115,12 +115,12 @@ class DateHelperSelectTagsI18nTests < ActiveSupport::TestCase end def test_date_or_time_select_given_no_order_options_translates_order - I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:year, :month, :day] + I18n.expects(:translate).with(:'date.order', :locale => 'en', :default => []).returns [:year, :month, :day] datetime_select('post', 'updated_at', :locale => 'en') end def test_date_or_time_select_given_invalid_order - I18n.expects(:translate).with(:'date.order', :locale => 'en').returns [:invalid, :month, :day] + I18n.expects(:translate).with(:'date.order', :locale => 'en', :default => []).returns [:invalid, :month, :day] assert_raise StandardError do datetime_select('post', 'updated_at', :locale => 'en') diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index b45aba6bb1..e9e97f5d62 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,5 +1,24 @@ ## Rails 4.0.0 (unreleased) ## +* Added deprecation for the `:dependent => :restrict` association option. + + Please note: + + * Up until now `has_many` and `has_one`, `:dependent => :restrict` + option raised a `DeleteRestrictionError` at the time of destroying + the object. Instead, it will add an error on the model. + + * To fix this warning, make sure your code isn't relying on a + `DeleteRestrictionError` and then add + `config.active_record.dependent_restrict_raises = false` to your + application config. + + * New rails application would be generated with the + `config.active_record.dependent_restrict_raises = false` in the + application config. + + *Manoj Kumar* + * Added `create_join_table` migration helper to create HABTM join tables create_join_table :products, :categories diff --git a/activerecord/Rakefile b/activerecord/Rakefile index d769a73dba..98020ad3ab 100755 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -187,15 +187,15 @@ end task :lines do lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 - for file_name in FileList["lib/active_record/**/*.rb"] + FileList["lib/active_record/**/*.rb"].each do |file_name| next if file_name =~ /vendor/ - f = File.open(file_name) - - while line = f.gets - lines += 1 - next if line =~ /^\s*$/ - next if line =~ /^\s*#/ - codelines += 1 + File.open(file_name, 'r') do |f| + while line = f.gets + lines += 1 + next if line =~ /^\s*$/ + next if line =~ /^\s*#/ + codelines += 1 + end end puts "L: #{sprintf("%4d", lines)}, LOC #{sprintf("%4d", codelines)} | #{file_name}" diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 58725246c8..958821add6 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1097,8 +1097,8 @@ module ActiveRecord # alongside this object by calling their +destroy+ method. If set to <tt>:delete_all</tt> all associated # objects are deleted *without* calling their +destroy+ method. If set to <tt>:nullify</tt> all associated # objects' foreign keys are set to +NULL+ *without* calling their +save+ callbacks. If set to - # <tt>:restrict</tt> this object raises an <tt>ActiveRecord::DeleteRestrictionError</tt> exception and - # cannot be deleted if it has any associated objects. + # <tt>:restrict</tt> an error will be added to the object, preventing its deletion, if any associated + # objects are present. # # If using with the <tt>:through</tt> option, the association on the join model must be # a +belongs_to+, and the records which get deleted are the join records, rather than @@ -1251,8 +1251,8 @@ module ActiveRecord # If set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. # If set to <tt>:nullify</tt>, the associated object's foreign key is set to +NULL+. - # Also, association is assigned. If set to <tt>:restrict</tt> this object raises an - # <tt>ActiveRecord::DeleteRestrictionError</tt> exception and cannot be deleted if it has any associated object. + # If set to <tt>:restrict</tt>, an error will be added to the object, preventing its deletion, if an + # associated object is present. # [:foreign_key] # Specify the foreign key used for the association. By default this is guessed to be the name # of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb index 6e2e5f9de0..666926ff51 100644 --- a/activerecord/lib/active_record/associations/builder/association.rb +++ b/activerecord/lib/active_record/associations/builder/association.rb @@ -51,5 +51,34 @@ module ActiveRecord::Associations::Builder association(name).writer(value) end end - end + + def dependent_restrict_raises? + ActiveRecord::Base.dependent_restrict_raises == true + end + + def dependent_restrict_deprecation_warning + if dependent_restrict_raises? + msg = "In the next release, `:dependent => :restrict` will not raise a `DeleteRestrictionError`. "\ + "Instead, it will add an error on the model. To fix this warning, make sure your code " \ + "isn't relying on a `DeleteRestrictionError` and then add " \ + "`config.active_record.dependent_restrict_raises = false` to your application config." + ActiveSupport::Deprecation.warn msg + end + end + + def define_restrict_dependency_method + name = self.name + mixin.redefine_method(dependency_method_name) do + # has_many or has_one associations + if send(name).respond_to?(:exists?) ? send(name).exists? : !send(name).nil? + if dependent_restrict_raises? + raise ActiveRecord::DeleteRestrictionError.new(name) + else + errors.add(:base, :restrict_dependent_destroy, :model => name.to_s.singularize) + return false + end + end + end + end + end end diff --git a/activerecord/lib/active_record/associations/builder/has_many.rb b/activerecord/lib/active_record/associations/builder/has_many.rb index fc6799fb15..9ddfd433e4 100644 --- a/activerecord/lib/active_record/associations/builder/has_many.rb +++ b/activerecord/lib/active_record/associations/builder/has_many.rb @@ -21,6 +21,7 @@ module ActiveRecord::Associations::Builder ":nullify or :restrict (#{options[:dependent].inspect})" end + dependent_restrict_deprecation_warning if options[:dependent] == :restrict send("define_#{options[:dependent]}_dependency_method") model.before_destroy dependency_method_name end @@ -52,13 +53,6 @@ module ActiveRecord::Associations::Builder end end - def define_restrict_dependency_method - name = self.name - mixin.redefine_method(dependency_method_name) do - raise ActiveRecord::DeleteRestrictionError.new(name) unless send(name).empty? - end - end - def dependency_method_name "has_many_dependent_for_#{name}" end diff --git a/activerecord/lib/active_record/associations/builder/has_one.rb b/activerecord/lib/active_record/associations/builder/has_one.rb index 7a6cd3890f..bc8a212bee 100644 --- a/activerecord/lib/active_record/associations/builder/has_one.rb +++ b/activerecord/lib/active_record/associations/builder/has_one.rb @@ -34,15 +34,12 @@ module ActiveRecord::Associations::Builder ":nullify or :restrict (#{options[:dependent].inspect})" end + dependent_restrict_deprecation_warning if options[:dependent] == :restrict send("define_#{options[:dependent]}_dependency_method") model.before_destroy dependency_method_name end end - def dependency_method_name - "has_one_dependent_#{options[:dependent]}_for_#{name}" - end - def define_destroy_dependency_method name = self.name mixin.redefine_method(dependency_method_name) do @@ -52,11 +49,8 @@ module ActiveRecord::Associations::Builder alias :define_delete_dependency_method :define_destroy_dependency_method alias :define_nullify_dependency_method :define_destroy_dependency_method - def define_restrict_dependency_method - name = self.name - mixin.redefine_method(dependency_method_name) do - raise ActiveRecord::DeleteRestrictionError.new(name) unless send(name).nil? - end + def dependency_method_name + "has_one_dependent_#{options[:dependent]}_for_#{name}" end end end diff --git a/activerecord/lib/active_record/associations/collection_association.rb b/activerecord/lib/active_record/associations/collection_association.rb index 7aed64d48c..b2136605e1 100644 --- a/activerecord/lib/active_record/associations/collection_association.rb +++ b/activerecord/lib/active_record/associations/collection_association.rb @@ -58,7 +58,7 @@ module ActiveRecord end end - relation.uniq.pluck(column) + relation.pluck(column) end end diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index 27ff13ad89..52f09efd53 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -69,7 +69,7 @@ module ActiveRecord result = if @query_cache[sql].key?(binds) ActiveSupport::Notifications.instrument("sql.active_record", - :sql => sql, :name => "CACHE", :connection_id => object_id) + :sql => sql, :binds => binds, :name => "CACHE", :connection_id => object_id) @query_cache[sql][binds] else @query_cache[sql][binds] = yield diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 201c05d8f5..9d9dbcc355 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -505,7 +505,7 @@ module ActiveRecord execute_and_free("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA') do |result| create_table = each_hash(result).first[:"Create Table"] if create_table.to_s =~ /PRIMARY KEY\s+\((.+)\)/ - keys = $1.split(",").map { |key| key.gsub(/`/, "") } + keys = $1.split(",").map { |key| key.gsub(/[`"]/, "") } keys.length == 1 ? [keys.first, nil] : nil else nil diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index a774af6024..a2ce620354 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -72,6 +72,16 @@ module ActiveRecord # The connection handler config_attribute :connection_handler self.connection_handler = ConnectionAdapters::ConnectionHandler.new + + ## + # :singleton-method: + # Specifies wether or not has_many or has_one association option + # :dependent => :restrict raises an exception. If set to true, the + # ActiveRecord::DeleteRestrictionError exception will be raised + # along with a DEPRECATION WARNING. If set to false, an error would + # be added to the model instead. + config_attribute :dependent_restrict_raises, :global => true + self.dependent_restrict_raises = true end module ClassMethods diff --git a/activerecord/lib/active_record/dynamic_finder_match.rb b/activerecord/lib/active_record/dynamic_finder_match.rb index b309df9b1b..38dbbef5fc 100644 --- a/activerecord/lib/active_record/dynamic_finder_match.rb +++ b/activerecord/lib/active_record/dynamic_finder_match.rb @@ -6,33 +6,23 @@ module ActiveRecord # class DynamicFinderMatch def self.match(method) - finder = :first - bang = false - instantiator = nil - - case method.to_s - when /^find_(all_|last_)?by_([_a-zA-Z]\w*)$/ - finder = :last if $1 == 'last_' - finder = :all if $1 == 'all_' - names = $2 - when /^find_by_([_a-zA-Z]\w*)\!$/ - bang = true - names = $1 - when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/ - instantiator = $1 == 'initialize' ? :new : :create - names = $2 - else - return nil + method = method.to_s + klass = [FindBy, FindByBang, FindOrInitializeCreateBy].find do |_klass| + _klass.matches?(method) end + klass.new(method) if klass + end - new(finder, instantiator, bang, names.split('_and_')) + def self.matches?(method) + method =~ self::METHOD_PATTERN end - def initialize(finder, instantiator, bang, attribute_names) - @finder = finder - @instantiator = instantiator - @bang = bang - @attribute_names = attribute_names + def initialize(method) + @finder = :first + @instantiator = nil + match_data = method.match(self.class::METHOD_PATTERN) + @attribute_names = match_data[-1].split("_and_") + initialize_from_match_data(match_data) end attr_reader :finder, :attribute_names, :instantiator @@ -41,16 +31,54 @@ module ActiveRecord @finder && !@instantiator end + def creator? + @finder == :first && @instantiator == :create + end + def instantiator? - @finder == :first && @instantiator + @instantiator end - def creator? - @finder == :first && @instantiator == :create + def bang? + false + end + + def valid_arguments?(arguments) + arguments.size >= @attribute_names.size end + private + + def initialize_from_match_data(match_data) + end + end + + class FindBy < DynamicFinderMatch + METHOD_PATTERN = /^find_(all_|last_)?by_([_a-zA-Z]\w*)$/ + + def initialize_from_match_data(match_data) + @finder = :last if match_data[1] == 'last_' + @finder = :all if match_data[1] == 'all_' + end + end + + class FindByBang < DynamicFinderMatch + METHOD_PATTERN = /^find_by_([_a-zA-Z]\w*)\!$/ + def bang? - @bang + true + end + end + + class FindOrInitializeCreateBy < DynamicFinderMatch + METHOD_PATTERN = /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/ + + def initialize_from_match_data(match_data) + @instantiator = match_data[1] == 'initialize' ? :new : :create + end + + def valid_arguments?(arguments) + arguments.size == 1 && arguments.first.is_a?(Hash) || super end end end diff --git a/activerecord/lib/active_record/dynamic_matchers.rb b/activerecord/lib/active_record/dynamic_matchers.rb index b6b8e24436..60ce3dd4f1 100644 --- a/activerecord/lib/active_record/dynamic_matchers.rb +++ b/activerecord/lib/active_record/dynamic_matchers.rb @@ -25,7 +25,7 @@ module ActiveRecord if match = (DynamicFinderMatch.match(method_id) || DynamicScopeMatch.match(method_id)) attribute_names = match.attribute_names super unless all_attributes_exists?(attribute_names) - if !(match.is_a?(DynamicFinderMatch) && match.instantiator? && arguments.first.is_a?(Hash)) && arguments.size < attribute_names.size + unless match.valid_arguments?(arguments) method_trace = "#{__FILE__}:#{__LINE__}:in `#{method_id}'" backtrace = [method_trace] + caller raise ArgumentError, "wrong number of arguments (#{arguments.size} for #{attribute_names.size})", backtrace diff --git a/activerecord/lib/active_record/dynamic_scope_match.rb b/activerecord/lib/active_record/dynamic_scope_match.rb index c832e927d6..a502155aac 100644 --- a/activerecord/lib/active_record/dynamic_scope_match.rb +++ b/activerecord/lib/active_record/dynamic_scope_match.rb @@ -19,5 +19,9 @@ module ActiveRecord attr_reader :scope, :attribute_names alias :scope? :scope + + def valid_arguments?(arguments) + arguments.size >= @attribute_names.size + end end end diff --git a/activerecord/lib/active_record/locale/en.yml b/activerecord/lib/active_record/locale/en.yml index 44328f63b6..8892f7ef2f 100644 --- a/activerecord/lib/active_record/locale/en.yml +++ b/activerecord/lib/active_record/locale/en.yml @@ -10,6 +10,7 @@ en: messages: taken: "has already been taken" record_invalid: "Validation failed: %{errors}" + restrict_dependent_destroy: "Cannot delete record because dependent %{model} exists" # Append your own errors here or at the model/attributes scope. # You can define own errors for models or model attributes. diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index bf9b4bf1c9..6bf3050af9 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -333,7 +333,7 @@ module ActiveRecord def select_for_count if @select_values.present? select = @select_values.join(", ") - select if select !~ /(,|\*)/ + select if select !~ /[,*]/ end end diff --git a/activerecord/lib/active_record/validations/uniqueness.rb b/activerecord/lib/active_record/validations/uniqueness.rb index 3a741ba600..7fd5d76ba5 100644 --- a/activerecord/lib/active_record/validations/uniqueness.rb +++ b/activerecord/lib/active_record/validations/uniqueness.rb @@ -57,8 +57,7 @@ module ActiveRecord def build_relation(klass, table, attribute, value) #:nodoc: reflection = klass.reflect_on_association(attribute) - column = nil - if(reflection) + if reflection column = klass.columns_hash[reflection.foreign_key] attribute = reflection.foreign_key value = value.attributes[reflection.primary_key_column.name] diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index f1a341437f..ab1e821aab 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -1140,16 +1140,42 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_nil companies(:leetsoft).reload.client_of assert_nil companies(:jadedpixel).reload.client_of - assert_equal num_accounts, Account.count end def test_restrict - firm = RestrictedFirm.new(:name => 'restrict') - firm.save! + option_before = ActiveRecord::Base.dependent_restrict_raises + ActiveRecord::Base.dependent_restrict_raises = true + + firm = RestrictedFirm.create!(:name => 'restrict') firm.companies.create(:name => 'child') + assert !firm.companies.empty? assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } + assert RestrictedFirm.exists?(:name => 'restrict') + assert firm.companies.exists?(:name => 'child') + ensure + ActiveRecord::Base.dependent_restrict_raises = option_before + end + + def test_restrict_when_dependent_restrict_raises_config_set_to_false + option_before = ActiveRecord::Base.dependent_restrict_raises + ActiveRecord::Base.dependent_restrict_raises = false + + firm = RestrictedFirm.create!(:name => 'restrict') + firm.companies.create(:name => 'child') + + assert !firm.companies.empty? + + firm.destroy + + assert !firm.errors.empty? + + assert_equal "Cannot delete record because dependent company exists", firm.errors[:base].first + assert RestrictedFirm.exists?(:name => 'restrict') + assert firm.companies.exists?(:name => 'child') + ensure + ActiveRecord::Base.dependent_restrict_raises = option_before end def test_included_in_collection @@ -1253,6 +1279,10 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert company.clients_using_sql.loaded? end + def test_get_ids_for_ordered_association + assert_equal [companies(:second_client).id, companies(:first_client).id], companies(:first_firm).clients_ordered_by_name_ids + end + def test_assign_ids_ignoring_blanks firm = Firm.create!(:name => 'Apple') firm.client_ids = [companies(:first_client).id, nil, companies(:second_client).id, ''] @@ -1401,29 +1431,29 @@ 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_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_queries 0 do assert_equal 0, author.essays.size end end @@ -1649,4 +1679,16 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_equal [bulb2], car.bulbs assert_equal [bulb2], car.reload.bulbs end + + def test_building_has_many_association_with_restrict_dependency + option_before = ActiveRecord::Base.dependent_restrict_raises + ActiveRecord::Base.dependent_restrict_raises = true + + klass = Class.new(ActiveRecord::Base) + + assert_deprecated { klass.has_many :companies, :dependent => :restrict } + assert_not_deprecated { klass.has_many :companies } + ensure + ActiveRecord::Base.dependent_restrict_raises = option_before + end end diff --git a/activerecord/test/cases/associations/has_one_associations_test.rb b/activerecord/test/cases/associations/has_one_associations_test.rb index 26931e3e85..37be6a279d 100644 --- a/activerecord/test/cases/associations/has_one_associations_test.rb +++ b/activerecord/test/cases/associations/has_one_associations_test.rb @@ -157,11 +157,38 @@ class HasOneAssociationsTest < ActiveRecord::TestCase end def test_dependence_with_restrict - firm = RestrictedFirm.new(:name => 'restrict') - firm.save! + option_before = ActiveRecord::Base.dependent_restrict_raises + ActiveRecord::Base.dependent_restrict_raises = true + + firm = RestrictedFirm.create!(:name => 'restrict') firm.create_account(:credit_limit => 10) + assert_not_nil firm.account + assert_raise(ActiveRecord::DeleteRestrictionError) { firm.destroy } + assert RestrictedFirm.exists?(:name => 'restrict') + assert firm.account.present? + ensure + ActiveRecord::Base.dependent_restrict_raises = option_before + end + + def test_dependence_with_restrict_with_dependent_restrict_raises_config_set_to_false + option_before = ActiveRecord::Base.dependent_restrict_raises + ActiveRecord::Base.dependent_restrict_raises = false + + firm = RestrictedFirm.create!(:name => 'restrict') + firm.create_account(:credit_limit => 10) + + assert_not_nil firm.account + + firm.destroy + + assert !firm.errors.empty? + assert_equal "Cannot delete record because dependent account exists", firm.errors[:base].first + assert RestrictedFirm.exists?(:name => 'restrict') + assert firm.account.present? + ensure + ActiveRecord::Base.dependent_restrict_raises = option_before end def test_successful_build_association @@ -456,4 +483,16 @@ class HasOneAssociationsTest < ActiveRecord::TestCase assert_equal car.id, bulb.attributes_after_initialize['car_id'] end + + def test_building_has_one_association_with_dependent_restrict + option_before = ActiveRecord::Base.dependent_restrict_raises + ActiveRecord::Base.dependent_restrict_raises = true + + klass = Class.new(ActiveRecord::Base) + + assert_deprecated { klass.has_one :account, :dependent => :restrict } + assert_not_deprecated { klass.has_one :account } + ensure + ActiveRecord::Base.dependent_restrict_raises = option_before + end end diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index 59d786622e..00a6d97928 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -1579,7 +1579,7 @@ class BasicsTest < ActiveRecord::TestCase Developer.find(:all) end assert developers.size >= 2 - for i in 1...developers.size + (1...developers.size).each do |i| assert developers[i-1].salary >= developers[i].salary end end diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index b4598ab32a..359cabd016 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -22,6 +22,9 @@ ActiveSupport::Deprecation.debug = true # Enable Identity Map only when ENV['IM'] is set to "true" ActiveRecord::IdentityMap.enabled = (ENV['IM'] == "true") +# Avoid deprecation warning setting dependent_restric_raises to false. The default is true +ActiveRecord::Base.dependent_restrict_raises = false + # Connect to the database ARTest.connect diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb index b4d1a631fa..e6e50a4cd4 100644 --- a/activerecord/test/cases/primary_keys_test.rb +++ b/activerecord/test/cases/primary_keys_test.rb @@ -200,3 +200,19 @@ class PrimaryKeyWithNoConnectionTest < ActiveRecord::TestCase assert_equal 'foo', model.primary_key end end + +if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter) + class PrimaryKeyWithAnsiQuotesTest < ActiveRecord::TestCase + self.use_transactional_fixtures = false + + def test_primaery_key_method_with_ansi_quotes + con = ActiveRecord::Base.connection + con.execute("SET SESSION sql_mode='ANSI_QUOTES'") + assert_equal "id", con.primary_key("topics") + ensure + con.reconnect! + end + + end +end + diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb index 297fb56570..16f05f2198 100644 --- a/activerecord/test/cases/reflection_test.rb +++ b/activerecord/test/cases/reflection_test.rb @@ -189,8 +189,8 @@ class ReflectionTest < ActiveRecord::TestCase def test_reflection_of_all_associations # FIXME these assertions bust a lot - assert_equal 38, Firm.reflect_on_all_associations.size - assert_equal 28, Firm.reflect_on_all_associations(:has_many).size + assert_equal 39, Firm.reflect_on_all_associations.size + assert_equal 29, Firm.reflect_on_all_associations(:has_many).size assert_equal 10, Firm.reflect_on_all_associations(:has_one).size assert_equal 0, Firm.reflect_on_all_associations(:belongs_to).size end diff --git a/activerecord/test/cases/serialization_test.rb b/activerecord/test/cases/serialization_test.rb index 31ba99a8ff..a4c065e667 100644 --- a/activerecord/test/cases/serialization_test.rb +++ b/activerecord/test/cases/serialization_test.rb @@ -25,7 +25,7 @@ class SerializationTest < ActiveRecord::TestCase end def test_serialize_should_be_reversible - for format in FORMATS + FORMATS.each do |format| @serialized = Contact.new.send("to_#{format}") contact = Contact.new.send("from_#{format}", @serialized) @@ -34,7 +34,7 @@ class SerializationTest < ActiveRecord::TestCase end def test_serialize_should_allow_attribute_only_filtering - for format in FORMATS + FORMATS.each do |format| @serialized = Contact.new(@contact_attributes).send("to_#{format}", :only => [ :age, :name ]) contact = Contact.new.send("from_#{format}", @serialized) assert_equal @contact_attributes[:name], contact.name, "For #{format}" @@ -43,7 +43,7 @@ class SerializationTest < ActiveRecord::TestCase end def test_serialize_should_allow_attribute_except_filtering - for format in FORMATS + FORMATS.each do |format| @serialized = Contact.new(@contact_attributes).send("to_#{format}", :except => [ :age, :name ]) contact = Contact.new.send("from_#{format}", @serialized) assert_nil contact.name, "For #{format}" diff --git a/activerecord/test/fixtures/developers.yml b/activerecord/test/fixtures/developers.yml index 308bf75de2..3656564f63 100644 --- a/activerecord/test/fixtures/developers.yml +++ b/activerecord/test/fixtures/developers.yml @@ -8,7 +8,7 @@ jamis: name: Jamis salary: 150000 -<% for digit in 3..10 %> +<% (3..10).each do |digit| %> dev_<%= digit %>: id: <%= digit %> name: fixture_<%= digit %> diff --git a/activerecord/test/models/company.rb b/activerecord/test/models/company.rb index d1a8a82786..fbdfaa2c29 100644 --- a/activerecord/test/models/company.rb +++ b/activerecord/test/models/company.rb @@ -45,6 +45,7 @@ class Firm < Company has_many :unsorted_clients_with_symbol, :class_name => :Client has_many :clients_sorted_desc, :class_name => "Client", :order => "id DESC" has_many :clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id" + has_many :clients_ordered_by_name, :order => "name", :class_name => "Client" has_many :unvalidated_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :validate => false has_many :dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :destroy has_many :exclusively_dependent_clients_of_firm, :foreign_key => "client_of", :class_name => "Client", :order => "id", :dependent => :delete_all diff --git a/activeresource/Rakefile b/activeresource/Rakefile index b1c18ff189..042d9fb0c7 100755 --- a/activeresource/Rakefile +++ b/activeresource/Rakefile @@ -33,7 +33,7 @@ end task :lines do lines, codelines, total_lines, total_codelines = 0, 0, 0, 0 - for file_name in FileList["lib/active_resource/**/*.rb"] + FileList["lib/active_resource/**/*.rb"].each do |file_name| next if file_name =~ /vendor/ f = File.open(file_name) diff --git a/activeresource/test/cases/format_test.rb b/activeresource/test/cases/format_test.rb index 21fdc24832..30342ecc74 100644 --- a/activeresource/test/cases/format_test.rb +++ b/activeresource/test/cases/format_test.rb @@ -19,7 +19,7 @@ class FormatTest < ActiveSupport::TestCase end def test_formats_on_single_element - for format in [ :json, :xml ] + [ :json, :xml ].each do |format| using_format(Person, format) do ActiveResource::HttpMock.respond_to.get "/people/1.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@david) assert_equal @david[:name], Person.find(1).name @@ -28,7 +28,7 @@ class FormatTest < ActiveSupport::TestCase end def test_formats_on_collection - for format in [ :json, :xml ] + [ :json, :xml ].each do |format| using_format(Person, format) do ActiveResource::HttpMock.respond_to.get "/people.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@programmers) remote_programmers = Person.find(:all) @@ -39,7 +39,7 @@ class FormatTest < ActiveSupport::TestCase end def test_formats_on_custom_collection_method - for format in [ :json, :xml ] + [ :json, :xml ].each do |format| using_format(Person, format) do ActiveResource::HttpMock.respond_to.get "/people/retrieve.#{format}?name=David", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode([@david]) remote_programmers = Person.get(:retrieve, :name => 'David') diff --git a/activesupport/lib/active_support/testing/performance/ruby.rb b/activesupport/lib/active_support/testing/performance/ruby.rb index 26731c6bd7..b7a34ea279 100644 --- a/activesupport/lib/active_support/testing/performance/ruby.rb +++ b/activesupport/lib/active_support/testing/performance/ruby.rb @@ -86,9 +86,12 @@ module ActiveSupport end protected - # overridden by each implementation def with_gc_stats + GC::Profiler.enable + GC.start yield + ensure + GC::Profiler.disable end end @@ -124,27 +127,42 @@ module ActiveSupport class Memory < DigitalInformationUnit Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY) + + # Ruby 1.9 + GCdata patch + if GC.respond_to?(:malloc_allocated_size) + def measure + GC.malloc_allocated_size + end + end end class Objects < Amount Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS) + + # Ruby 1.9 + GCdata patch + if GC.respond_to?(:malloc_allocations) + def measure + GC.malloc_allocations + end + end end class GcRuns < Amount Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS) + + def measure + GC.count + end end class GcTime < Time Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME) + + def measure + GC::Profiler.total_time + end end end end end end - -if RUBY_VERSION.between?('1.9.2', '2.0') - require 'active_support/testing/performance/ruby/yarv' -else - $stderr.puts 'Update your ruby interpreter to be able to run benchmarks.' - exit -end diff --git a/activesupport/lib/active_support/testing/performance/ruby/yarv.rb b/activesupport/lib/active_support/testing/performance/ruby/yarv.rb deleted file mode 100644 index c34d31bf10..0000000000 --- a/activesupport/lib/active_support/testing/performance/ruby/yarv.rb +++ /dev/null @@ -1,48 +0,0 @@ -module ActiveSupport - module Testing - module Performance - module Metrics - class Base - protected - def with_gc_stats - GC::Profiler.enable - GC.start - yield - ensure - GC::Profiler.disable - end - end - - class Memory < DigitalInformationUnit - # Ruby 1.9 + GCdata patch - if GC.respond_to?(:malloc_allocated_size) - def measure - GC.malloc_allocated_size - end - end - end - - class Objects < Amount - # Ruby 1.9 + GCdata patch - if GC.respond_to?(:malloc_allocations) - def measure - GC.malloc_allocations - end - end - end - - class GcRuns < Amount - def measure - GC.count - end - end - - class GcTime < Time - def measure - GC::Profiler.total_time - end - end - end - end - end -end diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb index 6c222b83ba..dbb6c71907 100644 --- a/activesupport/lib/active_support/xml_mini/jdom.rb +++ b/activesupport/lib/active_support/xml_mini/jdom.rb @@ -71,7 +71,7 @@ module ActiveSupport child_nodes = element.child_nodes if child_nodes.length > 0 - for i in 0...child_nodes.length + (0...child_nodes.length).each do |i| child = child_nodes.item(i) merge_element!(hash, child) unless child.node_type == Node.TEXT_NODE end @@ -133,7 +133,7 @@ module ActiveSupport def get_attributes(element) attribute_hash = {} attributes = element.attributes - for i in 0...attributes.length + (0...attributes.length).each do |i| attribute_hash[CONTENT_KEY] ||= '' attribute_hash[attributes.item(i).name] = attributes.item(i).value end @@ -147,7 +147,7 @@ module ActiveSupport def texts(element) texts = [] child_nodes = element.child_nodes - for i in 0...child_nodes.length + (0...child_nodes.length).each do |i| item = child_nodes.item(i) if item.node_type == Node.TEXT_NODE texts << item.get_data @@ -163,7 +163,7 @@ module ActiveSupport def empty_content?(element) text = '' child_nodes = element.child_nodes - for i in 0...child_nodes.length + (0...child_nodes.length).each do |i| item = child_nodes.item(i) if item.node_type == Node.TEXT_NODE text << item.get_data.strip diff --git a/railties/lib/rails/code_statistics.rb b/railties/lib/rails/code_statistics.rb index 435ea83ad8..03538b2422 100644 --- a/railties/lib/rails/code_statistics.rb +++ b/railties/lib/rails/code_statistics.rb @@ -37,24 +37,26 @@ class CodeStatistics #:nodoc: next unless file_name =~ pattern - f = File.open(directory + "/" + file_name) comment_started = false - while line = f.gets - stats["lines"] += 1 - if(comment_started) - if line =~ /^=end/ - comment_started = false - end - next - else - if line =~ /^=begin/ - comment_started = true + + File.open(directory + "/" + file_name) do |f| + while line = f.gets + stats["lines"] += 1 + if(comment_started) + if line =~ /^=end/ + comment_started = false + end next + else + if line =~ /^=begin/ + comment_started = true + next + end end + stats["classes"] += 1 if line =~ /^\s*class\s+[_A-Z]/ + stats["methods"] += 1 if line =~ /^\s*def\s+[_a-z]/ + stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/ end - stats["classes"] += 1 if line =~ /^\s*class\s+[_A-Z]/ - stats["methods"] += 1 if line =~ /^\s*def\s+[_a-z]/ - stats["codelines"] += 1 unless line =~ /^\s*$/ || line =~ /^\s*#/ end end diff --git a/railties/lib/rails/generators/actions.rb b/railties/lib/rails/generators/actions.rb index 45f55a2a0a..32793b1a70 100644 --- a/railties/lib/rails/generators/actions.rb +++ b/railties/lib/rails/generators/actions.rb @@ -246,7 +246,7 @@ module Rails sentinel = /\.routes\.draw do\s*$/ in_root do - inject_into_file 'config/routes.rb', "\n #{routing_code}\n", { :after => sentinel, :verbose => false } + inject_into_file 'config/routes.rb', "\n #{routing_code}", { :after => sentinel, :verbose => false } end end diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index d3420a6a3c..6677850a11 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -248,7 +248,7 @@ module Rails end def run_bundle - bundle_command('install') unless options[:skip_gemfile] || options[:skip_bundle] + bundle_command('install') unless options[:skip_gemfile] || options[:skip_bundle] || options[:pretend] end def empty_directory_with_gitkeep(destination, config = {}) diff --git a/railties/lib/rails/generators/base.rb b/railties/lib/rails/generators/base.rb index a98244c525..8f779316c1 100644 --- a/railties/lib/rails/generators/base.rb +++ b/railties/lib/rails/generators/base.rb @@ -254,17 +254,13 @@ module Rails nesting = class_name.split('::') last_name = nesting.pop - # Hack to limit const_defined? to non-inherited on 1.9 - extra = [] - extra << false unless Object.method(:const_defined?).arity == 1 - # Extract the last Module in the nesting last = nesting.inject(Object) do |last_module, nest| - break unless last_module.const_defined?(nest, *extra) + break unless last_module.const_defined?(nest, false) last_module.const_get(nest) end - if last && last.const_defined?(last_name.camelize, *extra) + if last && last.const_defined?(last_name.camelize, false) raise Error, "The name '#{class_name}' is either already used in your application " << "or reserved by Ruby on Rails. Please choose an alternative and run " << "this generator again." diff --git a/railties/lib/rails/generators/generated_attribute.rb b/railties/lib/rails/generators/generated_attribute.rb index 29a2ad3111..7dfc1aa599 100644 --- a/railties/lib/rails/generators/generated_attribute.rb +++ b/railties/lib/rails/generators/generated_attribute.rb @@ -32,8 +32,8 @@ module Rails case type when /(string|text|binary|integer)\{(\d+)\}/ return $1, :limit => $2.to_i - when /decimal\{(\d+)(,|\.|\-)(\d+)\}/ - return :decimal, :precision => $1.to_i, :scale => $3.to_i + when /decimal\{(\d+)[,.-](\d+)\}/ + return :decimal, :precision => $1.to_i, :scale => $2.to_i else return type, {} end diff --git a/railties/lib/rails/generators/rails/app/templates/config/application.rb b/railties/lib/rails/generators/rails/app/templates/config/application.rb index 3517956e4a..acf47a03e5 100644 --- a/railties/lib/rails/generators/rails/app/templates/config/application.rb +++ b/railties/lib/rails/generators/rails/app/templates/config/application.rb @@ -56,6 +56,11 @@ module <%= app_const_base %> # parameters by using an attr_accessible or attr_protected declaration. # config.active_record.whitelist_attributes = true + # Specifies wether or not has_many or has_one association option :dependent => :restrict raises + # an exception. If set to true, then an ActiveRecord::DeleteRestrictionError exception would be + # raised. If set to false, then an error will be added on the model instead. + <%= comment_if :skip_active_record %>config.active_record.dependent_restrict_raises = false + <% unless options.skip_sprockets? -%> # Enable the asset pipeline. config.assets.enabled = true diff --git a/railties/lib/rails/rubyprof_ext.rb b/railties/lib/rails/rubyprof_ext.rb index f6e90357ce..017eba3a76 100644 --- a/railties/lib/rails/rubyprof_ext.rb +++ b/railties/lib/rails/rubyprof_ext.rb @@ -12,7 +12,7 @@ module Prof #:nodoc: io.puts " time seconds seconds calls ms/call ms/call name" sum = 0.0 - for r in results + results.each do |r| sum += r.self_time name = if r.method_class.nil? diff --git a/railties/test/application/assets_test.rb b/railties/test/application/assets_test.rb index 01156e1b83..1469c9af4d 100644 --- a/railties/test/application/assets_test.rb +++ b/railties/test/application/assets_test.rb @@ -64,7 +64,7 @@ module ApplicationTests files << Dir["#{app_path}/public/assets/foo/application.js"].first files.each do |file| assert_not_nil file, "Expected application.js asset to be generated, but none found" - assert_equal "alert()", File.read(file) + assert_equal "alert();", File.read(file) end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index f3071843e2..a3c24c392b 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -202,6 +202,7 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator [destination_root, "--skip-active-record"] assert_no_file "config/database.yml" assert_file "config/application.rb", /#\s+require\s+["']active_record\/railtie["']/ + assert_file "config/application.rb", /#\s+config\.active_record\.dependent_restrict_raises = false/ assert_file "test/test_helper.rb" do |helper_content| assert_no_match(/fixtures :all/, helper_content) end @@ -349,6 +350,16 @@ class AppGeneratorTest < Rails::Generators::TestCase end end + def test_active_record_dependent_restrict_raises_is_present_application_config + run_generator + assert_file "config/application.rb", /config\.active_record\.dependent_restrict_raises = false/ + end + + def test_pretend_option + output = run_generator [File.join(destination_root, "myapp"), "--pretend"] + assert_no_match(/run bundle install/, output) + end + protected def action(*args, &block) |