From a9751a7034c5a2a49fd90e9f79ad5fcae103487b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 17 Oct 2009 10:31:11 -0300 Subject: Refactor ActionMailer layout and remove legacy one. --- actionmailer/lib/action_mailer/base.rb | 42 ++-- actionmailer/lib/action_mailer/delivery_method.rb | 17 +- .../lib/action_mailer/delivery_method/file.rb | 2 +- .../lib/action_mailer/delivery_method/sendmail.rb | 2 +- .../lib/action_mailer/delivery_method/smtp.rb | 2 +- .../lib/action_mailer/delivery_method/test.rb | 2 +- actionpack/lib/abstract_controller/layouts.rb | 20 ++ actionpack/lib/action_controller/legacy/layout.rb | 256 --------------------- actionpack/lib/action_controller/metal/layouts.rb | 11 - 9 files changed, 51 insertions(+), 303 deletions(-) delete mode 100644 actionpack/lib/action_controller/legacy/layout.rb diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 898356075f..29afa2692a 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -1,6 +1,4 @@ -require "active_support/core_ext/class" -# Use the old layouts until actionmailer gets refactored -require "action_controller/legacy/layout" +require 'active_support/core_ext/class' module ActionMailer #:nodoc: # Action Mailer allows you to send email from your application using a mailer model and views. @@ -254,11 +252,12 @@ module ActionMailer #:nodoc: # +implicit_parts_order+. class Base include AdvAttrAccessor, PartContainer, Quoting, Utils - extend AbstractController::RenderingController + + include AbstractController::RenderingController + include AbstractController::Layouts if Object.const_defined?(:ActionController) include ActionController::UrlWriter - include ActionController::Layout end private_class_method :new #:nodoc: @@ -569,8 +568,7 @@ module ActionMailer #:nodoc: end @template = initialize_template_class(body) - layout = _pick_layout(layout, true) unless - ActionController::Base.exempt_from_layout.include?(template.handler) + layout = _layout_for_option(:default, :formats => formats) @template._render_template(template, layout, {}) ensure @current_template_content_type = nil @@ -583,25 +581,23 @@ module ActionMailer #:nodoc: end def render(opts) + file = opts[:file] opts[:locals] ||= {} - layout, file = opts.delete(:layout), opts[:file] - - begin - @template = initialize_template_class(opts.delete(:body)) - - if file - prefix = mailer_name unless file =~ /\// - template = view_paths.find(file, {:formats => formats}, prefix) - end - layout = _pick_layout(layout, - !template || ActionController::Base.exempt_from_layout.include?(template.handler)) + @template = initialize_template_class(opts.delete(:body)) - if template - @template._render_template(template, layout, opts) - elsif inline = opts[:inline] - @template._render_inline(inline, layout, opts) - end + if file + prefix = mailer_name unless file =~ /\// + template = view_paths.find(file, {:formats => formats}, prefix) + end + + layout = opts.key?(:layout) ? opts.delete(:layout) : :default + layout = _layout_for_option(layout, :formats => formats) + + if template + @template._render_template(template, layout, opts) + elsif inline = opts[:inline] + @template._render_inline(inline, layout, opts) end end diff --git a/actionmailer/lib/action_mailer/delivery_method.rb b/actionmailer/lib/action_mailer/delivery_method.rb index ffba3c418c..29a51afdc3 100644 --- a/actionmailer/lib/action_mailer/delivery_method.rb +++ b/actionmailer/lib/action_mailer/delivery_method.rb @@ -2,10 +2,10 @@ require "active_support/core_ext/class" module ActionMailer module DeliveryMethod - autoload :File, 'action_mailer/delivery_method/file' + autoload :File, 'action_mailer/delivery_method/file' autoload :Sendmail, 'action_mailer/delivery_method/sendmail' - autoload :Smtp, 'action_mailer/delivery_method/smtp' - autoload :Test, 'action_mailer/delivery_method/test' + autoload :Smtp, 'action_mailer/delivery_method/smtp' + autoload :Test, 'action_mailer/delivery_method/test' # Creates a new DeliveryMethod object according to the given options. # @@ -27,18 +27,17 @@ module ActionMailer def self.lookup_method(delivery_method) case delivery_method when Symbol - method_name = delivery_method.to_s.camelize + method_name = delivery_method.to_s.camelize method_class = ActionMailer::DeliveryMethod.const_get(method_name) - method_class.new() - when nil + method_class.new + when nil # default Smtp.new else delivery_method end end - # An abstract delivery method class. There are multiple delivery method - # classes, documented under + # An abstract delivery method class. There are multiple delivery method classes. # See the classes under the ActionMailer::DeliveryMethod, e.g. # ActionMailer::DeliveryMethod::Smtp. # Smtp is the default delivery method for production @@ -47,8 +46,8 @@ module ActionMailer # each delivery method exposes just one method # # delivery_method = ActionMailer::DeliveryMethod::Smtp.new - # # delivery_method.perform_delivery(mail) # send the mail via smtp + # class Method superclass_delegating_accessor :settings self.settings = {} diff --git a/actionmailer/lib/action_mailer/delivery_method/file.rb b/actionmailer/lib/action_mailer/delivery_method/file.rb index 8807a05221..587ae37ffa 100644 --- a/actionmailer/lib/action_mailer/delivery_method/file.rb +++ b/actionmailer/lib/action_mailer/delivery_method/file.rb @@ -1,10 +1,10 @@ require 'tmpdir' + module ActionMailer module DeliveryMethod # A delivery method implementation which writes all mails to a file. class File < Method - self.settings = { :location => defined?(Rails) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails" } diff --git a/actionmailer/lib/action_mailer/delivery_method/sendmail.rb b/actionmailer/lib/action_mailer/delivery_method/sendmail.rb index 34e03b8060..db55af79f1 100644 --- a/actionmailer/lib/action_mailer/delivery_method/sendmail.rb +++ b/actionmailer/lib/action_mailer/delivery_method/sendmail.rb @@ -3,7 +3,6 @@ module ActionMailer # A delivery method implementation which sends via sendmail. class Sendmail < Method - self.settings = { :location => '/usr/sbin/sendmail', :arguments => '-i -t' @@ -18,5 +17,6 @@ module ActionMailer end end end + end end diff --git a/actionmailer/lib/action_mailer/delivery_method/smtp.rb b/actionmailer/lib/action_mailer/delivery_method/smtp.rb index e39f97330c..86b0ae8329 100644 --- a/actionmailer/lib/action_mailer/delivery_method/smtp.rb +++ b/actionmailer/lib/action_mailer/delivery_method/smtp.rb @@ -1,6 +1,5 @@ module ActionMailer module DeliveryMethod - # A delivery method implementation which sends via smtp. class Smtp < Method @@ -27,5 +26,6 @@ module ActionMailer end end end + end end diff --git a/actionmailer/lib/action_mailer/delivery_method/test.rb b/actionmailer/lib/action_mailer/delivery_method/test.rb index e63e0abbb8..6e3239d52a 100644 --- a/actionmailer/lib/action_mailer/delivery_method/test.rb +++ b/actionmailer/lib/action_mailer/delivery_method/test.rb @@ -3,10 +3,10 @@ module ActionMailer # A delivery method implementation designed for testing, which just appends each record to the :deliveries array class Test < Method - def perform_delivery(mail) ActionMailer::Base.deliveries << mail end end + end end diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 796ef40584..4723e18a01 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -171,6 +171,26 @@ module AbstractController name && _find_layout(name, details) end + # Determine the layout for a given name and details, taking into account + # the name type. + # + # ==== Parameters + # name:: The name of the template + # details Object}>:: A list of details to restrict + # the lookup to. By default, layout lookup is limited to the + # formats specified for the current request. + def _layout_for_option(name, details) + case name + when String then _layout_for_name(name, details) + when true then _default_layout(details, true) + when :default then _default_layout(details, false) + when false, nil then nil + else + raise ArgumentError, + "String, true, or false, expected for `layout'; you passed #{name.inspect}" + end + end + # Take in the name and details and find a Template. # # ==== Parameters diff --git a/actionpack/lib/action_controller/legacy/layout.rb b/actionpack/lib/action_controller/legacy/layout.rb deleted file mode 100644 index 4e3b67de20..0000000000 --- a/actionpack/lib/action_controller/legacy/layout.rb +++ /dev/null @@ -1,256 +0,0 @@ -require 'active_support/core_ext/enumerable' -require 'active_support/core_ext/class' -require 'active_support/core_ext/class/delegating_attributes' -require 'active_support/core_ext/class/inheritable_attributes' - -module ActionController #:nodoc: - # MegasuperultraHAX - # plz refactor ActionMailer - class Base - @@exempt_from_layout = [ActionView::TemplateHandlers::RJS] - cattr_accessor :exempt_from_layout - end - - module Layout #:nodoc: - def self.included(base) - base.extend(ClassMethods) - base.class_inheritable_accessor :layout_name, :layout_conditions - end - - # 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: - # - #

<%= @page_title %>

- # <%= 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: - # - #

Welcome

- # Off-world colonies offers you a chance to start a new life - # - # == Automatic layout assignment - # - # If there is a template in app/views/layouts/ with the same name as the current controller then it will be automatically - # set as that controller's layout unless explicitly told otherwise. Say you have a WeblogController, for example. If a template named - # app/views/layouts/weblog.erb or app/views/layouts/weblog.builder exists then it will be automatically set as - # the layout for your WeblogController. You can create a layout with the name application.erb or application.builder - # and this will be set as the default controller if there is no layout with the same name as the current controller and there is - # no layout explicitly assigned with the +layout+ method. Nested controllers use the same folder structure for automatic layout. - # assignment. So an Admin::WeblogController will look for a template named app/views/layouts/admin/weblog.erb. - # Setting a layout explicitly will always override the automatic behaviour for the controller where the layout is set. - # Explicitly setting the layout in a parent class, though, will not override the child class's layout assignment if the child - # class has a layout with the same name. - # - # == Inheritance for layouts - # - # Layouts are shared downwards in the inheritance hierarchy, but not upwards. Examples: - # - # class BankController < ActionController::Base - # layout "bank_standard" - # - # class InformationController < BankController - # - # 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. - # - # == 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 app/views/layouts/. - # 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 - # :only and :except 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 :only and :except condition can accept an arbitrary number of method references, so - # #:except => [ :rss, :text_only ] is valid, as is :except => :rss. - # - # == 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 :layout option to the render 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 ClassMethods - extend ActiveSupport::Memoizable - - # If a layout is specified, all rendered actions will have their result rendered - # when the layout yields. This layout can itself depend on instance variables assigned during action - # performance and have access to them as any normal template would. - def layout(template_name, conditions = {}, auto = false) - add_layout_conditions(conditions) - self.layout_name = template_name - end - - def memoized_default_layout(formats) #:nodoc: - self.layout_name || begin - layout = default_layout_name - layout.is_a?(String) ? find_layout(layout, formats) : layout - rescue ActionView::MissingTemplate - end - end - - def default_layout(*args) - memoized_default_layout(*args) - @_memoized_default_layout ||= {} - @_memoized_default_layout[args] ||= memoized_default_layout(*args) - end - - def memoized_find_layout(layout, formats) #:nodoc: - return layout if layout.nil? || layout.respond_to?(:render) - prefix = layout.to_s =~ /layouts\// ? nil : "layouts" - find_template(layout.to_s, {:formats => formats}, :_prefix => prefix) - end - - def find_layout(*args) - @_memoized_find_layout ||= {} - @_memoized_find_layout[args] ||= memoized_find_layout(*args) - end - - def layout_list #:nodoc: - Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] } - end - memoize :layout_list - - def default_layout_name - layout_match = name.underscore.sub(/_controller$/, '') - if layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty? - superclass.default_layout_name if superclass.respond_to?(:default_layout_name) - else - layout_match - end - end - memoize :default_layout_name - - private - def add_layout_conditions(conditions) - # :except => :foo == :except => [:foo] == :except => "foo" == :except => ["foo"] - conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} } - write_inheritable_hash(:layout_conditions, conditions) - end - end - - def active_layout(name) - name = self.class.default_layout(formats) if name == true - - layout_name = case name - when Symbol then __send__(name) - when Proc then name.call(self) - else name - end - - self.class.find_layout(layout_name, formats) - end - - def _pick_layout(layout_name = nil, implicit = false) - return unless layout_name || implicit - layout_name = true if layout_name.nil? - active_layout(layout_name) if action_has_layout? && layout_name - end - - private - def action_has_layout? - if conditions = self.class.layout_conditions - if only = conditions[:only] - return only.include?(action_name) - elsif except = conditions[:except] - return !except.include?(action_name) - end - end - true - end - - end -end diff --git a/actionpack/lib/action_controller/metal/layouts.rb b/actionpack/lib/action_controller/metal/layouts.rb index cac529b1ae..e7859e3fec 100644 --- a/actionpack/lib/action_controller/metal/layouts.rb +++ b/actionpack/lib/action_controller/metal/layouts.rb @@ -177,16 +177,5 @@ module ActionController options[:_layout] = _layout_for_option(layout, options[:_template].details) end - def _layout_for_option(name, details) - case name - when String then _layout_for_name(name, details) - when true then _default_layout(details, true) - when :default then _default_layout(details, false) - when false, nil then nil - else - raise ArgumentError, - "String, true, or false, expected for `layout'; you passed #{name.inspect}" - end - end end end -- cgit v1.2.3