diff options
80 files changed, 538 insertions, 247 deletions
@@ -44,7 +44,8 @@ platforms :ruby do gem "nokogiri", ">= 1.4.4" group :test do - gem "ruby-prof" + gem "ruby-prof" if RUBY_VERSION < "1.9.3" + end # AR gem "sqlite3", "~> 1.3.3" diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 3afdbea42a..ccc25c775b 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -213,14 +213,14 @@ module ActionMailer #:nodoc: # = Observing and Intercepting Mails # # Action Mailer provides hooks into the Mail observer and interceptor methods. These allow you to - # register objects that are called during the mail delivery life cycle. + # register classes that are called during the mail delivery life cycle. # - # An observer object must implement the <tt>:delivered_email(message)</tt> method which will be + # An observer class must implement the <tt>:delivered_email(message)</tt> method which will be # called once for every email sent after the email has been sent. # - # An interceptor object must implement the <tt>:delivering_email(message)</tt> method which will be + # An interceptor class must implement the <tt>:delivering_email(message)</tt> method which will be # called before the email is sent, allowing you to make modifications to the email before it hits - # the delivery agents. Your object should make any needed modifications directly to the passed + # the delivery agents. Your class should make any needed modifications directly to the passed # in Mail::Message instance. # # = Default Hash diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index 479e8246c5..5314dcc193 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,36 @@ *Rails 3.2.0 (unreleased)* +* Make sure escape_js returns SafeBuffer string if it receives SafeBuffer string [Prem Sichanugrist] + +* Fix escape_js to work correctly with the new SafeBuffer restriction [Paul Gallagher] + +* Brought back alternative convention for namespaced models in i18n [thoefer] + + Now the key can be either "namespace.model" or "namespace/model" until further deprecation. + +* It is prohibited to perform a in-place SafeBuffer mutation [tenderlove] + + The old behavior of SafeBuffer allowed you to mutate string in place via + method like `sub!`. These methods can add unsafe strings to a safe buffer, + and the safe buffer will continue to be marked as safe. + + An example problem would be something like this: + + <%= link_to('hello world', @user).sub!(/hello/, params[:xss]) %> + + In the above example, an untrusted string (`params[:xss]`) is added to the + safe buffer returned by `link_to`, and the untrusted content is successfully + sent to the client without being escaped. To prevent this from happening + `sub!` and other similar methods will now raise an exception when they are called on a safe buffer. + + In addition to the in-place versions, some of the versions of these methods which return a copy of the string will incorrectly mark strings as safe. For example: + + <%= link_to('hello world', @user).sub(/hello/, params[:xss]) %> + + The new versions will now ensure that *all* strings returned by these methods on safe buffers are marked unsafe. + + You can read more about this change in http://groups.google.com/group/rubyonrails-security/browse_thread/thread/2e516e7acc96c4fb + * Refactor ActionController::TestCase cookies [Andrew White] Assigning cookies for test cases should now use cookies[], e.g: diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index 0be04b70a1..2bdb23c4d7 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -109,7 +109,6 @@ module ActionController #:nodoc: def expire_fragment(key, options = nil) return unless cache_configured? key = fragment_cache_key(key) unless key.is_a?(Regexp) - message = nil instrument_fragment_cache :expire_fragment, key do if key.is_a?(Regexp) diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb index 6d0c163a9e..7420a5e7e9 100644 --- a/actionpack/lib/action_controller/metal/http_authentication.rb +++ b/actionpack/lib/action_controller/metal/http_authentication.rb @@ -423,7 +423,7 @@ module ActionController # Returns an Array of [String, Hash] if a token is present. # Returns nil if no token is found. def token_and_options(request) - if header = request.authorization.to_s[/^Token (.*)/] + if request.authorization.to_s[/^Token (.*)/] values = Hash[$1.split(',').map do |value| value.strip! # remove any spaces between commas and values key, value = value.split(/\=\"?/) # split key=value pairs diff --git a/actionpack/lib/action_dispatch/middleware/head.rb b/actionpack/lib/action_dispatch/middleware/head.rb index 56e2d2f2a8..f1906a3ab3 100644 --- a/actionpack/lib/action_dispatch/middleware/head.rb +++ b/actionpack/lib/action_dispatch/middleware/head.rb @@ -8,7 +8,7 @@ module ActionDispatch if env["REQUEST_METHOD"] == "HEAD" env["REQUEST_METHOD"] = "GET" env["rack.methodoverride.original_method"] = "HEAD" - status, headers, body = @app.call(env) + status, headers, _ = @app.call(env) [status, headers, []] else @app.call(env) diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 9791ba58e2..aae5752c93 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -207,9 +207,6 @@ module ActionDispatch "*/*;q=0.5" unless defined? @named_routes_configured - # install the named routes in this session instance. - klass = singleton_class - # the helpers are made protected by default--we make them public for # easier access during testing and troubleshooting. @named_routes_configured = true diff --git a/actionpack/lib/action_view/helpers/cache_helper.rb b/actionpack/lib/action_view/helpers/cache_helper.rb index e81d03b537..b57617b3d1 100644 --- a/actionpack/lib/action_view/helpers/cache_helper.rb +++ b/actionpack/lib/action_view/helpers/cache_helper.rb @@ -51,7 +51,13 @@ module ActionView # This dance is needed because Builder can't use capture pos = output_buffer.length yield - fragment = output_buffer.slice!(pos..-1) + if output_buffer.is_a?(ActionView::OutputBuffer) + safe_output_buffer = output_buffer.to_str + fragment = safe_output_buffer.slice!(pos..-1) + self.output_buffer = ActionView::OutputBuffer.new(safe_output_buffer) + else + fragment = output_buffer.slice!(pos..-1) + end controller.write_fragment(name, fragment, options) end end diff --git a/actionpack/lib/action_view/helpers/debug_helper.rb b/actionpack/lib/action_view/helpers/debug_helper.rb index cd67851642..c0cc7d347c 100644 --- a/actionpack/lib/action_view/helpers/debug_helper.rb +++ b/actionpack/lib/action_view/helpers/debug_helper.rb @@ -30,7 +30,7 @@ module ActionView begin Marshal::dump(object) "<pre class='debug_dump'>#{h(object.to_yaml).gsub(" ", " ")}</pre>".html_safe - rescue Exception => e # errors from Marshal or YAML + rescue Exception # errors from Marshal or YAML # Object couldn't be dumped, perhaps because of singleton methods -- this is the fallback "<code class='debug_dump'>#{h(object.inspect)}</code>".html_safe end diff --git a/actionpack/lib/action_view/helpers/javascript_helper.rb b/actionpack/lib/action_view/helpers/javascript_helper.rb index d7228bab67..4484390fde 100644 --- a/actionpack/lib/action_view/helpers/javascript_helper.rb +++ b/actionpack/lib/action_view/helpers/javascript_helper.rb @@ -18,7 +18,8 @@ module ActionView # $('some_element').replaceWith('<%=j render 'some/element_template' %>'); def escape_javascript(javascript) if javascript - javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] } + result = javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) {|match| JS_ESCAPE_MAP[match] } + javascript.html_safe? ? result.html_safe : result else '' end diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb index 75422a343d..8f97eb7d75 100644 --- a/actionpack/lib/action_view/helpers/text_helper.rb +++ b/actionpack/lib/action_view/helpers/text_helper.rb @@ -258,11 +258,12 @@ module ActionView text = ''.html_safe if text.nil? start_tag = tag('p', html_options, true) text = sanitize(text) unless options[:sanitize] == false + text = text.to_str text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br text.insert 0, start_tag - text.html_safe.safe_concat("</p>") + text = ActiveSupport::SafeBuffer.new(text).safe_concat("</p>") end # Creates a Cycle object whose _to_s_ method cycles through elements of an diff --git a/actionpack/lib/action_view/helpers/url_helper.rb b/actionpack/lib/action_view/helpers/url_helper.rb index 25411856cb..489b96856d 100644 --- a/actionpack/lib/action_view/helpers/url_helper.rb +++ b/actionpack/lib/action_view/helpers/url_helper.rb @@ -497,14 +497,14 @@ module ActionView }.compact extras = extras.empty? ? '' : '?' + ERB::Util.html_escape(extras.join('&')) - email_address_obfuscated = email_address.dup + email_address_obfuscated = email_address.to_str email_address_obfuscated.gsub!(/@/, html_options.delete("replace_at")) if html_options.key?("replace_at") email_address_obfuscated.gsub!(/\./, html_options.delete("replace_dot")) if html_options.key?("replace_dot") case encode when "javascript" string = '' html = content_tag("a", name || email_address_obfuscated.html_safe, html_options.merge("href" => "mailto:#{email_address}#{extras}".html_safe)) - html = escape_javascript(html) + html = escape_javascript(html.to_str) "document.write('#{html}');".each_byte do |c| string << sprintf("%%%x", c) end diff --git a/actionpack/lib/action_view/renderer/template_renderer.rb b/actionpack/lib/action_view/renderer/template_renderer.rb index a09cef8fef..d04c00fd40 100644 --- a/actionpack/lib/action_view/renderer/template_renderer.rb +++ b/actionpack/lib/action_view/renderer/template_renderer.rb @@ -64,7 +64,7 @@ module ActionView layout =~ /^\// ? with_fallbacks { find_template(layout, nil, false, keys) } : find_template(layout, nil, false, keys) end - rescue ActionView::MissingTemplate => e + rescue ActionView::MissingTemplate update_details(:formats => nil) do raise unless template_exists?(layout) end diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index d4448a7b33..587e37a84f 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -31,7 +31,6 @@ module ActionView def initialize(paths, path, prefixes, partial, details, *) @path = path prefixes = Array.wrap(prefixes) - display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ") template_type = if partial "partial" elsif path =~ /layouts/i diff --git a/actionpack/lib/sprockets/helpers/rails_helper.rb b/actionpack/lib/sprockets/helpers/rails_helper.rb index dcf4b9279e..0b6bd8ca40 100644 --- a/actionpack/lib/sprockets/helpers/rails_helper.rb +++ b/actionpack/lib/sprockets/helpers/rails_helper.rb @@ -67,13 +67,13 @@ module Sprockets def asset_path(source, default_ext = nil, body = false) source = source.logical_path if source.respond_to?(:logical_path) - path = asset_paths.compute_public_path(source, 'assets', default_ext, true) + path = asset_paths.compute_public_path(source, Rails.application.config.assets.prefix, default_ext, true) body ? "#{path}?body=1" : path end class AssetPaths < ActionView::Helpers::AssetPaths #:nodoc: def compute_public_path(source, dir, ext=nil, include_host=true) - super(source, 'assets', ext, include_host) + super(source, Rails.application.config.assets.prefix, ext, include_host) end def asset_for(source, ext) diff --git a/actionpack/lib/sprockets/railtie.rb b/actionpack/lib/sprockets/railtie.rb index 7b8a7ad3bb..4b497d142d 100644 --- a/actionpack/lib/sprockets/railtie.rb +++ b/actionpack/lib/sprockets/railtie.rb @@ -46,43 +46,48 @@ module Sprockets end protected + def asset_environment(app) + require "sprockets" - def asset_environment(app) - require "sprockets" - assets = app.config.assets - env = Sprockets::Environment.new(app.root.to_s) - env.static_root = File.join(app.root.join("public"), assets.prefix) - env.paths.concat assets.paths - env.logger = Rails.logger - env.js_compressor = expand_js_compressor(assets.js_compressor) if assets.compress - env.css_compressor = expand_css_compressor(assets.css_compressor) if assets.compress - env - end + assets = app.config.assets + + env = Sprockets::Environment.new(app.root.to_s) + + env.static_root = File.join(app.root.join("public"), assets.prefix) + env.paths.concat assets.paths + + env.logger = Rails.logger + + env.js_compressor = expand_js_compressor(assets.js_compressor) + env.css_compressor = expand_css_compressor(assets.css_compressor) - def expand_js_compressor(sym) - case sym - when :closure - require 'closure-compiler' - Closure::Compiler.new - when :uglifier - require 'uglifier' - Uglifier.new - when :yui - require 'yui/compressor' - YUI::JavaScriptCompressor.new - else - sym + env end - end - def expand_css_compressor(sym) - case sym - when :yui - require 'yui/compressor' - YUI::CssCompressor.new - else - sym + def expand_js_compressor(sym) + case sym + when :closure + require 'closure-compiler' + Closure::Compiler.new + when :uglifier + require 'uglifier' + Uglifier.new + when :yui + require 'yui/compressor' + YUI::JavaScriptCompressor.new + else + sym + end + end + + def expand_css_compressor(sym) + case sym + when :yui + require 'yui/compressor' + YUI::CssCompressor.new + else + sym + end end - end end end diff --git a/actionpack/test/abstract/abstract_controller_test.rb b/actionpack/test/abstract/abstract_controller_test.rb index 981c023d38..53712a60ec 100644 --- a/actionpack/test/abstract/abstract_controller_test.rb +++ b/actionpack/test/abstract/abstract_controller_test.rb @@ -178,12 +178,6 @@ module AbstractController end end - class Me5 < WithLayouts - def index - render - end - end - class TestLayouts < ActiveSupport::TestCase test "layouts are included" do controller = Me4.new @@ -241,11 +235,11 @@ module AbstractController assert_dispatch ActionMissingRespondToActionController, "success", :ohai end - test "a method is available as an action if respond_to_action? returns true" do + test "a method is available as an action if method_for_action returns true" do assert_dispatch RespondToActionController, "success", :index end - test "raises ActionNotFound if method is defined but respond_to_action? returns false" do + test "raises ActionNotFound if method is defined but method_for_action returns false" do assert_raise(ActionNotFound) { RespondToActionController.new.process(:fail) } end end diff --git a/actionpack/test/abstract/callbacks_test.rb b/actionpack/test/abstract/callbacks_test.rb index 3bdde86291..5d1a703c55 100644 --- a/actionpack/test/abstract/callbacks_test.rb +++ b/actionpack/test/abstract/callbacks_test.rb @@ -131,7 +131,7 @@ module AbstractController end def authenticate - @list = [] + @list ||= [] @authenticated = "true" end end diff --git a/actionpack/test/abstract/layouts_test.rb b/actionpack/test/abstract/layouts_test.rb index 5ed6aa68b5..86208899f8 100644 --- a/actionpack/test/abstract/layouts_test.rb +++ b/actionpack/test/abstract/layouts_test.rb @@ -87,18 +87,6 @@ module AbstractControllerTests end end - class WithSymbolReturningString < Base - layout :no_hello - - def index - render :template => ActionView::Template::Text.new("Hello missing symbol!") - end - private - def no_hello - nil - end - end - class WithSymbolReturningNil < Base layout :nilz diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 60534a9746..24d071df39 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -151,6 +151,7 @@ class BasicController config.assets_dir = public_dir config.javascripts_dir = "#{public_dir}/javascripts" config.stylesheets_dir = "#{public_dir}/stylesheets" + config.assets = ActiveSupport::InheritableOptions.new({ :prefix => "assets" }) config end end diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index 7f3d943bba..a714e8bbcc 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -100,9 +100,6 @@ class AssertResponseWithUnexpectedErrorController < ActionController::Base end end -class UserController < ActionController::Base -end - module Admin class InnerModuleController < ActionController::Base def index diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 82c2c23607..da3314fe6d 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -127,7 +127,7 @@ class PageCachingTest < ActionController::TestCase assert_equal 'I am xml', @response.body end - def test_should_cache_with_trailing_slash_on_url + def test_cached_page_should_not_have_trailing_slash_even_if_url_has_trailing_slash @controller.class.cache_page 'cached content', '/page_caching_test/trailing_slash/' assert File.exist?("#{FILE_STORE_PATH}/page_caching_test/trailing_slash.html") end @@ -141,7 +141,7 @@ class PageCachingTest < ActionController::TestCase [:ok, :no_content, :found, :not_found].each do |status| [:get, :post, :put, :delete].each do |method| - unless method == :get and status == :ok + unless method == :get && status == :ok define_method "test_shouldnt_cache_#{method}_with_#{status}_status" do send(method, status) assert_response status diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb index b12c798302..d51882066d 100644 --- a/actionpack/test/controller/content_type_test.rb +++ b/actionpack/test/controller/content_type_test.rb @@ -74,6 +74,7 @@ class ContentTypeTest < ActionController::TestCase get :render_defaults assert_equal "utf-16", @response.charset assert_equal Mime::HTML, @response.content_type + ensure OldContentTypeController.default_charset = "utf-8" end diff --git a/actionpack/test/dispatch/session/test_session_test.rb b/actionpack/test/dispatch/session/test_session_test.rb index 31ce97a25b..904398f563 100644 --- a/actionpack/test/dispatch/session/test_session_test.rb +++ b/actionpack/test/dispatch/session/test_session_test.rb @@ -29,7 +29,6 @@ class ActionController::TestSessionTest < ActiveSupport::TestCase end def test_clear_emptys_session - params = {:one => 'one', :two => 'two'} session = ActionController::TestSession.new({:one => 'one', :two => 'two'}) session.clear assert_nil(session[:one]) diff --git a/actionpack/test/template/erb_util_test.rb b/actionpack/test/template/erb_util_test.rb index 30f6d1a213..790ab1c74c 100644 --- a/actionpack/test/template/erb_util_test.rb +++ b/actionpack/test/template/erb_util_test.rb @@ -16,6 +16,16 @@ class ErbUtilTest < Test::Unit::TestCase end end + def test_json_escape_returns_unsafe_strings_when_passed_unsafe_strings + value = json_escape("asdf") + assert !value.html_safe? + end + + def test_json_escape_returns_safe_strings_when_passed_safe_strings + value = json_escape("asdf".html_safe) + assert value.html_safe? + end + def test_html_escape_is_html_safe escaped = h("<p>") assert_equal "<p>", escaped diff --git a/actionpack/test/template/html-scanner/document_test.rb b/actionpack/test/template/html-scanner/document_test.rb index ddfb351595..3db2fba783 100644 --- a/actionpack/test/template/html-scanner/document_test.rb +++ b/actionpack/test/template/html-scanner/document_test.rb @@ -123,7 +123,7 @@ HTML def test_parse_invalid_document assert_nothing_raised do - doc = HTML::Document.new("<html> + HTML::Document.new("<html> <table> <tr> <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td> @@ -135,7 +135,7 @@ HTML def test_invalid_document_raises_exception_when_strict assert_raise RuntimeError do - doc = HTML::Document.new("<html> + HTML::Document.new("<html> <table> <tr> <td style=\"color: #FFFFFF; height: 17px; onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" style=\"cursor:pointer; height: 17px;\"; nowrap onclick=\"window.location.href='http://www.rmeinc.com/about_rme.aspx'\" onmouseout=\"this.bgColor='#0066cc'; this.style.color='#FFFFFF'\" onmouseover=\"this.bgColor='#ffffff'; this.style.color='#0033cc'\">About Us</td> diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index 538e0e9874..dd8b7b7cd5 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -30,6 +30,15 @@ class JavaScriptHelperTest < ActionView::TestCase assert_equal %(dont <\\/close> tags), j(%(dont </close> tags)) end + def test_escape_javascript_with_safebuffer + given = %('quoted' "double-quoted" new-line:\n </closed>) + expect = %(\\'quoted\\' \\"double-quoted\\" new-line:\\n <\\/closed>) + assert_equal expect, escape_javascript(given) + assert_equal expect, escape_javascript(ActiveSupport::SafeBuffer.new(given)) + assert_instance_of String, escape_javascript(given) + assert_instance_of ActiveSupport::SafeBuffer, escape_javascript(ActiveSupport::SafeBuffer.new(given)) + end + def test_button_to_function assert_dom_equal %(<input type="button" onclick="alert('Hello world!');" value="Greeting" />), button_to_function("Greeting", "alert('Hello world!')") diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb index 74d7bba4fe..1ba14e8bc9 100644 --- a/actionpack/test/template/record_tag_helper_test.rb +++ b/actionpack/test/template/record_tag_helper_test.rb @@ -48,14 +48,12 @@ class RecordTagHelperTest < ActionView::TestCase end def test_block_works_with_content_tag_for_in_erb - __in_erb_template = '' expected = %(<tr class="post" id="post_45">#{@post.body}</tr>) actual = content_tag_for(:tr, @post) { concat @post.body } assert_dom_equal expected, actual end def test_div_for_in_erb - __in_erb_template = '' expected = %(<div class="post bar" id="post_45">#{@post.body}</div>) actual = div_for(@post, :class => "bar") { concat @post.body } assert_dom_equal expected, actual diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 86d08a43a5..4187a0ac78 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -370,7 +370,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_incompatible_external_encoding with_external_encoding Encoding::SHIFT_JIS do begin - result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message @@ -381,7 +381,7 @@ class LazyViewRenderTest < ActiveSupport::TestCase def test_render_utf8_template_with_partial_with_incompatible_encoding with_external_encoding Encoding::SHIFT_JIS do begin - result = @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") + @view.render(:file => "test/utf8_magic_with_bare_partial.html.erb", :layouts => "layouts/yield") flunk 'Should have raised incompatible encoding error' rescue ActionView::Template::Error => error assert_match 'Your template was not saved as valid Shift_JIS', error.original_exception.message diff --git a/actionpack/test/template/template_test.rb b/actionpack/test/template/template_test.rb index 81fb34b80f..b0ca7de0b6 100644 --- a/actionpack/test/template/template_test.rb +++ b/actionpack/test/template/template_test.rb @@ -153,7 +153,6 @@ class TestERBTemplate < ActiveSupport::TestCase def test_encoding_can_be_specified_with_magic_comment_in_erb with_external_encoding Encoding::UTF_8 do @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat", :virtual_path => nil) - result = render assert_equal Encoding::UTF_8, render.encoding assert_equal "hello \u{fc}mlat", render end diff --git a/actionpack/test/template/text_helper_test.rb b/actionpack/test/template/text_helper_test.rb index 740f577a6e..5a43b5f864 100644 --- a/actionpack/test/template/text_helper_test.rb +++ b/actionpack/test/template/text_helper_test.rb @@ -291,7 +291,7 @@ class TextHelperTest < ActionView::TestCase end def test_cycle_class_with_no_arguments - assert_raise(ArgumentError) { value = Cycle.new() } + assert_raise(ArgumentError) { Cycle.new } end def test_cycle @@ -304,7 +304,7 @@ class TextHelperTest < ActionView::TestCase end def test_cycle_with_no_arguments - assert_raise(ArgumentError) { value = cycle() } + assert_raise(ArgumentError) { cycle } end def test_cycle_resets_with_new_values diff --git a/activemodel/lib/active_model/naming.rb b/activemodel/lib/active_model/naming.rb index 4c1a82f413..c7b9c41f46 100644 --- a/activemodel/lib/active_model/naming.rb +++ b/activemodel/lib/active_model/naming.rb @@ -21,7 +21,7 @@ module ActiveModel @partial_path = "#{@collection}/#{@element}".freeze @param_key = (namespace ? _singularize(@unnamespaced) : @singular).freeze @route_key = (namespace ? ActiveSupport::Inflector.pluralize(@param_key) : @plural).freeze - @i18n_key = self.underscore.to_sym + @i18n_key = self.underscore.tr('/', '.').to_sym end # Transform the model name into a more humane format, using I18n. By default, @@ -35,8 +35,9 @@ module ActiveModel @klass.respond_to?(:i18n_scope) defaults = @klass.lookup_ancestors.map do |klass| - klass.model_name.i18n_key - end + [klass.model_name.i18n_key, + klass.model_name.i18n_key.to_s.tr('.', '/').to_sym] + end.flatten defaults << options[:default] if options[:default] defaults << @human diff --git a/activemodel/lib/active_model/translation.rb b/activemodel/lib/active_model/translation.rb index 6d64c81b5f..c615311692 100644 --- a/activemodel/lib/active_model/translation.rb +++ b/activemodel/lib/active_model/translation.rb @@ -44,8 +44,9 @@ module ActiveModel # Specify +options+ with additional translating options. def human_attribute_name(attribute, options = {}) defaults = lookup_ancestors.map do |klass| - :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}" - end + [:"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}", + :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key.to_s.tr('.', '/')}.#{attribute}"] + end.flatten defaults << :"attributes.#{attribute}" defaults << options.delete(:default) if options[:default] diff --git a/activemodel/test/cases/translation_test.rb b/activemodel/test/cases/translation_test.rb index 1b1d972d5c..838956bc98 100644 --- a/activemodel/test/cases/translation_test.rb +++ b/activemodel/test/cases/translation_test.rb @@ -76,5 +76,15 @@ class ActiveModelI18nTests < ActiveModel::TestCase Person.model_name.human(options) assert_equal({:default => 'person model'}, options) end + + def test_alternate_namespaced_model_attribute_translation + I18n.backend.store_translations 'en', :activemodel => {:attributes => {:person => {:gender => {:attribute => 'person gender attribute'}}}} + assert_equal 'person gender attribute', Person::Gender.human_attribute_name('attribute') + end + + def test_alternate_namespaced_model_translation + I18n.backend.store_translations 'en', :activemodel => {:models => {:person => {:gender => 'person gender model'}}} + assert_equal 'person gender model', Person::Gender.model_name.human + end end diff --git a/activerecord/RUNNING_UNIT_TESTS b/activerecord/RUNNING_UNIT_TESTS index 16444249cc..8fe9a357b4 100644 --- a/activerecord/RUNNING_UNIT_TESTS +++ b/activerecord/RUNNING_UNIT_TESTS @@ -9,24 +9,26 @@ You can build postgres and mysql databases using the build_postgresql and build_ You can run a particular test file from the command line, e.g. - $ ruby test/cases/base_test.rb + $ ruby -Itest test/cases/base_test.rb To run a specific test: - $ ruby test/cases/base_test.rb -n test_something_works + $ ruby -Itest test/cases/base_test.rb -n test_something_works You can run with a database other than the default you set in test/config.yml, using the ARCONN environment variable: - $ ARCONN=postgresql ruby test/cases/base_test.rb + $ ARCONN=postgresql ruby -Itest test/cases/base_test.rb You can run all the tests for a given database via rake: -To setup the testing environment for PostgreSQL use this command: + $ rake test_mysql - rake postgresql:build_databases +The 'rake test' task will run all the tests for mysql, mysql2, sqlite3 and postgresql. -The incantation for running a particular test looks like this +== Identity Map - rake test TEST=test/cases/datatype_test_postgresql.rb TESTOPTS="--name=test_timestamp_with_zone_values_without_rails_time_zone_support" +By default the tests run with the Identity Map turned off. But all tests should pass whether or +not the identity map is on or off. You can turn it on using the IM env variable: + $ IM=true ruby -Itest test/case/base_test.rb diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 687b668634..c3aee90124 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -141,7 +141,7 @@ module ActiveRecord @target ||= find_target end end - loaded! + loaded! unless loaded? target rescue ActiveRecord::RecordNotFound reset @@ -177,9 +177,7 @@ module ActiveRecord # Sets the owner attributes on the given record def set_owner_attributes(record) - if owner.persisted? - creation_attributes.each { |key, value| record[key] = value } - end + creation_attributes.each { |key, value| record[key] = value } end # Should be true if there is a foreign key present on the owner which diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 81b4a26b04..5267116c42 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -67,7 +67,7 @@ module ActiveRecord def method_missing(method, *args, &block) match = DynamicFinderMatch.match(method) if match && match.instantiator? - record = send(:find_or_instantiator_by_attributes, match, match.attribute_names, *args) do |r| + send(:find_or_instantiator_by_attributes, match, match.attribute_names, *args) do |r| @association.send :set_owner_attributes, r @association.send :add_to_target, r yield(r) if block_given? diff --git a/activerecord/lib/active_record/associations/has_one_association.rb b/activerecord/lib/active_record/associations/has_one_association.rb index 2f3a6e71f1..6b8201973a 100644 --- a/activerecord/lib/active_record/associations/has_one_association.rb +++ b/activerecord/lib/active_record/associations/has_one_association.rb @@ -14,8 +14,8 @@ module ActiveRecord end if record - set_inverse_instance(record) set_owner_attributes(record) + set_inverse_instance(record) if owner.persisted? && save && !record.save nullify_owner_attributes(record) diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 08cc282d09..2f283ff6bc 100644 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -659,8 +659,8 @@ module ActiveRecord #:nodoc: def set_table_name(value = nil, &block) @quoted_table_name = nil define_attr_method :table_name, value, &block + @arel_table = nil - @arel_table = Arel::Table.new(table_name, arel_engine) @relation = Relation.new(self, arel_table) end alias :table_name= :set_table_name @@ -892,7 +892,7 @@ module ActiveRecord #:nodoc: end def arel_table - Arel::Table.new(table_name, arel_engine) + @arel_table ||= Arel::Table.new(table_name, arel_engine) end def arel_engine @@ -2006,7 +2006,7 @@ MSG set_values = (1..3).collect{|position| values_hash_from_param[position].blank? ? 1 : values_hash_from_param[position]} begin Date.new(*set_values) - rescue ArgumentError => ex # if Date.new raises an exception on an invalid date + rescue ArgumentError # if Date.new raises an exception on an invalid date instantiate_time_object(name, set_values).to_date # we instantiate Time object and convert it back to a date thus using Time's logic in handling invalid dates end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 8d7dd8bacf..9e6cb13cca 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -707,7 +707,7 @@ module ActiveRecord def quoted_columns_for_index(column_names, options = {}) length = options[:length] if options.is_a?(Hash) - quoted_column_names = case length + case length when Hash column_names.map {|name| length[name] ? "#{quote_column_name(name)}(#{length[name]})" : quote_column_name(name) } when Fixnum diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 4ec0431b8c..367a1be4d9 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -279,7 +279,7 @@ module ActiveRecord @changed_attributes.except!(*changes.keys) primary_key = self.class.primary_key - self.class.update_all(changes, { primary_key => self[primary_key] }) == 1 + self.class.unscoped.update_all(changes, { primary_key => self[primary_key] }) == 1 end end diff --git a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb index 752b864818..3a9744e78f 100644 --- a/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb +++ b/activerecord/test/cases/adapters/mysql2/reserved_word_test.rb @@ -87,8 +87,8 @@ class MysqlReservedWordTest < ActiveRecord::TestCase assert_nothing_raised { x.save } x.order = 'y' assert_nothing_raised { x.save } - assert_nothing_raised { y = Group.find_by_order('y') } - assert_nothing_raised { y = Group.find(1) } + assert_nothing_raised { Group.find_by_order('y') } + assert_nothing_raised { Group.find(1) } x = Group.find(1) end diff --git a/activerecord/test/cases/associations/join_model_test.rb b/activerecord/test/cases/associations/join_model_test.rb index b59ce4efeb..4ce8b85098 100644 --- a/activerecord/test/cases/associations/join_model_test.rb +++ b/activerecord/test/cases/associations/join_model_test.rb @@ -139,7 +139,21 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase def test_set_polymorphic_has_one tagging = tags(:misc).taggings.create posts(:thinking).tagging = tagging - assert_equal "Post", tagging.taggable_type + + assert_equal "Post", tagging.taggable_type + assert_equal posts(:thinking).id, tagging.taggable_id + assert_equal posts(:thinking), tagging.taggable + end + + def test_set_polymorphic_has_one_on_new_record + tagging = tags(:misc).taggings.create + post = Post.new :title => "foo", :body => "bar" + post.tagging = tagging + post.save! + + assert_equal "Post", tagging.taggable_type + assert_equal post.id, tagging.taggable_id + assert_equal post, tagging.taggable end def test_create_polymorphic_has_many_with_scope @@ -708,8 +722,8 @@ class AssociationsJoinModelTest < ActiveRecord::TestCase end def test_has_many_with_pluralize_table_names_false - engine = Engine.create!(:car_id => 1) - aircraft = Aircraft.create!(:name => "Airbus 380", :id => 1) + aircraft = Aircraft.create!(:name => "Airbus 380") + engine = Engine.create!(:car_id => aircraft.id) assert_equal aircraft.engines, [engine] end diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index 110f6b97c6..d0dc9cb03d 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -12,19 +12,20 @@ require 'active_support/dependencies' require 'support/config' require 'support/connection' -ARTest.connect - # TODO: Move all these random hacks into the ARTest namespace and into the support/ dir # Show backtraces for deprecated behavior for quicker cleanup. ActiveSupport::Deprecation.debug = true -# Quote "type" if it's a reserved word for the current connection. -QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') - # Enable Identity Map only when ENV['IM'] is set to "true" ActiveRecord::IdentityMap.enabled = (ENV['IM'] == "true") +# Connect to the database +ARTest.connect + +# Quote "type" if it's a reserved word for the current connection. +QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type') + def current_adapter?(*types) types.any? do |type| ActiveRecord::ConnectionAdapters.const_defined?(type) && diff --git a/activerecord/test/cases/timestamp_test.rb b/activerecord/test/cases/timestamp_test.rb index ceb1452afd..4445a12e1d 100644 --- a/activerecord/test/cases/timestamp_test.rb +++ b/activerecord/test/cases/timestamp_test.rb @@ -11,6 +11,7 @@ class TimestampTest < ActiveRecord::TestCase def setup @developer = Developer.first + @developer.update_attribute(:updated_at, Time.now.prev_month) @previously_updated_at = @developer.updated_at end @@ -40,6 +41,15 @@ class TimestampTest < ActiveRecord::TestCase assert_equal previous_salary, @developer.salary end + def test_touching_a_record_with_default_scope_that_excludes_it_updates_its_timestamp + developer = @developer.becomes(DeveloperCalledJamis) + + developer.touch + assert_not_equal @previously_updated_at, developer.updated_at + developer.reload + assert_not_equal @previously_updated_at, developer.updated_at + end + def test_saving_when_record_timestamps_is_false_doesnt_update_its_timestamp Developer.record_timestamps = false @developer.name = "John Smith" diff --git a/activerecord/test/support/connection.rb b/activerecord/test/support/connection.rb index fcd2e4dee5..a39794fa39 100644 --- a/activerecord/test/support/connection.rb +++ b/activerecord/test/support/connection.rb @@ -11,7 +11,7 @@ module ARTest end def self.connect - puts "Using #{connection_name}" + puts "Using #{connection_name} with Identity Map #{ActiveRecord::IdentityMap.enabled? ? 'on' : 'off'}" ActiveRecord::Base.logger = Logger.new("debug.log") ActiveRecord::Base.configurations = connection_config ActiveRecord::Base.establish_connection 'arunit' diff --git a/activeresource/test/cases/base/load_test.rb b/activeresource/test/cases/base/load_test.rb index d6b04cfaa8..0d030148d0 100644 --- a/activeresource/test/cases/base/load_test.rb +++ b/activeresource/test/cases/base/load_test.rb @@ -72,7 +72,6 @@ class BaseLoadTest < Test::Unit::TestCase def test_after_load_attributes_are_accessible_via_indifferent_access assert_equal Hash.new, @person.attributes - matz_attributes = @matz.values.first assert_equal @matz.stringify_keys, @person.load(@matz).attributes assert_equal @matz[:name], @person.attributes['name'] assert_equal @matz[:name], @person.attributes[:name] diff --git a/activeresource/test/cases/finder_test.rb b/activeresource/test/cases/finder_test.rb index 9c51f2a390..5fbbfeef6e 100644 --- a/activeresource/test/cases/finder_test.rb +++ b/activeresource/test/cases/finder_test.rb @@ -95,7 +95,7 @@ class FinderTest < Test::Unit::TestCase def test_find_all_sub_objects_not_found assert_nothing_raised do - addys = StreetAddress.find(:all, :params => { :person_id => 2 }) + StreetAddress.find(:all, :params => { :person_id => 2 }) end end diff --git a/activeresource/test/cases/log_subscriber_test.rb b/activeresource/test/cases/log_subscriber_test.rb index b9143f5b67..ab5c22a783 100644 --- a/activeresource/test/cases/log_subscriber_test.rb +++ b/activeresource/test/cases/log_subscriber_test.rb @@ -23,7 +23,7 @@ class LogSubscriberTest < ActiveSupport::TestCase end def test_request_notification - matz = Person.find(1) + Person.find(1) wait assert_equal 2, @logger.logged(:info).size assert_equal "GET http://37s.sunrise.i:3000/people/1.json", @logger.logged(:info)[0] diff --git a/activeresource/test/cases/observing_test.rb b/activeresource/test/cases/observing_test.rb index ca3ab5d03d..58d3d389ff 100644 --- a/activeresource/test/cases/observing_test.rb +++ b/activeresource/test/cases/observing_test.rb @@ -37,7 +37,7 @@ class ObservingTest < Test::Unit::TestCase end def test_create_fires_save_and_create_notifications - rick = Person.create(:name => 'Rick') + Person.create(:name => 'Rick') assert_equal [:before_save, :before_create, :after_create, :after_save], self.history end diff --git a/activesupport/lib/active_support/core_ext/date/freeze.rb b/activesupport/lib/active_support/core_ext/date/freeze.rb index 4edd715ba2..a731f8345e 100644 --- a/activesupport/lib/active_support/core_ext/date/freeze.rb +++ b/activesupport/lib/active_support/core_ext/date/freeze.rb @@ -5,7 +5,7 @@ # first call will result in a frozen object error since the memo # instance variable is uninitialized. # -# Work around by eagerly memoizing before freezing. +# Work around by eagerly memoizing before the first freeze. # # Ruby 1.9 uses a preinitialized instance variable so it's unaffected. # This hack is as close as we can get to feature detection: @@ -17,9 +17,11 @@ if RUBY_VERSION < '1.9' if frozen_object_error.message =~ /frozen/ class Date #:nodoc: def freeze - self.class.private_instance_methods(false).each do |m| - if m.to_s =~ /\A__\d+__\Z/ - instance_variable_set(:"@#{m}", [send(m)]) + unless frozen? + self.class.private_instance_methods(false).each do |m| + if m.to_s =~ /\A__\d+__\Z/ + instance_variable_set(:"@#{m}", [send(m)]) + end end end diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 3a7652f5bf..1777a4b32d 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/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index c27cbc37c5..20e40fe40f 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -51,7 +51,8 @@ class ERB # <%=j @person.to_json %> # def json_escape(s) - s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } + result = s.to_s.gsub(/[&"><]/) { |special| JSON_ESCAPE[special] } + s.html_safe? ? result.html_safe : result end alias j json_escape @@ -74,6 +75,7 @@ end module ActiveSupport #:nodoc: class SafeBuffer < String + UNSAFE_STRING_METHODS = ["capitalize", "chomp", "chop", "delete", "downcase", "gsub", "lstrip", "next", "reverse", "rstrip", "slice", "squeeze", "strip", "sub", "succ", "swapcase", "tr", "tr_s", "upcase"].freeze alias safe_concat concat def concat(value) @@ -110,6 +112,18 @@ module ActiveSupport #:nodoc: to_str.to_yaml(*args) end + + UNSAFE_STRING_METHODS.each do |unsafe_method| + class_eval <<-EOT, __FILE__, __LINE__ + def #{unsafe_method}(*args) + super.to_str + end + + def #{unsafe_method}!(*args) + raise TypeError, "Cannot modify SafeBuffer in place" + end + EOT + end end end diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index d81693209f..b4f848cd44 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -454,4 +454,10 @@ class DateExtBehaviorTest < Test::Unit::TestCase Date.today.freeze.inspect end end + + def test_can_freeze_twice + assert_nothing_raised do + Date.today.freeze.freeze + end + end end diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index a4e2acbb32..3a9854358c 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -60,4 +60,16 @@ class SafeBufferTest < ActiveSupport::TestCase yaml = YAML.dump data assert_equal({'str' => str}, YAML.load(yaml)) end + + test "Should not return safe buffer from gsub" do + altered_buffer = @buffer.gsub('', 'asdf') + assert_equal 'asdf', altered_buffer + assert !altered_buffer.html_safe? + end + + test "Should not allow gsub! on safe buffers" do + assert_raise TypeError do + @buffer.gsub!('', 'asdf') + end + end end diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb index ee5a20c789..5bd995aa32 100644 --- a/activesupport/test/test_test.rb +++ b/activesupport/test/test_test.rb @@ -50,7 +50,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_expression_is_evaluated_in_the_appropriate_scope silence_warnings do - local_scope = 'foo' + local_scope = local_scope = 'foo' assert_difference('local_scope; @object.num') { @object.increment } end end diff --git a/railties/CHANGELOG b/railties/CHANGELOG index c77d03c39f..880849d2ec 100644 --- a/railties/CHANGELOG +++ b/railties/CHANGELOG @@ -7,6 +7,8 @@ *Rails 3.1.0 (unreleased)* +* The new rake task assets:clean removes precompiled assets. [fxn] + * Application and plugin generation run bundle install unless --skip-gemfile or --skip-bundle. [fxn] * Fixed database tasks for jdbc* adapters #jruby diff --git a/railties/guides/source/caching_with_rails.textile b/railties/guides/source/caching_with_rails.textile index cebf49573d..f058dce42b 100644 --- a/railties/guides/source/caching_with_rails.textile +++ b/railties/guides/source/caching_with_rails.textile @@ -112,7 +112,7 @@ As an example, if you wanted to show all the orders placed on your website in re <ruby> <% Order.find_recent.each do |o| %> - <%= o.buyer.name %> bought <% o.product.name %> + <%= o.buyer.name %> bought <%= o.product.name %> <% end %> <% cache do %> @@ -162,17 +162,17 @@ class ProductSweeper < ActionController::Caching::Sweeper # If our sweeper detects that a Product was created call this def after_create(product) - expire_cache_for(product) + expire_cache_for(product) end # If our sweeper detects that a Product was updated call this def after_update(product) - expire_cache_for(product) + expire_cache_for(product) end # If our sweeper detects that a Product was deleted call this def after_destroy(product) - expire_cache_for(product) + expire_cache_for(product) end private diff --git a/railties/guides/source/configuring.textile b/railties/guides/source/configuring.textile index dd66fd15bb..da951a0833 100644 --- a/railties/guides/source/configuring.textile +++ b/railties/guides/source/configuring.textile @@ -18,7 +18,7 @@ Rails offers four standard spots to place initialization code: h3. Running Code Before Rails -In the rare event that your application needs to run some code before Rails itself is loaded, put it above the call to +require 'rails/all'+ in your +config/application.rb+. +In the rare event that your application needs to run some code before Rails itself is loaded, put it above the call to +require 'rails/all'+ in +config/application.rb+. h3. Configuring Rails Components @@ -52,12 +52,14 @@ end * +config.asset_host+ sets the host for the assets. Useful when CDNs are used for hosting assets, or when you want to work around the concurrency constraints builtin in browsers using different domain aliases. Shorter version of +config.action_controller.asset_host+. -* +config.asset_path+ can take a callable, a string, or be +nil+. Default is +nil+. If set, this configuration parameter lets you decorate asset paths. For example, the normal path for +blog.js+ would be +/javascripts/blog.js+, let that absolute path be +path+. If +config.asset_path+ is a callable, Rails calls it when generating asset paths passing +path+ as argument. If +config.asset_path+ is a string, it is expected to be a +sprintf+ format string with a +%s+ where +path+ will get inserted. In either case, Rails outputs the decorated path. *This option is ignored if the asset pipeline is enabled, which is by default*. Shorter version of +config.action_controller.asset_path+. +* +config.asset_path+ lets you decorate asset paths. This can be a callable, a string, or be +nil+ which is the default. For example, the normal path for +blog.js+ would be +/javascripts/blog.js+, let that absolute path be +path+. If +config.asset_path+ is a callable, Rails calls it when generating asset paths passing +path+ as argument. If +config.asset_path+ is a string, it is expected to be a +sprintf+ format string with a +%s+ where +path+ will get inserted. In either case, Rails outputs the decorated path. Shorter version of +config.action_controller.asset_path+. <ruby> config.asset_path = proc { |path| "/blog/public#{path}" } </ruby> +NOTE. The +config.asset_path+ configuration is ignored if the asset pipeline is enabled, which is the default. + * +config.autoload_once_paths+ accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if +config.cache_classes+ is false, which is the case in development mode by default. Otherwise, all autoloading happens only once. All elements of this array must also be in +autoload_paths+. Default is an empty array. * +config.autoload_paths+ accepts an array of paths from which Rails will autoload constants. Default is all directories under +app+. @@ -84,11 +86,11 @@ config.asset_path = proc { |path| "/blog/public#{path}" } * +config.log_level+ defines the verbosity of the Rails logger. This option defaults to +:debug+ for all modes except production, where it defaults to +:info+. -* +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ +Logger+ class. Defaults to an instance of +ActiveSupport::BufferedLogger+, with auto flushing off in production mode. +* +config.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby +Logger+ class. Defaults to an instance of +ActiveSupport::BufferedLogger+, with auto flushing off in production mode. -* +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":configuring-middleware section below. +* +config.middleware+ allows you to configure the application's middleware. This is covered in depth in the "Configuring Middleware":#configuring-middleware section below. -* +config.plugins+ accepts the list of plugins to load. If this is set to +nil+, default, all plugins will be loaded. If this is set to +[]+, no plugins will be loaded. Otherwise, plugins will be loaded in the order specified. This option let's you enforce some particular loading order, useful when dependencies between plugins require it. For that use case, put first the plugins you want to be loaded in a certain order, and then the special symbol +:all+ to have the rest loaded without the need to specify them. +* +config.plugins+ accepts the list of plugins to load. The default is +nil+ in which case all plugins will be loaded. If this is set to +[]+, no plugins will be loaded. Otherwise, plugins will be loaded in the order specified. This option lets you enforce some particular loading order, useful when dependencies between plugins require it. For that use case, put first the plugins you want to be loaded in a certain order, and then the special symbol +:all+ to have the rest loaded without the need to specify them. * +config.preload_frameworks+ enables or disables preloading all frameworks at startup. Enabled by +config.threadsafe!+. Defaults to +nil+, so is disabled. @@ -98,7 +100,7 @@ config.asset_path = proc { |path| "/blog/public#{path}" } * +config.serve_static_assets+ configures Rails to serve static assets. Defaults to true, but in the production environment is turned off. The server software used to run the application should be used to serve the assets instead. -* +config.session_store+ is usually set up in +config/initializers/session_store.rb+ and specifies what class to use to store the session. Possible values are +:cookie_store+, default, +:mem_cache_store+, and +:disabled+. The last one tells Rails not to deal with sessions. Custom session stores can also be specified like so: +* +config.session_store+ is usually set up in +config/initializers/session_store.rb+ and specifies what class to use to store the session. Possible values are +:cookie_store+ which is the default, +:mem_cache_store+, and +:disabled+. The last one tells Rails not to deal with sessions. Custom session stores can also be specified: <ruby> config.session_store :my_custom_store @@ -129,37 +131,41 @@ end The full set of methods that can be used in this block are as follows: -* +force_plural+ allows pluralized model names. Defaults to _false_. -* +helper+ defines whether or not to generate helpers. Defaults to _true_. -* +orm+ defines which orm to use. Defaults to _nil_, so will use Active Record by default. -* +integration_tool+ defines which integration tool to use. Defaults to _nil_. -* +performance_tool+ defines which performance tool to use. Defaults to _nil_. +* +assets+ allows to create assets on generating a scaffold. Defaults to +true+. +* +force_plural+ allows pluralized model names. Defaults to +false+. +* +helper+ defines whether or not to generate helpers. Defaults to +true+. +* +integration_tool+ defines which integration tool to use. Defaults to +nil+. +* +javascripts+ turns on the hook for javascripts in generators. Used in Rails for when the +scaffold+ generator is ran. Defaults to +true+. +* +javascript_engine+ configures the engine to be used (for eg. coffee) when generating assets. Defaults to +nil+. +* +orm+ defines which orm to use. Defaults to +false+ and will use Active Record by default. +* +performance_tool+ defines which performance tool to use. Defaults to +nil+. * +resource_controller+ defines which generator to use for generating a controller when using +rails generate resource+. Defaults to +:controller+. * +scaffold_controller+ different from +resource_controller+, defines which generator to use for generating a _scaffolded_ controller when using +rails generate scaffold+. Defaults to +:scaffold_controller+. -* +stylesheets+ turns on the hook for stylesheets in generators. Used in Rails for when the +scaffold+ generator is ran, but this hook can be used in other generates as well. -* +test_framework+ defines which test framework to use. Defaults to _nil_, so will use Test::Unit by default. +* +stylesheets+ turns on the hook for stylesheets in generators. Used in Rails for when the +scaffold+ generator is ran, but this hook can be used in other generates as well. Defaults to +true+. +* +stylesheet_engine+ configures the stylesheet engine (for eg. sass) to be used when generating assets. Defaults to +:css+. +* +test_framework+ defines which test framework to use. Defaults to +false+ and will use Test::Unit by default. * +template_engine+ defines which template engine to use, such as ERB or Haml. Defaults to +:erb+. h4. Configuring Middleware Every Rails application comes with a standard set of middleware which it uses in this order in the development environment: -* +Rack::SSL+ Will force every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to _true_. -* +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is _true_. -* +Rack::Lock+ Will wrap the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to _false_, which it is by default. +* +Rack::SSL+ Will force every request to be under HTTPS protocol. Will be available if +config.force_ssl+ is set to +true+. +* +ActionDispatch::Static+ is used to serve static assets. Disabled if +config.serve_static_assets+ is +true+. +* +Rack::Lock+ Will wrap the app in mutex so it can only be called by a single thread at a time. Only enabled if +config.action_controller.allow_concurrency+ is set to +false+, which it is by default. * +ActiveSupport::Cache::Strategy::LocalCache+ Serves as a basic memory backed cache. This cache is not thread safe and is intended only for serving as a temporary memory cache for a single thread. * +Rack::Runtime+ Sets an +X-Runtime+ header, containing the time (in seconds) taken to execute the request. -* +Rails::Rack::Logger+ Will notify the logs that the request has began. After request is complete, flushes all the logs. -* +ActionDispatch::ShowExceptions+ rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to _true_. If +config.action_dispatch.show_exceptions+ is set to _false_, exceptions will be raised regardless. -* +ActionDispatch::RemoteIp+ checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings. -* +Rack::Sendfile+ The Sendfile middleware intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+ +* +Rails::Rack::Logger+ Notifies the logs that the request has began. After request is complete, flushes all the logs. +* +ActionDispatch::ShowExceptions+ Rescues any exception returned by the application and renders nice exception pages if the request is local or if +config.consider_all_requests_local+ is set to +true+. If +config.action_dispatch.show_exceptions+ is set to +false+, exceptions will be raised regardless. +* +ActionDispatch::RemoteIp+ Checks for IP spoofing attacks. Configurable with the +config.action_dispatch.ip_spoofing_check+ and +config.action_dispatch.trusted_proxies+ settings. +* +Rack::Sendfile+ Intercepts responses whose body is being served from a file and replaces it with a server specific X-Sendfile header. Configurable with +config.action_dispatch.x_sendfile_header+. * +ActionDispatch::Callbacks+ Runs the prepare callbacks before serving the request. -* +ActiveRecord::ConnectionAdapters::ConnectionManagement+ cleans active connections after each request, unless the +rack.test+ key in the request environment is set to _true_. -* +ActiveRecord::QueryCache+ caches all +SELECT+ queries generated in a request. If an +INSERT+ or +UPDATE+ takes place then the cache is cleaned. +* +ActiveRecord::ConnectionAdapters::ConnectionManagement+ cleans active connections after each request, unless the +rack.test+ key in the request environment is set to +true+. +* +ActiveRecord::QueryCache+ caches all SELECT queries generated in a request. If any INSERT or UPDATE takes place then the cache is cleaned. * +ActionDispatch::Cookies+ sets cookies for the request. * +ActionDispatch::Session::CookieStore+ is responsible for storing the session in cookies. An alternate middleware can be used for this by changing the +config.action_controller.session_store+ to an alternate value. Additionally, options passed to this can be configured by using +config.action_controller.session_options+. * +ActionDispatch::Flash+ sets up the +flash+ keys. Only available if +config.action_controller.session_store+ is set to a value. -* +ActionDispatch::ParamsParser+ parses out parameters from the request into +params+ +* +ActionDispatch::ParamsParser+ parses out parameters from the request into +params+. * +Rack::MethodOverride+ allows the method to be overridden if +params[:_method]+ is set. This is the middleware which supports the PUT and DELETE HTTP method types. * +ActionDispatch::Head+ converts HEAD requests to GET requests and serves them as so. * +ActionDispatch::BestStandardsSupport+ enables "best standards support" so that IE8 renders some elements correctly. @@ -170,13 +176,13 @@ Besides these usual middleware, you can add your own by using the +config.middle config.middleware.use Magical::Unicorns </ruby> -This will put the +Magical::Unicorns+ middleware on the end of the stack. If you wish to put this middleware before another use +insert_before+: +This will put the +Magical::Unicorns+ middleware on the end of the stack. You can use +insert_before+ if you wish to add a middleware before another. <ruby> config.middleware.insert_before ActionDispatch::Head, Magical::Unicorns </ruby> -There's also +insert_after+ which will insert a middleware _after_ another: +There's also +insert_after+ which will insert a middleware after another: <ruby> config.middleware.insert_after ActionDispatch::Head, Magical::Unicorns @@ -198,13 +204,13 @@ h4. Configuring i18n * +config.i18n.default_locale+ sets the default locale of an application used for i18n. Defaults to +:en+. -* +config.i18n.load_path+ sets the path Rails uses to look for locale files. Defaults to +config/locales/*.{yml,rb}+ +* +config.i18n.load_path+ sets the path Rails uses to look for locale files. Defaults to +config/locales/*.{yml,rb}+. h4. Configuring Active Record <tt>config.active_record</tt> includes a variety of configuration options: -* +config.active_record.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8.x Logger class, which is then passed on to any new database connections made. You can retrieve this logger by calling +logger+ on either an Active Record model class or an Active Record model instance. Set to +nil+ to disable logging. +* +config.active_record.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then passed on to any new database connections made. You can retrieve this logger by calling +logger+ on either an Active Record model class or an Active Record model instance. Set to +nil+ to disable logging. * +config.active_record.primary_key_prefix_type+ lets you adjust the naming for primary key columns. By default, Rails assumes that primary key columns are named +id+ (and this configuration option doesn't need to be set.) There are two other choices: ** +:table_name+ would make the primary key for the Customer class +customerid+ @@ -214,7 +220,7 @@ h4. Configuring Active Record * +config.active_record.table_name_suffix+ lets you set a global string to be appended to table names. If you set this to +_northwest+, then the Customer class will look for +customers_northwest+ as its table. The default is an empty string. -* +config.active_record.pluralize_table_names+ specifies whether Rails will look for singular or plural table names in the database. If set to +true+ (the default), then the Customer class will use the +customers+ table. If set to +false+, then the Customers class will use the +customer+ table. +* +config.active_record.pluralize_table_names+ specifies whether Rails will look for singular or plural table names in the database. If set to +true+ (the default), then the Customer class will use the +customers+ table. If set to +false+, then the Customer class will use the +customer+ table. * +config.active_record.default_timezone+ determines whether to use +Time.local+ (if set to +:local+) or +Time.utc+ (if set to +:utc+) when pulling dates and times from the database. The default is +:utc+ for Rails, although Active Record defaults to +:local+ when used outside of Rails. @@ -244,13 +250,13 @@ h4. Configuring Action Controller * +config.action_controller.page_cache_directory+ should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>. For Rails, this directory has already been set to +Rails.public_path+ (which is usually set to <tt>Rails.root + "/public"</tt>). Changing this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your web server to look in the new location for cached files. -* +config.action_controller.page_cache_extension+ configures the extension used for cached pages saved to +page_cache_directory+. Defaults to +.html+ +* +config.action_controller.page_cache_extension+ configures the extension used for cached pages saved to +page_cache_directory+. Defaults to +.html+. -* +config.action_controller.perform_caching+ configures whether the application should perform caching or not. Set to _false_ in development mode, _true_ in production. +* +config.action_controller.perform_caching+ configures whether the application should perform caching or not. Set to false in development mode, true in production. * +config.action_controller.default_charset+ specifies the default character set for all renders. The default is "utf-8". -* +config.action_controller.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Controller. Set to +nil+ to disable logging. +* +config.action_controller.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Controller. Set to +nil+ to disable logging. * +config.action_controller.request_forgery_protection_token+ sets the token parameter name for RequestForgery. Calling +protect_from_forgery+ sets it to +:authenticity_token+ by default. @@ -288,36 +294,40 @@ h4. Configuring Action View There are only a few configuration options for Action View, starting with four on +ActionView::Base+: -* +config.action_view.field_error_proc+ provides an HTML generator for displaying errors that come from Active Record. The default is <tt>Proc.new{ |html_tag, instance| %Q(%<div class="field_with_errors">#{html_tag}</div>).html_safe }</tt> +* +config.action_view.field_error_proc+ provides an HTML generator for displaying errors that come from Active Record. The default is + +<ruby> +Proc.new { |html_tag, instance| %Q(<div class="field_with_errors">#{html_tag}</div>).html_safe } +</ruby> * +config.action_view.default_form_builder+ tells Rails which form builder to use by default. The default is +ActionView::Helpers::FormBuilder+. -* +config.action_view.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Mailer. Set to +nil+ to disable logging. +* +config.action_view.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Mailer. Set to +nil+ to disable logging. * +config.action_view.erb_trim_mode+ gives the trim mode to be used by ERB. It defaults to +'-'+. See the "ERB documentation":http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/ for more information. * +config.action_view.javascript_expansions+ is a hash containing expansions that can be used for the JavaScript include tag. By default, this is defined as: <ruby> - config.action_view.javascript_expansions = { :defaults => ['prototype', 'effects', 'dragdrop', 'controls', 'rails'] } +config.action_view.javascript_expansions = { :defaults => %w(jquery jquery_ujs) } </ruby> However, you may add to this by defining others: <ruby> - config.action_view.javascript_expansions[:jquery] = ["jquery", "jquery-ui"] +config.action_view.javascript_expansions[:prototype] = ['prototype', 'effects', 'dragdrop', 'controls'] </ruby> And can reference in the view with the following code: <ruby> - <%= javascript_include_tag :jquery %> +<%= javascript_include_tag :prototype %> </ruby> * +config.action_view.stylesheet_expansions+ works in much the same way as +javascript_expansions+, but has no default key. Keys defined for this hash can be referenced in the view like such: <ruby> - <%= stylesheet_link_tag :special %> +<%= stylesheet_link_tag :special %> </ruby> * +ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids+ With the cache enabled, the asset tag helper methods will make fewer expensive file system calls (the default implementation checks the file system timestamp). However this prevents you from modifying any asset files while the server is running. @@ -326,7 +336,7 @@ h4. Configuring Action Mailer There are a number of settings available on +config.action_mailer+: -* +config.action_mailer.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Action Mailer. Set to +nil+ to disable logging. +* +config.action_mailer.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Action Mailer. Set to +nil+ to disable logging. * +config.action_mailer.smtp_settings+ allows detailed configuration for the +:smtp+ delivery method. It accepts a hash of options, which can include any of these options: ** +:address+ - Allows you to use a remote mail server. Just change it from its default "localhost" setting. @@ -354,11 +364,21 @@ There are a number of settings available on +config.action_mailer+: :parts_order => [ "text/plain", "text/enriched", "text/html" ] </ruby> +* +config.action_mailer.observers+ registers observers which will be notified when mail is delivered. +<ruby> +config.active_record.observers = ["MailObserver"] +</ruby> + +* +config.action_mailer.interceptors+ registers interceptors which will be called before mail is sent. +<ruby> +config.active_record.interceptors = ["MailInterceptor"] +</ruby> + h4. Configuring Active Resource There is a single configuration setting available on +config.active_resource+: -* +config.active_resource.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby 1.8+ Logger class, which is then used to log information from Active Resource. Set to +nil+ to disable logging. +* +config.active_resource.logger+ accepts a logger conforming to the interface of Log4r or the default Ruby Logger class, which is then used to log information from Active Resource. Set to +nil+ to disable logging. h4. Configuring Active Support @@ -398,7 +418,7 @@ Some parts of Rails can also be configured externally by supplying environment v h3. Using Initializer Files -After loading the framework and any gems and plugins in your application, Rails turns to loading initializers. An initializer is any file of Ruby code stored under +config/initializers+ in your application. You can use initializers to hold configuration settings that should be made after all of the frameworks, plugins and gems are loaded, such as options to configure settings for these parts. +After loading the framework and any gems and plugins in your application, Rails turns to loading initializers. An initializer is any Ruby file stored under +config/initializers+ in your application. You can use initializers to hold configuration settings that should be made after all of the frameworks, plugins and gems are loaded, such as options to configure settings for these parts. NOTE: You can use subfolders to organize your initializers if you like, because Rails will look into the whole file hierarchy from the initializers folder on down. @@ -406,7 +426,7 @@ TIP: If you have any ordering dependency in your initializers, you can control t h3. Initialization events -Rails has 5 initialization events which can be hooked into (listed in order that they are ran): +Rails has 5 initialization events which can be hooked into (listed in the order that they are ran): * +before_configuration+: This is run as soon as the application constant inherits from +Rails::Application+. The +config+ calls are evaluated before this happens. @@ -437,7 +457,7 @@ Initializers defined using the +initializer+ method will be ran in the order the WARNING: You may put your initializer before or after any other initializer in the chain, as long as it is logical. Say you have 4 initializers called "one" through "four" (defined in that order) and you define "four" to go _before_ "four" but _after_ "three", that just isn't logical and Rails will not be able to determine your initializer order. -The block's argument of the +initialize+ is the instance of the application itself, and so we can access the configuration on it by using the +config+ method as this initializer does. +The block argument of the +initializer+ method is the instance of the application itself, and so we can access the configuration on it by using the +config+ method as done in the example. Because +Rails::Application+ inherits from +Rails::Railtie+ (indirectly), you can use the +initializer+ method in +config/application.rb+ to define initializers for the application. @@ -450,11 +470,11 @@ Serves as a placeholder so that +:load_environment_config+ can be defined to run *+load_active_support+* Requires +active_support/dependencies+ which sets up the basis for Active Support. Optionally requires +active_support/all+ if +config.active_support.bare+ is un-truthful, which is the default. -*+preload_frameworks+* Will load all autoload dependencies of Rails automatically if +config.preload_frameworks+ is +true+ or "truthful". By default this configuration option is disabled. In Rails, when internal classes are referenced for the first time they are autoloaded. +:preload_frameworks+ loads all of this at once on initialization. +*+preload_frameworks+* Loads all autoload dependencies of Rails automatically if +config.preload_frameworks+ is +true+ or "truthful". By default this configuration option is disabled. In Rails, when internal classes are referenced for the first time they are autoloaded. +:preload_frameworks+ loads all of this at once on initialization. -*+initialize_logger+* Initializes the logger (an +ActiveSupport::BufferedLogger+ object) for the application and makes it accessible at +Rails.logger+, providing that there's no initializer inserted before this point that has defined +Rails.logger+. +*+initialize_logger+* Initializes the logger (an +ActiveSupport::BufferedLogger+ object) for the application and makes it accessible at +Rails.logger+, provided that no initializer inserted before this point has defined +Rails.logger+. -*+initialize_cache+* If +RAILS_CACHE+ isn't yet set, initializes the cache by referencing the value in +config.cache_store+ and stores the outcome as +RAILS_CACHE+. If this object responds to the +middleware+ method, its middleware is inserted before +Rack::Runtime+ in the middleware stack. +*+initialize_cache+* If +RAILS_CACHE+ isn't set yet, initializes the cache by referencing the value in +config.cache_store+ and stores the outcome as +RAILS_CACHE+. If this object responds to the +middleware+ method, its middleware is inserted before +Rack::Runtime+ in the middleware stack. *+set_clear_dependencies_hook+* Provides a hook for +active_record.set_dispatch_hooks+ to use, which will run before this initializer. This initializer -- which runs only if +cache_classes+ is set to +false+ -- uses +ActionDispatch::Callbacks.after+ to remove the constants which have been referenced during the request from the object space so that they will be reloaded during the following request. @@ -464,7 +484,7 @@ Serves as a placeholder so that +:load_environment_config+ can be defined to run *+i18n.callbacks+* In the development environment, sets up a +to_prepare+ callback which will call +I18n.reload!+ if any of the locales have changed since the last request. In production mode this callback will only run on the first request. -*+active_support.initialize_whiny_nils+* Will require +active_support/whiny_nil+ if +config.whiny_nils+ is set to +true+. This file will output errors such as: +*+active_support.initialize_whiny_nils+* Requires +active_support/whiny_nil+ if +config.whiny_nils+ is set to +true+. This file will output errors such as: <plain> Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id @@ -480,19 +500,19 @@ The error occurred while evaluating nil.each *+active_support.deprecation_behavior+* Sets up deprecation reporting for environments, defaulting to +:log+ for development, +:notify+ for production and +:stderr+ for test. If a value isn't set for +config.active_support.deprecation+ then this initializer will prompt the user to configure this line in the current environment's +config/environments+ file. Can be set to an array of values. -*+active_support.initialize_time_zone+* Sets the default time zone for the application based off the +config.time_zone+ setting, which defaults to "UTC". +*+active_support.initialize_time_zone+* Sets the default time zone for the application based on the +config.time_zone+ setting, which defaults to "UTC". *+action_dispatch.configure+* Configures the +ActionDispatch::Http::URL.tld_length+ to be set to the value of +config.action_dispatch.tld_length+. -*+action_view.cache_asset_ids+* Will set +ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids+ to +false+ when Active Support loads, but only if +config.cache_classes+ is too. +*+action_view.cache_asset_ids+* Sets +ActionView::Helpers::AssetTagHelper::AssetPaths.cache_asset_ids+ to +false+ when Active Support loads, but only if +config.cache_classes+ is too. *+action_view.javascript_expansions+* Registers the expansions set up by +config.action_view.javascript_expansions+ and +config.action_view.stylesheet_expansions+ to be recognised by Action View and therefore usable in the views. *+action_view.set_configs+* Sets up Action View by using the settings in +config.action_view+ by +send+'ing the method names as setters to +ActionView::Base+ and passing the values through. -*+action_controller.logger+* Sets +ActionController::Base.logger+ -- if it's not already set -- to +Rails.logger+. +*+action_controller.logger+* Sets +ActionController::Base.logger+ -- if it's not already set -- to +Rails.logger+. -*+action_controller.initialize_framework_caches+* Sets +ActionController::Base.cache_store+ -- if it's not already set -- to +RAILS_CACHE+. +*+action_controller.initialize_framework_caches+* Sets +ActionController::Base.cache_store+ -- if it's not already set -- to +RAILS_CACHE+. *+action_controller.set_configs+* Sets up Action Controller by using the settings in +config.action_controller+ by +send+'ing the method names as setters to +ActionController::Base+ and passing the values through. @@ -506,9 +526,9 @@ The error occurred while evaluating nil.each *+active_record.initialize_database+* Loads the database configuration (by default) from +config/database.yml+ and establishes a connection for the current environment. -*+active_record.log_runtime+* Includes +ActiveRecord::Railties::ControllerRuntime+ which is responsible for reporting the length of time Active Record calls took for the request back to the logger. +*+active_record.log_runtime+* Includes +ActiveRecord::Railties::ControllerRuntime+ which is responsible for reporting the time taken by Active Record calls for the request back to the logger. -*+active_record.set_dispatch_hooks+* If +config.cache_classes+ is set to false, all reloadable connections to the database will be reset. +*+active_record.set_dispatch_hooks+* Resets all reloadable connections to the database if +config.cache_classes+ is set to +false+. *+action_mailer.logger+* Sets +ActionMailer::Base.logger+ -- if it's not already set -- to +Rails.logger+. @@ -536,10 +556,6 @@ The error occurred while evaluating nil.each *+load_config_initializers+* Loads all Ruby files from +config/initializers+ in the application, railties and engines. The files in this directory can be used to hold configuration settings that should be made after all of the frameworks and plugins are loaded. -NOTE: You can use subfolders to organize your initializers if you like, because Rails will look into the whole file hierarchy from the +initializers+ folder on down. - -TIP: If you have any ordering dependency in your initializers, you can control the load order by naming. For example, +01_critical.rb+ will be loaded before +02_normal.rb+. - *+engines_blank_point+* Provides a point-in-initialization to hook into if you wish to do anything before engines are loaded. After this point, all railtie and engine initializers are ran. *+add_generator_templates+* Finds templates for generators at +lib/templates+ for the application, railities and engines and adds these to the +config.generators.templates+ setting, which will make the templates available for all generators to reference. diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 953233d774..a2b2af98a6 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -105,14 +105,6 @@ module Rails self end - def load_generators(app=self) - initialize_generators - railties.all { |r| r.load_generators(app) } - Rails::Generators.configure!(app.config.generators) - super - self - end - def load_console(app=self) initialize_console railties.all { |r| r.load_console(app) } @@ -138,6 +130,10 @@ module Rails @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) end + def to_app + self + end + protected alias :build_middleware_stack :app @@ -195,10 +191,6 @@ module Rails end end - def initialize_generators - require "rails/generators" - end - def initialize_console require "pp" require "rails/console/app" diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index f22b4ef1f1..5e55aeada9 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -23,11 +23,7 @@ when 'generate', 'destroy', 'plugin' require APP_PATH Rails.application.require_environment! - if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH) - Rails.application.load_generators(engine) - else - Rails.application.load_generators - end + Rails.application.load_generators require "rails/commands/#{command}" end diff --git a/railties/lib/rails/commands/generate.rb b/railties/lib/rails/commands/generate.rb index b6f9a003d1..1fb2d98834 100644 --- a/railties/lib/rails/commands/generate.rb +++ b/railties/lib/rails/commands/generate.rb @@ -7,4 +7,6 @@ if ARGV.first.in?([nil, "-h", "--help"]) end name = ARGV.shift -Rails::Generators.invoke name, ARGV, :behavior => :invoke, :destination_root => Rails.root + +root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root +Rails::Generators.invoke name, ARGV, :behavior => :invoke, :destination_root => root diff --git a/railties/lib/rails/commands/server.rb b/railties/lib/rails/commands/server.rb index 91c87514cf..23392276d5 100644 --- a/railties/lib/rails/commands/server.rb +++ b/railties/lib/rails/commands/server.rb @@ -43,7 +43,7 @@ module Rails end def app - @app ||= super.instance + @app ||= super.respond_to?(:to_app) ? super.to_app : super end def opt_parser diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 383be1802f..b358de89d0 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -330,6 +330,14 @@ module Rails autoload :Configuration, "rails/engine/configuration" autoload :Railties, "rails/engine/railties" + def load_generators(app=self) + initialize_generators + railties.all { |r| r.load_generators(app) } + Rails::Generators.configure!(app.config.generators) + super + self + end + class << self attr_accessor :called_from, :isolated alias :isolated? :isolated @@ -567,6 +575,10 @@ module Rails protected + def initialize_generators + require "rails/generators" + end + def routes? defined?(@routes) end diff --git a/railties/lib/rails/engine/commands.rb b/railties/lib/rails/engine/commands.rb new file mode 100644 index 0000000000..3b0920e213 --- /dev/null +++ b/railties/lib/rails/engine/commands.rb @@ -0,0 +1,38 @@ +require 'active_support/core_ext/object/inclusion' + +ARGV << '--help' if ARGV.empty? + +aliases = { + "g" => "generate" +} + +command = ARGV.shift +command = aliases[command] || command + +require ENGINE_PATH +engine = ::Rails::Engine.find(ENGINE_ROOT) + +case command +when 'generate', 'destroy' + require 'rails/generators' + Rails::Generators.namespace = engine.railtie_namespace + engine.load_generators + require "rails/commands/#{command}" + +when '--version', '-v' + ARGV.unshift '--version' + require 'rails/commands/application' + +else + puts "Error: Command not recognized" unless command.in?(['-h', '--help']) + puts <<-EOT +Usage: rails COMMAND [ARGS] + +The common rails commands available for engines are: + generate Generate new code (short-cut alias: "g") + destroy Undo code generated with "generate" + +All commands can be run with -h for more information. + EOT + exit(1) +end diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb index 09e505a75b..355b05ce0b 100644 --- a/railties/lib/rails/generators.rb +++ b/railties/lib/rails/generators.rb @@ -20,6 +20,8 @@ module Rails autoload :ResourceHelpers, 'rails/generators/resource_helpers' autoload :TestCase, 'rails/generators/test_case' + mattr_accessor :namespace + DEFAULT_ALIASES = { :rails => { :actions => '-a', diff --git a/railties/lib/rails/generators/named_base.rb b/railties/lib/rails/generators/named_base.rb index 7e7f8d2d08..c6c0392f43 100644 --- a/railties/lib/rails/generators/named_base.rb +++ b/railties/lib/rails/generators/named_base.rb @@ -63,9 +63,7 @@ module Rails end def namespace - @namespace ||= if defined?(Rails) && Rails.application - Rails.application.class.parents.detect { |n| n.respond_to?(:_railtie) } - end + Rails::Generators.namespace end def namespaced? diff --git a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb index 11867a4cd7..807350316c 100644 --- a/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb +++ b/railties/lib/rails/generators/rails/plugin_new/plugin_new_generator.rb @@ -126,6 +126,8 @@ task :default => :test end def script(force = false) + return unless full? + directory "script", :force => force do |content| "#{shebang}\n" + content end diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt index 65d82abf6d..aa87d1b50c 100644 --- a/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt +++ b/railties/lib/rails/generators/rails/plugin_new/templates/script/rails.tt @@ -1,4 +1,7 @@ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. -ENGINE_PATH = File.expand_path('../..', __FILE__) -load File.expand_path('../../<%= dummy_path %>/script/rails', __FILE__) +ENGINE_ROOT = File.expand_path('../..', __FILE__) +ENGINE_PATH = File.expand_path('../../lib/<%= name -%>/engine', __FILE__) + +require 'rails/all' +require 'rails/engine/commands' diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 65c567d72f..5f50943626 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -1,6 +1,7 @@ require 'rails/initializable' require 'rails/configuration' require 'active_support/inflector' +require 'active_support/core_ext/module/introspection' module Rails # Railtie is the core of the Rails framework and provides several hooks to extend @@ -192,5 +193,9 @@ module Rails def load_generators(app) self.class.generators.each { |block| block.call(app) } end + + def railtie_namespace + @railtie_namespace ||= self.class.parents.detect { |n| n.respond_to?(:_railtie) } + end end end diff --git a/railties/lib/rails/tasks/assets.rake b/railties/lib/rails/tasks/assets.rake index 5f87edc9e2..4678ea460e 100644 --- a/railties/lib/rails/tasks/assets.rake +++ b/railties/lib/rails/tasks/assets.rake @@ -13,6 +13,9 @@ namespace :assets do assets = Rails.application.config.assets public_asset_path = Rails.public_path + assets.prefix file_list = FileList.new("#{public_asset_path}/*.js", "#{public_asset_path}/*.css") - file_list.each{ |file| rm file } + file_list.each do |file| + rm file + rm "#{file}.gz", :force => true + end end end diff --git a/railties/railties.gemspec b/railties/railties.gemspec index f1c92bd5d4..9c535f4f90 100644 --- a/railties/railties.gemspec +++ b/railties/railties.gemspec @@ -20,6 +20,7 @@ Gem::Specification.new do |s| s.add_dependency('rake', '>= 0.8.7') s.add_dependency('thor', '~> 0.14.6') s.add_dependency('rack-ssl', '~> 1.3.2') + s.add_dependency('rdoc', '~> 3.4') s.add_dependency('activesupport', version) s.add_dependency('actionpack', version) end diff --git a/railties/test/abstract_unit.rb b/railties/test/abstract_unit.rb index 8b38081667..1c3f8a701a 100644 --- a/railties/test/abstract_unit.rb +++ b/railties/test/abstract_unit.rb @@ -10,7 +10,6 @@ require 'active_support/core_ext/logger' require 'action_controller' require 'rails/all' -# TODO: Remove these hacks module TestApp class Application < Rails::Application config.root = File.dirname(__FILE__) diff --git a/railties/test/generators/namespaced_generators_test.rb b/railties/test/generators/namespaced_generators_test.rb index 17cbac0912..dd1e4bdac1 100644 --- a/railties/test/generators/namespaced_generators_test.rb +++ b/railties/test/generators/namespaced_generators_test.rb @@ -7,15 +7,7 @@ require 'rails/generators/rails/scaffold/scaffold_generator' class NamespacedGeneratorTestCase < Rails::Generators::TestCase def setup - TestApp::Application.isolate_namespace(TestApp) - end - - def teardown - if TestApp.respond_to?(:_railtie) - TestApp.singleton_class.send(:undef_method, :_railtie) - TestApp.singleton_class.send(:undef_method, :table_name_prefix) - TestApp::Application.isolated = false - end + Rails::Generators.namespace = TestApp end end diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index b272638026..283d99dd9e 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -12,7 +12,6 @@ DEFAULT_PLUGIN_FILES = %w( lib lib/bukkits.rb lib/tasks/bukkits_tasks.rake - script/rails test/bukkits_test.rb test/test_helper.rb test/dummy @@ -172,6 +171,7 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "config/routes.rb", /Rails.application.routes.draw do/ assert_file "lib/bukkits/engine.rb", /module Bukkits\n class Engine < ::Rails::Engine\n end\nend/ assert_file "lib/bukkits.rb", /require "bukkits\/engine"/ + assert_file "script/rails" end def test_being_quiet_while_creating_dummy_application @@ -199,8 +199,16 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase assert_file "bukkits.gemspec", /s.version = "0.0.1"/ end + def test_usage_of_engine_commands + run_generator [destination_root, "--full"] + assert_file "script/rails", /ENGINE_PATH = File.expand_path\('..\/..\/lib\/bukkits\/engine', __FILE__\)/ + assert_file "script/rails", /ENGINE_ROOT = File.expand_path\('..\/..', __FILE__\)/ + assert_file "script/rails", /require 'rails\/all'/ + assert_file "script/rails", /require 'rails\/engine\/commands'/ + end + def test_shebang - run_generator + run_generator [destination_root, "--full"] assert_file "script/rails", /#!\/usr\/bin\/env ruby/ end @@ -254,7 +262,6 @@ class CustomPluginGeneratorTest < Rails::Generators::TestCase assert_file 'spec/dummy' assert_file 'Rakefile', /task :default => :spec/ assert_file 'Rakefile', /# spec tasks in rakefile/ - assert_file 'script/rails', %r{spec/dummy} end protected diff --git a/railties/test/generators/shared_generator_tests.rb b/railties/test/generators/shared_generator_tests.rb index be9aef8a41..d3074afd91 100644 --- a/railties/test/generators/shared_generator_tests.rb +++ b/railties/test/generators/shared_generator_tests.rb @@ -67,12 +67,12 @@ module SharedGeneratorTests end def test_shebang_is_added_to_rails_file - run_generator [destination_root, "--ruby", "foo/bar/baz"] + run_generator [destination_root, "--ruby", "foo/bar/baz", "--full"] assert_file "script/rails", /#!foo\/bar\/baz/ end def test_shebang_when_is_the_same_as_default_use_env - run_generator [destination_root, "--ruby", Thor::Util.ruby_command] + run_generator [destination_root, "--ruby", Thor::Util.ruby_command, "--full"] assert_file "script/rails", /#!\/usr\/bin\/env/ end diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb index 335e639692..0a203fd4d0 100644 --- a/railties/test/isolation/abstract_unit.rb +++ b/railties/test/isolation/abstract_unit.rb @@ -287,4 +287,4 @@ Module.new do end f.puts "require 'rails/all'" end -end +end unless defined?(RAILS_ISOLATED_ENGINE) diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 44cee2b164..0ff1e0f180 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -15,7 +15,7 @@ module RailtiesTest @plugin = engine "bukkits" do |plugin| plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine railtie_name "bukkits" end @@ -36,7 +36,7 @@ module RailtiesTest test "initializers are executed after application configuration initializers" do @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine initializer "dummy_initializer" do end @@ -77,7 +77,7 @@ module RailtiesTest add_to_config("config.action_dispatch.show_exceptions = false") @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, ['Hello World']] } config.middleware.use ::RailtiesTest::EngineTest::Upcaser @@ -127,7 +127,7 @@ module RailtiesTest test "it provides routes as default endpoint" do @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine end end @@ -153,7 +153,7 @@ module RailtiesTest test "engine can load its own plugins" do @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine end end @@ -170,7 +170,7 @@ module RailtiesTest test "engine does not load plugins that already exists in application" do @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine end end @@ -193,7 +193,7 @@ module RailtiesTest test "it loads its environment file" do @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine end end @@ -212,7 +212,7 @@ module RailtiesTest test "it passes router in env" do @plugin.write "lib/bukkits.rb", <<-RUBY - class Bukkits + module Bukkits class Engine < ::Rails::Engine endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, 'hello'] } end diff --git a/railties/test/railties/generators_test.rb b/railties/test/railties/generators_test.rb new file mode 100644 index 0000000000..fe59dcd52b --- /dev/null +++ b/railties/test/railties/generators_test.rb @@ -0,0 +1,115 @@ +RAILS_ISOLATED_ENGINE = true +require "isolation/abstract_unit" + +require "#{RAILS_FRAMEWORK_ROOT}/railties/lib/rails/generators/test_case" + +module RailtiesTests + class GeneratorTest < Rails::Generators::TestCase + include ActiveSupport::Testing::Isolation + + TMP_PATH = File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. tmp])) + self.destination_root = File.join(TMP_PATH, "foo_bar") + + def tmp_path(*args) + File.join(TMP_PATH, *args) + end + + def engine_path + tmp_path('foo_bar') + end + + def bundled_rails(cmd) + `bundle exec rails #{cmd}` + end + + def rails(cmd) + environment = File.expand_path('../../../../load_paths', __FILE__) + if File.exist?("#{environment}.rb") + require_environment = "-r #{environment}" + end + `#{Gem.ruby} #{require_environment} #{RAILS_FRAMEWORK_ROOT}/bin/rails #{cmd}` + end + + def build_engine(is_mountable=false) + FileUtils.mkdir_p(engine_path) + FileUtils.rm_r(engine_path) + + mountable = is_mountable ? "--mountable" : "" + + rails("plugin new #{engine_path} --full #{mountable}") + + Dir.chdir(engine_path) do + File.open("Gemfile", "w") do |f| + f.write <<-GEMFILE.gsub(/^ {12}/, '') + source "http://rubygems.org" + + gem 'rails', :path => '#{RAILS_FRAMEWORK_ROOT}' + gem 'sqlite3' + + if RUBY_VERSION < '1.9' + gem "ruby-debug", ">= 0.10.3" + end + GEMFILE + end + end + end + + def build_mountable_engine + build_engine(true) + end + + def test_controllers_are_correctly_namespaced_when_engine_is_mountable + build_mountable_engine + Dir.chdir(engine_path) do + bundled_rails("g controller topics") + assert_file "app/controllers/foo_bar/topics_controller.rb", /module FooBar\n class TopicsController/ + assert_no_file "app/controllers/topics_controller.rb" + end + end + + def test_models_are_correctly_namespaced_when_engine_is_mountable + build_mountable_engine + Dir.chdir(engine_path) do + bundled_rails("g model topic") + assert_file "app/models/foo_bar/topic.rb", /module FooBar\n class Topic/ + assert_no_file "app/models/topic.rb" + end + end + + def test_helpers_are_correctly_namespaced_when_engine_is_mountable + build_mountable_engine + Dir.chdir(engine_path) do + bundled_rails("g helper topics") + assert_file "app/helpers/foo_bar/topics_helper.rb", /module FooBar\n module TopicsHelper/ + assert_no_file "app/helpers/topics_helper.rb" + end + end + + def test_controllers_are_not_namespaced_when_engine_is_not_mountable + build_engine + Dir.chdir(engine_path) do + bundled_rails("g controller topics") + assert_file "app/controllers/topics_controller.rb", /class TopicsController/ + assert_no_file "app/controllers/foo_bar/topics_controller.rb" + end + end + + def test_models_are_not_namespaced_when_engine_is_not_mountable + build_engine + Dir.chdir(engine_path) do + bundled_rails("g model topic") + assert_file "app/models/topic.rb", /class Topic/ + assert_no_file "app/models/foo_bar/topic.rb" + end + end + + def test_helpers_are_not_namespaced_when_engine_is_not_mountable + build_engine + Dir.chdir(engine_path) do + bundled_rails("g helper topics") + assert_file "app/helpers/topics_helper.rb", /module TopicsHelper/ + assert_no_file "app/helpers/foo_bar/topics_helper.rb" + end + end + end +end diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb index 659551d08a..d8ea58166e 100644 --- a/railties/test/railties/shared_tests.rb +++ b/railties/test/railties/shared_tests.rb @@ -54,7 +54,7 @@ module RailtiesTest add_to_config "ActiveRecord::Base.timestamped_migrations = false" Dir.chdir(app_path) do - output = `rake bukkits:install:migrations` + output = `bundle exec rake bukkits:install:migrations` assert File.exists?("#{app_path}/db/migrate/2_create_users.rb") assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.rb") @@ -63,7 +63,7 @@ module RailtiesTest assert_match /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length - output = `rake railties:install:migrations` + output = `bundle exec rake railties:install:migrations` assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.rb") assert_match /NOTE: Migration 3_create_sessions.rb from bukkits has been skipped/, output @@ -71,7 +71,7 @@ module RailtiesTest assert_no_match /2_create_users/, output migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length - output = `rake railties:install:migrations` + output = `bundle exec rake railties:install:migrations` assert_equal migrations_count, Dir["#{app_path}/db/migrate/*.rb"].length end |