diff options
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/abstract_controller/base.rb | 15 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/layouts.rb | 158 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/rendering.rb | 14 | ||||
-rw-r--r-- | actionpack/lib/action_controller.rb | 16 | ||||
-rw-r--r-- | actionpack/lib/action_controller/base.rb | 3 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal.rb | 15 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/layouts.rb | 171 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/logger.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/rendering.rb | 12 | ||||
-rw-r--r-- | actionpack/lib/action_controller/railtie.rb (renamed from actionpack/lib/action_controller/rails.rb) | 5 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/form_helper.rb | 42 | ||||
-rw-r--r-- | actionpack/lib/action_view/railtie.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/render/rendering.rb | 44 |
13 files changed, 258 insertions, 243 deletions
diff --git a/actionpack/lib/abstract_controller/base.rb b/actionpack/lib/abstract_controller/base.rb index efea81aa71..a6889d5d01 100644 --- a/actionpack/lib/abstract_controller/base.rb +++ b/actionpack/lib/abstract_controller/base.rb @@ -72,6 +72,16 @@ module AbstractController # And always exclude explicitly hidden actions hidden_actions end + + # Returns the full controller name, underscored, without the ending Controller. + # For instance, MyApp::MyPostsController would return "my_app/my_posts" for + # controller_name. + # + # ==== Returns + # String + def controller_path + @controller_path ||= name && name.sub(/Controller$/, '').underscore + end end abstract! @@ -96,6 +106,11 @@ module AbstractController process_action(action_name, *args) end + # Delegates to the class' #controller_path + def controller_path + self.class.controller_path + end + private # Returns true if the name can be considered an action. This can # be overridden in subclasses to modify the semantics of what diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 4073e9b386..6fbf6bc392 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -1,4 +1,160 @@ module AbstractController + # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in + # repeated setups. The inclusion pattern has pages that look like this: + # + # <%= render "shared/header" %> + # Hello World + # <%= render "shared/footer" %> + # + # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose + # and if you ever want to change the structure of these two includes, you'll have to change all the templates. + # + # With layouts, you can flip it around and have the common structure know where to insert changing content. This means + # that the header and footer are only mentioned in one place, like this: + # + # // The header part of this layout + # <%= yield %> + # // The footer part of this layout + # + # And then you have content pages that look like this: + # + # hello world + # + # At rendering time, the content page is computed and then inserted in the layout, like this: + # + # // The header part of this layout + # hello world + # // The footer part of this layout + # + # == Accessing shared variables + # + # Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with + # references that won't materialize before rendering time: + # + # <h1><%= @page_title %></h1> + # <%= yield %> + # + # ...and content pages that fulfill these references _at_ rendering time: + # + # <% @page_title = "Welcome" %> + # Off-world colonies offers you a chance to start a new life + # + # The result after rendering is: + # + # <h1>Welcome</h1> + # Off-world colonies offers you a chance to start a new life + # + # == Layout assignment + # + # You can either specify a layout declaratively (using the #layout class method) or give + # it the same name as your controller, and place it in <tt>app/views/layouts</tt>. + # If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance. + # + # For instance, if you have PostsController and a template named <tt>app/views/layouts/posts.html.erb</tt>, + # that template will be used for all actions in PostsController and controllers inheriting + # from PostsController. + # + # If you use a module, for instance Weblog::PostsController, you will need a template named + # <tt>app/views/layouts/weblog/posts.html.erb</tt>. + # + # Since all your controllers inherit from ApplicationController, they will use + # <tt>app/views/layouts/application.html.erb</tt> if no other layout is specified + # or provided. + # + # == Inheritance Examples + # + # class BankController < ActionController::Base + # layout "bank_standard" + # + # class InformationController < BankController + # + # class TellerController < BankController + # # teller.html.erb exists + # + # class TillController < TellerController + # + # class VaultController < BankController + # layout :access_level_layout + # + # class EmployeeController < BankController + # layout nil + # + # The InformationController uses "bank_standard" inherited from the BankController, the VaultController overwrites + # and picks the layout dynamically, and the EmployeeController doesn't want to use a layout at all. + # + # The TellerController uses +teller.html.erb+, and TillController inherits that layout and + # uses it as well. + # + # == Types of layouts + # + # Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes + # you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can + # be done either by specifying a method reference as a symbol or using an inline method (as a proc). + # + # The method reference is the preferred approach to variable layouts and is used like this: + # + # class WeblogController < ActionController::Base + # layout :writers_and_readers + # + # def index + # # fetching posts + # end + # + # private + # def writers_and_readers + # logged_in? ? "writer_layout" : "reader_layout" + # end + # + # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing + # is logged in or not. + # + # If you want to use an inline method, such as a proc, do something like this: + # + # class WeblogController < ActionController::Base + # layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" } + # + # Of course, the most common way of specifying a layout is still just as a plain template name: + # + # class WeblogController < ActionController::Base + # layout "weblog_standard" + # + # If no directory is specified for the template name, the template will by default be looked for in <tt>app/views/layouts/</tt>. + # Otherwise, it will be looked up relative to the template root. + # + # == Conditional layouts + # + # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering + # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The + # <tt>:only</tt> and <tt>:except</tt> options can be passed to the layout call. For example: + # + # class WeblogController < ActionController::Base + # layout "weblog_standard", :except => :rss + # + # # ... + # + # end + # + # This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout + # around the rendered view. + # + # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so + # #<tt>:except => [ :rss, :text_only ]</tt> is valid, as is <tt>:except => :rss</tt>. + # + # == Using a different layout in the action render call + # + # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above. + # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller. + # You can do this by passing a <tt>:layout</tt> option to the <tt>render</tt> call. For example: + # + # class WeblogController < ActionController::Base + # layout "weblog_standard" + # + # def help + # render :action => "help", :layout => "help" + # end + # end + # + # This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout. module Layouts extend ActiveSupport::Concern @@ -89,7 +245,7 @@ module AbstractController # ==== Returns # String:: A template name def _implied_layout_name - name && name.underscore + controller_path end # Takes the specified layout and creates a _layout method to be called diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 64a8a5f241..332d86b089 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -1,5 +1,4 @@ require "abstract_controller/base" -require "abstract_controller/logger" module AbstractController class DoubleRenderError < Error @@ -13,8 +12,6 @@ module AbstractController module Rendering extend ActiveSupport::Concern - include AbstractController::Logger - included do extlib_inheritable_accessor :_view_paths self._view_paths ||= ActionView::PathSet.new @@ -67,7 +64,7 @@ module AbstractController def render_to_body(options = {}) # TODO: Refactor so we can just use the normal template logic for this if options.key?(:partial) - view_context.render_partial(options) + _render_partial(options) else _determine_template(options) _render_template(options) @@ -87,11 +84,18 @@ module AbstractController # ==== Options # _template<ActionView::Template>:: The template to render # _layout<ActionView::Template>:: The layout to wrap the template in (optional) - # _partial<TrueClass, FalseClass>:: Whether or not the template to be rendered is a partial def _render_template(options) view_context.render_template(options) end + # Renders the given partial. + # + # ==== Options + # partial<String|Object>:: The partial name or the object to be rendered + def _render_partial(options) + view_context.render_partial(options) + end + # The list of view paths for this controller. See ActionView::ViewPathSet for # more details about writing custom view paths. def view_paths diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 26a85d4de8..d66fc3fcc9 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -13,31 +13,29 @@ module ActionController autoload :Middleware autoload_under "metal" do - autoload :Benchmarking + autoload :Compatibility autoload :ConditionalGet autoload :Configuration + autoload :Cookies + autoload :FilterParameterLogging + autoload :Flash autoload :Head autoload :Helpers autoload :HideActions - autoload :Layouts + autoload :HttpAuthentication autoload :Logger autoload :MimeResponds autoload :RackDelegation - autoload :Compatibility autoload :Redirecting autoload :Rendering autoload :Renderers + autoload :RequestForgeryProtection autoload :Rescue autoload :Responder autoload :SessionManagement + autoload :Streaming autoload :UrlFor autoload :Verification - autoload :Flash - autoload :RequestForgeryProtection - autoload :Streaming - autoload :HttpAuthentication - autoload :FilterParameterLogging - autoload :Cookies end autoload :Dispatcher, 'action_controller/dispatch/dispatcher' diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 67656110c4..b23be66910 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -3,7 +3,7 @@ module ActionController abstract! include AbstractController::Callbacks - include AbstractController::Logger + include AbstractController::Layouts include ActionController::Helpers include ActionController::HideActions @@ -11,7 +11,6 @@ module ActionController include ActionController::Redirecting include ActionController::Rendering include ActionController::Renderers::All - include ActionController::Layouts include ActionController::ConditionalGet include ActionController::RackDelegation include ActionController::Logger diff --git a/actionpack/lib/action_controller/metal.rb b/actionpack/lib/action_controller/metal.rb index f445ca70ee..1819c0f886 100644 --- a/actionpack/lib/action_controller/metal.rb +++ b/actionpack/lib/action_controller/metal.rb @@ -28,21 +28,6 @@ module ActionController self.class.controller_name end - # Returns the full controller name, underscored, without the ending Controller. - # For instance, MyApp::MyPostsController would return "my_app/my_posts" for - # controller_name. - # - # ==== Returns - # String - def self.controller_path - @controller_path ||= name && name.sub(/Controller$/, '').underscore - end - - # Delegates to the class' #controller_path - def controller_path - self.class.controller_path - end - # The details below can be overridden to support a specific # Request and Response object. The default ActionController::Base # implementation includes RackDelegation, which makes a request diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb deleted file mode 100644 index f44498a884..0000000000 --- a/actionpack/lib/action_controller/metal/layouts.rb +++ /dev/null @@ -1,171 +0,0 @@ -module ActionController - # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in - # repeated setups. The inclusion pattern has pages that look like this: - # - # <%= render "shared/header" %> - # Hello World - # <%= render "shared/footer" %> - # - # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose - # and if you ever want to change the structure of these two includes, you'll have to change all the templates. - # - # With layouts, you can flip it around and have the common structure know where to insert changing content. This means - # that the header and footer are only mentioned in one place, like this: - # - # // The header part of this layout - # <%= yield %> - # // The footer part of this layout - # - # And then you have content pages that look like this: - # - # hello world - # - # At rendering time, the content page is computed and then inserted in the layout, like this: - # - # // The header part of this layout - # hello world - # // The footer part of this layout - # - # == Accessing shared variables - # - # Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with - # references that won't materialize before rendering time: - # - # <h1><%= @page_title %></h1> - # <%= yield %> - # - # ...and content pages that fulfill these references _at_ rendering time: - # - # <% @page_title = "Welcome" %> - # Off-world colonies offers you a chance to start a new life - # - # The result after rendering is: - # - # <h1>Welcome</h1> - # Off-world colonies offers you a chance to start a new life - # - # == Layout assignment - # - # You can either specify a layout declaratively (using the #layout class method) or give - # it the same name as your controller, and place it in <tt>app/views/layouts</tt>. - # If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance. - # - # For instance, if you have PostsController and a template named <tt>app/views/layouts/posts.html.erb</tt>, - # that template will be used for all actions in PostsController and controllers inheriting - # from PostsController. - # - # If you use a module, for instance Weblog::PostsController, you will need a template named - # <tt>app/views/layouts/weblog/posts.html.erb</tt>. - # - # Since all your controllers inherit from ApplicationController, they will use - # <tt>app/views/layouts/application.html.erb</tt> if no other layout is specified - # or provided. - # - # == Inheritance Examples - # - # class BankController < ActionController::Base - # layout "bank_standard" - # - # class InformationController < BankController - # - # class TellerController < BankController - # # teller.html.erb exists - # - # class TillController < TellerController - # - # class VaultController < BankController - # layout :access_level_layout - # - # class EmployeeController < BankController - # layout nil - # - # The InformationController uses "bank_standard" inherited from the BankController, the VaultController overwrites - # and picks the layout dynamically, and the EmployeeController doesn't want to use a layout at all. - # - # The TellerController uses +teller.html.erb+, and TillController inherits that layout and - # uses it as well. - # - # == Types of layouts - # - # Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes - # you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can - # be done either by specifying a method reference as a symbol or using an inline method (as a proc). - # - # The method reference is the preferred approach to variable layouts and is used like this: - # - # class WeblogController < ActionController::Base - # layout :writers_and_readers - # - # def index - # # fetching posts - # end - # - # private - # def writers_and_readers - # logged_in? ? "writer_layout" : "reader_layout" - # end - # - # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing - # is logged in or not. - # - # If you want to use an inline method, such as a proc, do something like this: - # - # class WeblogController < ActionController::Base - # layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" } - # - # Of course, the most common way of specifying a layout is still just as a plain template name: - # - # class WeblogController < ActionController::Base - # layout "weblog_standard" - # - # If no directory is specified for the template name, the template will by default be looked for in <tt>app/views/layouts/</tt>. - # Otherwise, it will be looked up relative to the template root. - # - # == Conditional layouts - # - # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering - # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The - # <tt>:only</tt> and <tt>:except</tt> options can be passed to the layout call. For example: - # - # class WeblogController < ActionController::Base - # layout "weblog_standard", :except => :rss - # - # # ... - # - # end - # - # This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout - # around the rendered view. - # - # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so - # #<tt>:except => [ :rss, :text_only ]</tt> is valid, as is <tt>:except => :rss</tt>. - # - # == Using a different layout in the action render call - # - # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above. - # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller. - # You can do this by passing a <tt>:layout</tt> option to the <tt>render</tt> call. For example: - # - # class WeblogController < ActionController::Base - # layout "weblog_standard" - # - # def help - # render :action => "help", :layout => "help" - # end - # end - # - # This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout. - module Layouts - extend ActiveSupport::Concern - - include ActionController::Rendering - include AbstractController::Layouts - - module ClassMethods - # If no layout is provided, look for a layout with this name. - def _implied_layout_name - controller_path - end - end - end -end diff --git a/actionpack/lib/action_controller/metal/logger.rb b/actionpack/lib/action_controller/metal/logger.rb index e71f77fbb2..4f4370e5f0 100644 --- a/actionpack/lib/action_controller/metal/logger.rb +++ b/actionpack/lib/action_controller/metal/logger.rb @@ -8,6 +8,10 @@ module ActionController module Logger extend ActiveSupport::Concern + included do + include AbstractController::Logger + end + attr_internal :view_runtime def process_action(action) diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index 20eb524e50..74e50bb032 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -20,12 +20,6 @@ module ActionController def render_to_body(options) _process_options(options) - - if options.key?(:partial) - options[:partial] = action_name if options[:partial] == true - options[:_details] = {:formats => formats} - end - super end @@ -43,6 +37,12 @@ module ActionController super end + def _render_partial(options) + options[:partial] = action_name if options[:partial] == true + options[:_details] = {:formats => formats} + super + end + def format_for_text formats.first end diff --git a/actionpack/lib/action_controller/rails.rb b/actionpack/lib/action_controller/railtie.rb index df708c315b..f861d12905 100644 --- a/actionpack/lib/action_controller/rails.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -1,5 +1,8 @@ +require "action_controller" +require "rails" + module ActionController - class Plugin < Rails::Plugin + class Railtie < Rails::Railtie plugin_name :action_controller initializer "action_controller.set_configs" do |app| 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/railtie.rb b/actionpack/lib/action_view/railtie.rb new file mode 100644 index 0000000000..a90e0636b9 --- /dev/null +++ b/actionpack/lib/action_view/railtie.rb @@ -0,0 +1,2 @@ +require "action_view" +require "rails"
\ No newline at end of file diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 0302e44b4e..48316cac53 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -22,15 +22,18 @@ module ActionView return _render_partial(options) end - layout = find(layout, {:formats => formats}) if layout + template = if options[:file] + find(options[:file], {:formats => formats}) + elsif options[:inline] + handler = Template.handler_class_for_extension(options[:type] || "erb") + Template.new(options[:inline], "inline template", handler, {}) + elsif options[:text] + Template::Text.new(options[:text]) + end - if file = options[:file] - template = find(file, {:formats => formats}) + if template + layout = find(layout, {:formats => formats}) if layout _render_template(template, layout, :locals => options[:locals]) - elsif inline = options[:inline] - _render_inline(inline, layout, options) - elsif text = options[:text] - _render_text(text, layout, options[:locals]) end when :update update_page(&block) @@ -76,42 +79,23 @@ module ActionView capture(&block) end - def _render_inline(inline, layout, options) - locals = options[:locals] - - content = ActiveSupport::Notifications.instrument(:render_inline) do - handler = Template.handler_class_for_extension(options[:type] || "erb") - template = Template.new(options[:inline], "inline template", handler, {}) - template.render(self, locals) - end - - _render_text(content, layout, locals) - end - - def _render_text(content, layout, locals) - ActiveSupport::Notifications.instrument(:render_text) - content = _render_layout(layout, locals){ content } if layout - content - end - # This is the API to render a ViewContext's template from a controller. # # Internal Options: # _template:: The Template object to render # _layout:: The layout, if any, to wrap the Template in - # _partial:: true if the template is a partial def render_template(options) _evaluate_assigns_and_ivars - template, layout, partial = options.values_at(:_template, :_layout, :_partial) - _render_template(template, layout, options, partial) + template, layout = options.values_at(:_template, :_layout) + _render_template(template, layout, options) end - def _render_template(template, layout = nil, options = {}, partial = nil) + def _render_template(template, layout = nil, options = {}) locals = options[:locals] || {} content = ActiveSupport::Notifications.instrument(:render_template, :identifier => template.identifier, :layout => (layout ? layout.identifier : nil)) do - partial ? _render_partial_object(template, options) : template.render(self, locals) + template.render(self, locals) end @_content_for[:layout] = content |