diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2010-01-03 22:27:28 -0800 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2010-01-03 22:27:28 -0800 |
commit | 5e94d3e3ea06e577d97a32eb4b38b61c4ce8ff8f (patch) | |
tree | b89d06302223be67c595e65bffce54357d41a15a /actionpack | |
parent | d7d917335e242f48fae31bc99e6d4ab381244913 (diff) | |
parent | eca11bfdb5d3cf375faf8a24e2dc0cc5abd20f92 (diff) | |
download | rails-5e94d3e3ea06e577d97a32eb4b38b61c4ce8ff8f.tar.gz rails-5e94d3e3ea06e577d97a32eb4b38b61c4ce8ff8f.tar.bz2 rails-5e94d3e3ea06e577d97a32eb4b38b61c4ce8ff8f.zip |
Merge
Diffstat (limited to 'actionpack')
17 files changed, 171 insertions, 38 deletions
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index 69ed84da95..5c0d754ad6 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -62,9 +62,9 @@ module ActionController #:nodoc: end def log_event(name, before, after, instrumenter_id, payload) - if name.to_s =~ /(read|write|cache|expire|exist)_(fragment|page)\??/ + if name.to_s =~ /action_controller\.((read|write|expire|exist)_(fragment|page)\??)/ key_or_path = payload[:key] || payload[:path] - human_name = name.to_s.humanize + human_name = $1.humanize duration = (after - before) * 1000 logger.info("#{human_name} #{key_or_path.inspect} (%.1fms)" % duration) else diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb index f569d0dd8b..a0c5ed797e 100644 --- a/actionpack/lib/action_controller/caching/fragments.rb +++ b/actionpack/lib/action_controller/caching/fragments.rb @@ -53,7 +53,7 @@ module ActionController #:nodoc: return content unless cache_configured? key = fragment_cache_key(key) - ActiveSupport::Notifications.instrument(:write_fragment, :key => key) do + instrument_fragment_cache :write_fragment, key do cache_store.write(key, content, options) end content @@ -64,7 +64,7 @@ module ActionController #:nodoc: return unless cache_configured? key = fragment_cache_key(key) - ActiveSupport::Notifications.instrument(:read_fragment, :key => key) do + instrument_fragment_cache :read_fragment, key do cache_store.read(key, options) end end @@ -74,7 +74,7 @@ module ActionController #:nodoc: return unless cache_configured? key = fragment_cache_key(key) - ActiveSupport::Notifications.instrument(:exist_fragment?, :key => key) do + instrument_fragment_cache :exist_fragment?, key do cache_store.exist?(key, options) end end @@ -101,16 +101,18 @@ module ActionController #:nodoc: key = fragment_cache_key(key) unless key.is_a?(Regexp) message = nil - ActiveSupport::Notifications.instrument(:expire_fragment, :key => key) do + instrument_fragment_cache :expire_fragment, key do if key.is_a?(Regexp) - message = "Expired fragments matching: #{key.source}" cache_store.delete_matched(key, options) else - message = "Expired fragment: #{key}" cache_store.delete(key, options) end end end + + def instrument_fragment_cache(name, key) + ActiveSupport::Notifications.instrument("action_controller.#{name}", :key => key){ yield } + end end end end diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb index d46f528c7e..5797eeebd6 100644 --- a/actionpack/lib/action_controller/caching/pages.rb +++ b/actionpack/lib/action_controller/caching/pages.rb @@ -64,7 +64,7 @@ module ActionController #:nodoc: return unless perform_caching path = page_cache_path(path) - ActiveSupport::Notifications.instrument(:expire_page, :path => path) do + instrument_page_cache :expire_page, path do File.delete(path) if File.exist?(path) end end @@ -75,7 +75,7 @@ module ActionController #:nodoc: return unless perform_caching path = page_cache_path(path) - ActiveSupport::Notifications.instrument(:cache_page, :path => path) do + instrument_page_cache :write_page, path do FileUtils.makedirs(File.dirname(path)) File.open(path, "wb+") { |f| f.write(content) } end @@ -107,6 +107,10 @@ module ActionController #:nodoc: def page_cache_path(path) page_cache_directory + page_cache_file(path) end + + def instrument_page_cache(name, path) + ActiveSupport::Notifications.instrument("action_controller.#{name}", :path => path){ yield } + end end # Expires the page that was cached with the +options+ as a key. Example: diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb index 4f4370e5f0..bf5f3b774f 100644 --- a/actionpack/lib/action_controller/metal/logger.rb +++ b/actionpack/lib/action_controller/metal/logger.rb @@ -15,7 +15,8 @@ module ActionController attr_internal :view_runtime def process_action(action) - ActiveSupport::Notifications.instrument(:process_action, :controller => self, :action => action) do + ActiveSupport::Notifications.instrument("action_controller.process_action", + :controller => self, :action => action) do super end end @@ -50,7 +51,7 @@ module ActionController # This is the hook invoked by ActiveSupport::Notifications.subscribe. # If you need to log any event, overwrite the method and do it here. def log_event(name, before, after, instrumenter_id, payload) #:nodoc: - if name == :process_action + if name == "action_controller.process_action" duration = [(after - before) * 1000, 0.01].max controller = payload[:controller] request = controller.request @@ -66,7 +67,7 @@ module ActionController message << " [#{request.request_uri rescue "unknown"}]" logger.info(message) - elsif name == :render_template + elsif name == "action_view.render_template" # TODO Make render_template logging work if you are using just ActionView duration = (after - before) * 1000 message = "Rendered #{payload[:identifier]}" diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index f27f22c7e7..04a101dbb2 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -179,7 +179,7 @@ module ActionDispatch 'cookie containing the session data. Use ' + 'config.action_controller.session = { :key => ' + '"_myapp_session", :secret => "some secret phrase" } in ' + - 'config/environment.rb' + 'config/application.rb' end end diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 4ebc8a2ab9..af356707c6 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -1,7 +1,24 @@ require 'active_support/core_ext/exception' +require 'active_support/notifications' require 'action_dispatch/http/request' module ActionDispatch + # This middleware rescues any exception returned by the application and renders + # nice exception pages if it's being rescued locally. + # + # Every time an exception is caught, a notification is published, becoming a good API + # to deal with exceptions. So, if you want send an e-mail through ActionMailer + # everytime this notification is published, you just need to do the following: + # + # ActiveSupport::Notifications.subscribe "action_dispatch.show_exception" do |name, start, end, instrumentation_id, payload| + # ExceptionNotifier.deliver_exception(start, payload) + # end + # + # The payload is a hash which has to pairs: + # + # * :env - Contains the rack env for the given request; + # * :exception - The exception raised; + # class ShowExceptions LOCALHOST = '127.0.0.1'.freeze @@ -44,8 +61,11 @@ module ActionDispatch def call(env) @app.call(env) rescue Exception => exception - raise exception if env['action_dispatch.show_exceptions'] == false - render_exception(env, exception) + ActiveSupport::Notifications.instrument 'action_dispatch.show_exception', + :env => env, :exception => exception do + raise exception if env['action_dispatch.show_exceptions'] == false + render_exception(env, exception) + end end private diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index d69e5109fa..4970c768e8 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -274,6 +274,7 @@ module ActionView #:nodoc: end def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc: + @config = nil @formats = formats @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } @controller = controller diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index d0c66eda60..81c9c88820 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -504,8 +504,9 @@ module ActionView end # Returns a label tag tailored for labelling an input field for a specified attribute (identified by +method+) on an object - # assigned to the template (identified by +object+). The text of label will default to the attribute name unless you specify - # it explicitly. Additional options on the label tag can be passed as a hash with +options+. These options will be tagged + # assigned to the template (identified by +object+). The text of label will default to the attribute name unless a translation + # is found in the current I18n locale (through views.labels.<modelname>.<attribute>) or you specify it explicitly. + # Additional options on the label tag can be passed as a hash with +options+. These options will be tagged # onto the HTML as an HTML element attribute as in the example shown, except for the <tt>:value</tt> option, which is designed to # target labels for radio_button tags (where the value is used in the ID of the input tag). # @@ -513,6 +514,29 @@ module ActionView # label(:post, :title) # # => <label for="post_title">Title</label> # + # You can localize your labels based on model and attribute names. + # For example you can define the following in your locale (e.g. en.yml) + # + # views: + # labels: + # post: + # body: "Write your entire text here" + # + # Which then will result in + # + # label(:post, :body) + # # => <label for="post_body">Write your entire text here</label> + # + # Localization can also be based purely on the translation of the attribute-name like this: + # + # activemodel: + # attribute: + # post: + # cost: "Total cost" + # + # label(:post, :cost) + # # => <label for="post_cost">Total cost</label> + # # label(:post, :title, "A short title") # # => <label for="post_title">A short title</label> # @@ -751,7 +775,19 @@ module ActionView add_default_name_and_id_for_value(tag_value, name_and_id) options.delete("index") options["for"] ||= name_and_id["id"] - content = (text.blank? ? nil : text.to_s) || method_name.humanize + + content = if text.blank? + I18n.t("views.labels.#{object_name}.#{method_name}", :default => "").presence + else + text.to_s + end + + content ||= if object && object.class.respond_to?(:human_attribute_name) + object.class.human_attribute_name(method_name) + end + + content ||= method_name.humanize + label_tag(name_and_id["id"], content, options) end diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 5158415c20..67a8ee4472 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -215,12 +215,13 @@ module ActionView options = @options if @collection - ActiveSupport::Notifications.instrument(:render_collection, :path => @path, - :count => @collection.size) do + ActiveSupport::Notifications.instrument("action_view.render_collection", + :path => @path, :count => @collection.size) do render_collection end else - content = ActiveSupport::Notifications.instrument(:render_partial, :path => @path) do + content = ActiveSupport::Notifications.instrument("action_view.render_partial", + :path => @path) do render_partial end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 48316cac53..2fdfad694d 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -93,7 +93,7 @@ module ActionView def _render_template(template, layout = nil, options = {}) locals = options[:locals] || {} - content = ActiveSupport::Notifications.instrument(:render_template, + content = ActiveSupport::Notifications.instrument("action_view.render_template", :identifier => template.identifier, :layout => (layout ? layout.identifier : nil)) do template.render(self, locals) end @@ -109,7 +109,8 @@ module ActionView end def _render_layout(layout, locals, &block) - ActiveSupport::Notifications.instrument(:render_layout, :identifier => layout.identifier) do + ActiveSupport::Notifications.instrument("action_view.render_layout", + :identifier => layout.identifier) do layout.render(self, locals){ |*name| _layout_for(*name, &block) } end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 8c65087898..c1aebefc77 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -96,7 +96,6 @@ class ActiveSupport::TestCase end class MockLogger - attr_reader :logged attr_accessor :level def initialize @@ -108,6 +107,10 @@ class MockLogger @logged << args.first @logged << blk.call if block_given? end + + def logged + @logged.compact.map { |l| l.to_s.strip } + end end class ActionController::IntegrationTest < ActiveSupport::TestCase diff --git a/actionpack/test/activerecord/controller_runtime_test.rb b/actionpack/test/activerecord/controller_runtime_test.rb index 0f534da14b..9525dd8307 100644 --- a/actionpack/test/activerecord/controller_runtime_test.rb +++ b/actionpack/test/activerecord/controller_runtime_test.rb @@ -23,9 +23,11 @@ class ARLoggingTest < ActionController::TestCase end def test_log_with_active_record + # Wait pending notifications to be published + wait get :show wait - assert_match /ActiveRecord runtime/, logs[3] + assert_match /ActiveRecord runtime/, @controller.logger.logged[3] end private @@ -33,7 +35,4 @@ class ARLoggingTest < ActionController::TestCase @controller.logger = MockLogger.new end - def logs - @logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip} - end end diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 679eaf7b38..5a8dc0c358 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -630,17 +630,17 @@ class FragmentCachingTest < ActionController::TestCase end def test_fragment_for_logging - fragment_computed = false - events = [] - ActiveSupport::Notifications.subscribe { |*args| events << args } + # Wait pending notifications to be published + ActiveSupport::Notifications.notifier.wait + @controller.logger = MockLogger.new - buffer = 'generated till now -> ' - @controller.fragment_for(buffer, 'expensive') { fragment_computed = true } + fragment_computed = false + @controller.fragment_for('buffer', 'expensive') { fragment_computed = true } + ActiveSupport::Notifications.notifier.wait assert fragment_computed - assert_equal 'generated till now -> ', buffer - ActiveSupport::Notifications.notifier.wait - assert_equal [:exist_fragment?, :write_fragment], events.map(&:first) + assert_match /Exist fragment\? "views\/expensive"/, @controller.logger.logged[0] + assert_match /Write fragment "views\/expensive"/, @controller.logger.logged[1] end end diff --git a/actionpack/test/controller/logging_test.rb b/actionpack/test/controller/logging_test.rb index 4206dffa7e..594cf17312 100644 --- a/actionpack/test/controller/logging_test.rb +++ b/actionpack/test/controller/logging_test.rb @@ -19,6 +19,7 @@ class LoggingTest < ActionController::TestCase def setup super + wait # Wait pending notifications to be published set_logger end @@ -75,6 +76,6 @@ class LoggingTest < ActionController::TestCase end def logs - @logs ||= @controller.logger.logged.compact.map {|l| l.to_s.strip} + @logs ||= @controller.logger.logged end end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 9f6a93756c..951fb4a22e 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -104,4 +104,27 @@ class ShowExceptionsTest < ActionController::IntegrationTest assert_response 405 assert_match /ActionController::MethodNotAllowed/, body end + + test "publishes notifications" do + # Wait pending notifications to be published + ActiveSupport::Notifications.notifier.wait + + @app, event = ProductionApp, nil + self.remote_addr = '127.0.0.1' + + ActiveSupport::Notifications.subscribe('action_dispatch.show_exception') do |*args| + event = args + end + + get "/" + assert_response 500 + assert_match /puke/, body + + ActiveSupport::Notifications.notifier.wait + + assert_equal 'action_dispatch.show_exception', event.first + assert_kind_of Hash, event.last[:env] + assert_equal 'GET', event.last[:env]["REQUEST_METHOD"] + assert_kind_of RuntimeError, event.last[:exception] + end end diff --git a/actionpack/test/lib/controller/fake_models.rb b/actionpack/test/lib/controller/fake_models.rb index 823de8bdc7..b0e5d7a94c 100644 --- a/actionpack/test/lib/controller/fake_models.rb +++ b/actionpack/test/lib/controller/fake_models.rb @@ -54,6 +54,7 @@ end class Post < Struct.new(:title, :author_name, :body, :secret, :written_on, :cost) extend ActiveModel::Naming include ActiveModel::Conversion + extend ActiveModel::Translation alias_method :secret?, :secret diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb index 44734abb18..b1e9fe99a2 100644 --- a/actionpack/test/template/form_helper_test.rb +++ b/actionpack/test/template/form_helper_test.rb @@ -6,6 +6,25 @@ class FormHelperTest < ActionView::TestCase def setup super + + # Create "label" locale for testing I18n label helpers + I18n.backend.store_translations 'label', { + :activemodel => { + :attributes => { + :post => { + :cost => "Total cost" + } + } + }, + :views => { + :labels => { + :post => { + :body => "Write entire text here" + } + } + } + } + @post = Post.new @comment = Comment.new def @post.errors() @@ -51,6 +70,27 @@ class FormHelperTest < ActionView::TestCase assert_dom_equal('<label for="post_secret">Secret?</label>', label(:post, :secret?)) end + def test_label_with_locales_strings + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal('<label for="post_body">Write entire text here</label>', label("post", "body")) + ensure + I18n.locale = old_locale + end + + def test_label_with_human_attribute_name + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal('<label for="post_cost">Total cost</label>', label(:post, :cost)) + ensure + I18n.locale = old_locale + end + + def test_label_with_locales_symbols + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal('<label for="post_body">Write entire text here</label>', label(:post, :body)) + ensure + I18n.locale = old_locale + end + def test_label_with_for_attribute_as_symbol assert_dom_equal('<label for="my_for">Title</label>', label(:post, :title, nil, :for => "my_for")) end |