Skip to content

Commit

Permalink
Merge branch 'master' into sprockets
Browse files Browse the repository at this point in the history
  • Loading branch information
josh committed Apr 13, 2011
2 parents d7b521d + f0e198b commit ed24595
Show file tree
Hide file tree
Showing 184 changed files with 2,597 additions and 1,013 deletions.
2 changes: 1 addition & 1 deletion README.rdoc
Expand Up @@ -48,7 +48,7 @@ more separate. Each of these packages can be used independently outside of

"Welcome aboard: You're riding Ruby on Rails!"

5. Follow the guidelines to start developing your application. You can find the following resources handy:
5. Follow the guidelines to start developing your application. You may find the following resources handy:

* The README file created within your application.
* The {Getting Started with Rails}[http://guides.rubyonrails.org/getting_started.html].
Expand Down
15 changes: 14 additions & 1 deletion actionmailer/README.rdoc
Expand Up @@ -32,7 +32,7 @@ This can be as simple as:
end

The body of the email is created by using an Action View template (regular
ERb) that has the instance variables that are declared in the mailer action.
ERB) that has the instance variables that are declared in the mailer action.

So the corresponding body template for the method above could look like this:

Expand Down Expand Up @@ -72,6 +72,19 @@ Or you can just chain the methods together like:

Notifier.welcome.deliver # Creates the email and sends it immediately

== Setting defaults

It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from ActionMailer::Base. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you wont need to worry about that. Finally it is also possible to pass in a Proc that will get evaluated when it is needed.

Note that every value you set with this method will get over written if you use the same key in your mailer method.

Example:

class Authenticationmailer < ActionMailer::Base
default :from => "awesome@application.com", :subject => Proc.new { "E-mail was generated at #{Time.now}" }
.....
end

== Receiving emails

To receive emails, you need to implement a public instance method called <tt>receive</tt> that takes an
Expand Down
2 changes: 0 additions & 2 deletions actionmailer/actionmailer.gemspec
Expand Up @@ -17,8 +17,6 @@ Gem::Specification.new do |s|
s.require_path = 'lib'
s.requirements << 'none'

s.has_rdoc = true

s.add_dependency('actionpack', version)
s.add_dependency('mail', '~> 2.2.15')
end
30 changes: 27 additions & 3 deletions actionmailer/lib/action_mailer/base.rb
Expand Up @@ -4,6 +4,7 @@
require 'active_support/core_ext/array/wrap'
require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/proc'
require 'active_support/core_ext/string/inflections'
require 'action_mailer/log_subscriber'

module ActionMailer #:nodoc:
Expand Down Expand Up @@ -349,9 +350,6 @@ class Base < AbstractController::Base
helper ActionMailer::MailHelper
include ActionMailer::OldApi

delegate :register_observer, :to => Mail
delegate :register_interceptor, :to => Mail

private_class_method :new #:nodoc:

class_attribute :default_params
Expand All @@ -363,6 +361,32 @@ class Base < AbstractController::Base
}.freeze

class << self
# Register one or more Observers which will be notified when mail is delivered.
def register_observers(*observers)
observers.flatten.compact.each { |observer| register_observer(observer) }
end

# Register one or more Interceptors which will be called before mail is sent.
def register_interceptors(*interceptors)
interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
end

# Register an Observer which will be notified when mail is delivered.
# Either a class or a string can be passed in as the Observer. If a string is passed in
# it will be <tt>constantize</tt>d.
def register_observer(observer)
delivery_observer = (observer.is_a?(String) ? observer.constantize : observer)
Mail.register_observer(delivery_observer)
end

# Register an Inteceptor which will be called before mail is sent.
# Either a class or a string can be passed in as the Observer. If a string is passed in
# it will be <tt>constantize</tt>d.
def register_interceptor(interceptor)
delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor)
Mail.register_interceptor(delivery_interceptor)
end

def mailer_name
@mailer_name ||= name.underscore
end
Expand Down
8 changes: 6 additions & 2 deletions actionmailer/lib/action_mailer/railtie.rb
Expand Up @@ -19,13 +19,17 @@ class Railtie < Rails::Railtie
options.stylesheets_dir ||= paths["public/stylesheets"].first

# make sure readers methods get compiled
options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host
options.asset_path ||= app.config.asset_path
options.asset_host ||= app.config.asset_host

ActiveSupport.on_load(:action_mailer) do
include AbstractController::UrlFor
extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
include app.routes.mounted_helpers

register_interceptors(options.delete(:interceptors))
register_observers(options.delete(:observers))

options.each { |k,v| send("#{k}=", v) }
end
end
Expand Down
40 changes: 40 additions & 0 deletions actionmailer/test/base_test.rb
Expand Up @@ -478,25 +478,65 @@ def self.delivered_email(mail)
end
end

class MySecondObserver
def self.delivered_email(mail)
end
end

test "you can register an observer to the mail object that gets informed on email delivery" do
ActionMailer::Base.register_observer(MyObserver)
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
mail.deliver
end

test "you can register an observer using its stringified name to the mail object that gets informed on email delivery" do
ActionMailer::Base.register_observer("BaseTest::MyObserver")
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
mail.deliver
end

test "you can register multiple observers to the mail object that both get informed on email delivery" do
ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver)
mail = BaseMailer.welcome
MyObserver.expects(:delivered_email).with(mail)
MySecondObserver.expects(:delivered_email).with(mail)
mail.deliver
end

class MyInterceptor
def self.delivering_email(mail)
end
end

class MySecondInterceptor
def self.delivering_email(mail)
end
end

test "you can register an interceptor to the mail object that gets passed the mail object before delivery" do
ActionMailer::Base.register_interceptor(MyInterceptor)
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end

test "you can register an interceptor using its stringified name to the mail object that gets passed the mail object before delivery" do
ActionMailer::Base.register_interceptor("BaseTest::MyInterceptor")
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end

test "you can register multiple interceptors to the mail object that both get passed the mail object before delivery" do
ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor)
mail = BaseMailer.welcome
MyInterceptor.expects(:delivering_email).with(mail)
MySecondInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end

test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do
mail1 = ProcMailer.welcome
yesterday = 1.day.ago
Expand Down
2 changes: 2 additions & 0 deletions actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.1.0 (unreleased)*

* Implicit actions named not_implemented can be rendered [Santiago Pastorino]

* Wildcard route will always matching the optional format segment by default. For example if you have this route:

map '*pages' => 'pages#show'
Expand Down
4 changes: 2 additions & 2 deletions actionpack/README.rdoc
Expand Up @@ -19,7 +19,7 @@ It consists of several modules:

* Action View, which handles view template lookup and rendering, and provides
view helpers that assist when building HTML forms, Atom feeds and more.
Template formats that Action View handles are ERb (embedded Ruby, typically
Template formats that Action View handles are ERB (embedded Ruby, typically
used to inline short Ruby snippets inside HTML), XML Builder and RJS
(dynamically generated JavaScript from Ruby code).

Expand Down Expand Up @@ -57,7 +57,7 @@ A short rundown of some of the major features:
{Learn more}[link:classes/ActionController/Base.html]


* ERb templates (static content mixed with dynamic output from ruby)
* ERB templates (static content mixed with dynamic output from ruby)

<% for post in @posts %>
Title: <%= post.title %>
Expand Down
4 changes: 1 addition & 3 deletions actionpack/actionpack.gemspec
Expand Up @@ -17,8 +17,6 @@ Gem::Specification.new do |s|
s.require_path = 'lib'
s.requirements << 'none'

s.has_rdoc = true

s.add_dependency('activesupport', version)
s.add_dependency('activemodel', version)
s.add_dependency('rack-cache', '~> 1.0.0')
Expand All @@ -28,5 +26,5 @@ Gem::Specification.new do |s|
s.add_dependency('rack-test', '~> 0.5.7')
s.add_dependency('rack-mount', '~> 0.7.1')
s.add_dependency('tzinfo', '~> 0.3.23')
s.add_dependency('erubis', '~> 2.6.6')
s.add_dependency('erubis', '~> 2.7.0')
end
2 changes: 2 additions & 0 deletions actionpack/lib/abstract_controller/base.rb
@@ -1,3 +1,4 @@
require 'erubis'
require 'active_support/configurable'
require 'active_support/descendants_tracker'
require 'active_support/core_ext/module/anonymous'
Expand All @@ -18,6 +19,7 @@ class Base
include ActiveSupport::Configurable
extend ActiveSupport::DescendantsTracker

undef_method :not_implemented
class << self
attr_reader :abstract
alias_method :abstract?, :abstract
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/abstract_controller/callbacks.rb
Expand Up @@ -29,7 +29,7 @@ module ClassMethods
#
# ==== Options
# * <tt>only</tt> - The callback should be run only for this action
# * <tt>except<tt> - The callback should be run for all actions except this action
# * <tt>except</tt> - The callback should be run for all actions except this action
def _normalize_callback_options(options)
if only = options[:only]
only = Array(only).map {|o| "action_name == '#{o}'"}.join(" || ")
Expand Down
4 changes: 2 additions & 2 deletions actionpack/lib/action_controller/base.rb
Expand Up @@ -105,7 +105,7 @@ module ActionController
# == Renders
#
# Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering
# of a template. Included in the Action Pack is the Action View, which enables rendering of ERb templates. It's automatically configured.
# of a template. Included in the Action Pack is the Action View, which enables rendering of ERB templates. It's automatically configured.
# The controller passes objects to the view by assigning instance variables:
#
# def show
Expand All @@ -128,7 +128,7 @@ module ActionController
# end
# end
#
# Read more about writing ERb and Builder templates in ActionView::Base.
# Read more about writing ERB and Builder templates in ActionView::Base.
#
# == Redirects
#
Expand Down
6 changes: 5 additions & 1 deletion actionpack/lib/action_controller/metal.rb
Expand Up @@ -201,19 +201,23 @@ def to_a #:nodoc:
class_attribute :middleware_stack
self.middleware_stack = ActionController::MiddlewareStack.new

def self.inherited(base)
def self.inherited(base) #nodoc:
base.middleware_stack = self.middleware_stack.dup
super
end

# Adds given middleware class and its args to bottom of middleware_stack
def self.use(*args, &block)
middleware_stack.use(*args, &block)
end

# Alias for middleware_stack
def self.middleware
middleware_stack
end

# Makes the controller a rack endpoint that points to the action in
# the given env's action_dispatch.request.path_parameters key.
def self.call(env)
action(env['action_dispatch.request.path_parameters'][:action]).call(env)
end
Expand Down
Expand Up @@ -67,7 +67,7 @@ module HttpAuthentication
# class PostsController < ApplicationController
# REALM = "SuperSecret"
# USERS = {"dhh" => "secret", #plain text password
# "dap" => Digest:MD5::hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
# "dap" => Digest::MD5.hexdigest(["dap",REALM,"secret"].join(":")) #ha1 digest password
#
# before_filter :authenticate, :except => [:index]
#
Expand Down
4 changes: 2 additions & 2 deletions actionpack/lib/action_controller/metal/implicit_render.rb
Expand Up @@ -10,8 +10,8 @@ def send_action(method, *args)
end
end

def default_render
render
def default_render(*args)
render(*args)
end

def action_method?(action_name)
Expand Down
16 changes: 10 additions & 6 deletions actionpack/lib/action_controller/metal/mime_responds.rb
@@ -1,8 +1,9 @@
require 'abstract_controller/collector'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/object/inclusion'

module ActionController #:nodoc:
module MimeResponds #:nodoc:
module MimeResponds
extend ActiveSupport::Concern

included do
Expand Down Expand Up @@ -189,7 +190,7 @@ def respond_to(*mimes, &block)
raise ArgumentError, "respond_to takes either types or a block, never both" if mimes.any? && block_given?

if response = retrieve_response_from_mimes(mimes, &block)
response.call
response.call(nil)
end
end

Expand Down Expand Up @@ -222,6 +223,9 @@ def respond_to(*mimes, &block)
# is quite simple (it just needs to respond to call), you can even give
# a proc to it.
#
# In order to use respond_with, first you need to declare the formats your
# controller responds to in the class level with a call to <tt>respond_to</tt>.
#
def respond_with(*resources, &block)
raise "In order to use respond_with, first you need to declare the formats your " <<
"controller responds to in the class level" if self.class.mimes_for_respond_to.empty?
Expand All @@ -245,9 +249,9 @@ def collect_mimes_from_class_level #:nodoc:
config = self.class.mimes_for_respond_to[mime]

if config[:except]
!config[:except].include?(action)
!action.in?(config[:except])
elsif config[:only]
config[:only].include?(action)
action.in?(config[:only])
else
true
end
Expand All @@ -257,9 +261,9 @@ def collect_mimes_from_class_level #:nodoc:
# Collects mimes and return the response for the negotiated format. Returns
# nil if :not_acceptable was sent to the client.
#
def retrieve_response_from_mimes(mimes=nil, &block)
def retrieve_response_from_mimes(mimes=nil, &block) #:nodoc:
mimes ||= collect_mimes_from_class_level
collector = Collector.new(mimes) { default_render }
collector = Collector.new(mimes) { |options| default_render(options || {}) }
block.call(collector) if block_given?

if format = request.negotiate_mime(collector.order)
Expand Down

0 comments on commit ed24595

Please sign in to comment.