Skip to content

Commit

Permalink
Merge branch 'master' into adequaterecord
Browse files Browse the repository at this point in the history
* master: (311 commits)
  Add a missing changelog entry for #13981 and #14035
  Revert "Fixed plugin_generator test"
  implements new option :month_format_string for date select helpers [Closes #13618]
  add factory methods for empty alias trackers
  guarantee a list in the alias tracker so we can remove a conditional
  stop exposing table_joins
  make most parameters to the AliasTracker required
  make a singleton for AssociationScope
  pass the association and connection to the scope method
  pass the tracker down the stack and construct it in the scope method
  clean up add_constraints signature
  remove the reflection delegate
  remove klass delegator
  remove railties changes. fixes #14054
  remove chain delegate
  remove scope_chain delegate
  Add verb to sanitization note
  fix path shown in mailer's templates
  updated Travis build status image url
  fix guide active_support_core_extensions. add Note to String#indent [ci skip]
  ...

Conflicts:
	activerecord/lib/active_record/associations/join_dependency.rb
	activerecord/test/cases/associations/association_scope_test.rb
  • Loading branch information
tenderlove committed Feb 17, 2014
2 parents 5ac2879 + 3e3ed1e commit fe42eff
Show file tree
Hide file tree
Showing 300 changed files with 4,974 additions and 1,660 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Expand Up @@ -6,7 +6,7 @@ rvm:
- 1.9.3
- 2.0.0
- 2.1.0
- rbx
- rbx-2
- jruby
env:
- "GEM=railties"
Expand All @@ -17,7 +17,7 @@ env:
- "GEM=ar:postgresql"
matrix:
allow_failures:
- rvm: rbx
- rvm: rbx-2
- rvm: jruby
fast_finish: true
notifications:
Expand Down
7 changes: 1 addition & 6 deletions Gemfile
Expand Up @@ -9,7 +9,7 @@ gem 'mocha', '~> 0.14', require: false

gem 'rack-cache', '~> 1.2'
gem 'bcrypt-ruby', '~> 3.1.2'
gem 'jquery-rails', '~> 2.2.0'
gem 'jquery-rails', '~> 3.1.0'
gem 'turbolinks'
gem 'coffee-rails', '~> 4.0.0'
gem 'arel', github: 'rails/arel'
Expand Down Expand Up @@ -77,11 +77,6 @@ platforms :jruby do
end
end

platforms :rbx do
gem 'psych', '~> 2.0'
gem 'rubysl', '~> 2.0'
end

# gems that are necessary for ActiveRecord tests with Oracle database
if ENV['ORACLE_ENHANCED']
platforms :ruby do
Expand Down
3 changes: 1 addition & 2 deletions README.md
Expand Up @@ -76,8 +76,7 @@ We encourage you to contribute to Ruby on Rails! Please check out the

## Code Status

* [![Build Status](https://api.travis-ci.org/rails/rails.png)](https://travis-ci.org/rails/rails)
* [![Dependencies](https://gemnasium.com/rails/rails.png?travis)](https://gemnasium.com/rails/rails)
* [![Build Status](https://travis-ci.org/rails/rails.png?branch=master)](https://travis-ci.org/rails/rails)

## License

Expand Down
24 changes: 23 additions & 1 deletion actionmailer/CHANGELOG.md
@@ -1,4 +1,26 @@
* Add mailer previews feature based on 37 Signals mail_view gem
* Support the use of underscored symbols when registering interceptors and
observers like we do elsewhere within Rails.

*Andrew White*

* Add the ability to intercept emails before previewing in a similar fashion
to how emails can be intercepted before delivery.

Fixes #13622.

Example:

class CSSInlineStyler
def self.previewing_email(message)
# inline CSS styles
end
end

ActionMailer::Base.register_preview_interceptor CSSInlineStyler

*Andrew White*

* Add mailer previews feature based on 37 Signals mail_view gem.

*Andrew White*

Expand Down
2 changes: 1 addition & 1 deletion actionmailer/README.rdoc
Expand Up @@ -74,7 +74,7 @@ Or you can just chain the methods together like:

== 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 <tt>ActionMailer::Base</tt>. 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 won't need to worry about that. Finally, it is also possible to pass in a Proc that will get evaluated when it is needed.
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 <tt>ActionMailer::Base</tt>. This method accepts a Hash as the parameter. You can use any of the headers email messages have, 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 won't 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 overwritten if you use the same key in your mailer method.

Expand Down
43 changes: 35 additions & 8 deletions actionmailer/lib/action_mailer/base.rb
Expand Up @@ -51,7 +51,7 @@ module ActionMailer
# * <tt>mail</tt> - Allows you to specify email to be sent.
#
# The hash passed to the mail method allows you to specify any header that a <tt>Mail::Message</tt>
# will accept (any valid Email header including optional fields).
# will accept (any valid email header including optional fields).
#
# The mail method, if not passed a block, will inspect your views and send all the views with
# the same name as the method, so the above action would send the +welcome.text.erb+ view
Expand Down Expand Up @@ -330,6 +330,21 @@ module ActionMailer
# An overview of all previews is accessible at <tt>http://localhost:3000/rails/mailers</tt>
# on a running development server instance.
#
# Previews can also be intercepted in a similar manner as deliveries can be by registering
# a preview interceptor that has a <tt>previewing_email</tt> method:
#
# class CssInlineStyler
# def self.previewing_email(message)
# # inline CSS styles
# end
# end
#
# config.action_mailer.register_preview_interceptor :css_inline_styler
#
# Note that interceptors need to be registered both with <tt>register_interceptor</tt>
# and <tt>register_preview_interceptor</tt> if they should operate on both sending and
# previewing emails.
#
# = Configuration options
#
# These options are specified on the class level, like
Expand Down Expand Up @@ -429,18 +444,30 @@ def register_interceptors(*interceptors)
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.
# Either a class, string or symbol can be passed in as the Observer.
# If a string or symbol is passed in it will be camelized and constantized.
def register_observer(observer)
delivery_observer = (observer.is_a?(String) ? observer.constantize : observer)
delivery_observer = case observer
when String, Symbol
observer.to_s.camelize.constantize
else
observer
end

Mail.register_observer(delivery_observer)
end

# Register an Interceptor which will be called before mail is sent.
# Either a class or a string can be passed in as the Interceptor. If a string is passed in
# it will be <tt>constantize</tt>d.
# Either a class, string or symbol can be passed in as the Interceptor.
# If a string or symbol is passed in it will be camelized and constantized.
def register_interceptor(interceptor)
delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor)
delivery_interceptor = case interceptor
when String, Symbol
interceptor.to_s.camelize.constantize
else
interceptor
end

Mail.register_interceptor(delivery_interceptor)
end

Expand Down Expand Up @@ -737,7 +764,7 @@ def mail(headers = {}, &block)
m.charset = charset = headers[:charset]

# Set configure delivery behavior
wrap_delivery_behavior!(headers.delete(:delivery_method),headers.delete(:delivery_method_options))
wrap_delivery_behavior!(headers.delete(:delivery_method), headers.delete(:delivery_method_options))

# Assign all headers except parts_order, content_type and body
assignable = headers.except(:parts_order, :content_type, :body, :template_name, :template_path)
Expand Down
43 changes: 37 additions & 6 deletions actionmailer/lib/action_mailer/preview.rb
Expand Up @@ -9,7 +9,32 @@ module Previews #:nodoc:
#
# config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
#
class_attribute :preview_path, instance_writer: false
mattr_accessor :preview_path, instance_writer: false

# :nodoc:
mattr_accessor :preview_interceptors, instance_writer: false
self.preview_interceptors = []

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

# Register am Interceptor which will be called before mail is previewed.
# Either a class or a string can be passed in as the Interceptor. If a
# string is passed in it will be <tt>constantize</tt>d.
def register_preview_interceptor(interceptor)
preview_interceptor = case interceptor
when String, Symbol
interceptor.to_s.camelize.constantize
else
interceptor
end

unless preview_interceptors.include?(preview_interceptor)
preview_interceptors << preview_interceptor
end
end
end
end

Expand All @@ -23,10 +48,14 @@ def all
descendants
end

# Returns the mail object for the given email name
# Returns the mail object for the given email name. The registered preview
# interceptors will be informed so that they can transform the message
# as they would if the mail was actually being delivered.
def call(email)
preview = self.new
preview.public_send(email)
message = preview.public_send(email)
inform_preview_interceptors(message)
message
end

# Returns all of the available email previews
Expand Down Expand Up @@ -56,7 +85,7 @@ def preview_name

protected
def load_previews #:nodoc:
if preview_path?
if preview_path
Dir["#{preview_path}/**/*_preview.rb"].each{ |file| require_dependency file }
end
end
Expand All @@ -65,8 +94,10 @@ def preview_path #:nodoc:
Base.preview_path
end

def preview_path? #:nodoc:
Base.preview_path?
def inform_preview_interceptors(message) #:nodoc:
Base.preview_interceptors.each do |interceptor|
interceptor.previewing_email(message)
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion actionmailer/lib/action_mailer/railtie.rb
Expand Up @@ -46,7 +46,7 @@ class Railtie < Rails::Railtie # :nodoc:
end

config.after_initialize do
if ActionMailer::Base.preview_path?
if ActionMailer::Base.preview_path
ActiveSupport::Dependencies.autoload_paths << ActionMailer::Base.preview_path
end
end
Expand Down
59 changes: 56 additions & 3 deletions actionmailer/test/base_test.rb
Expand Up @@ -530,6 +530,13 @@ def self.delivered_email(mail)
mail.deliver
end

test "you can register an observer using its symbolized underscored name to the mail object that gets informed on email delivery" do
ActionMailer::Base.register_observer(:"base_test/my_observer")
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
Expand All @@ -539,12 +546,18 @@ def self.delivered_email(mail)
end

class MyInterceptor
def self.delivering_email(mail)
end
def self.delivering_email(mail); end
def self.previewing_email(mail); end
end

class MySecondInterceptor
def self.delivering_email(mail)
def self.delivering_email(mail); end
def self.previewing_email(mail); end
end

class BaseMailerPreview < ActionMailer::Preview
def welcome
BaseMailer.welcome
end
end

Expand All @@ -562,6 +575,13 @@ def self.delivering_email(mail)
mail.deliver
end

test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before delivery" do
ActionMailer::Base.register_interceptor(:"base_test/my_interceptor")
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
Expand All @@ -570,6 +590,39 @@ def self.delivering_email(mail)
mail.deliver
end

test "you can register a preview interceptor to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor(MyInterceptor)
mail = BaseMailer.welcome
BaseMailerPreview.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
end

test "you can register a preview interceptor using its stringified name to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor("BaseTest::MyInterceptor")
mail = BaseMailer.welcome
BaseMailerPreview.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
end

test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptor(:"base_test/my_interceptor")
mail = BaseMailer.welcome
BaseMailerPreview.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
end

test "you can register multiple preview interceptors to the mail object that both get passed the mail object before previewing" do
ActionMailer::Base.register_preview_interceptors("BaseTest::MyInterceptor", MySecondInterceptor)
mail = BaseMailer.welcome
BaseMailerPreview.stubs(:welcome).returns(mail)
MyInterceptor.expects(:previewing_email).with(mail)
MySecondInterceptor.expects(:previewing_email).with(mail)
BaseMailerPreview.call(:welcome)
end

test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do
mail1 = ProcMailer.welcome['X-Proc-Method']
yesterday = 1.day.ago
Expand Down
29 changes: 20 additions & 9 deletions actionmailer/test/delivery_methods_test.rb
Expand Up @@ -38,8 +38,10 @@ class DefaultsDeliveryMethodsTest < ActiveSupport::TestCase
end

test "default sendmail settings" do
settings = {location: '/usr/sbin/sendmail',
arguments: '-i -t'}
settings = {
location: '/usr/sbin/sendmail',
arguments: '-i -t'
}
assert_equal settings, ActionMailer::Base.sendmail_settings
end
end
Expand Down Expand Up @@ -138,13 +140,15 @@ def teardown
end

test "default delivery options can be overridden per mail instance" do
settings = { address: "localhost",
port: 25,
domain: 'localhost.localdomain',
user_name: nil,
password: nil,
authentication: nil,
enable_starttls_auto: true }
settings = {
address: "localhost",
port: 25,
domain: 'localhost.localdomain',
user_name: nil,
password: nil,
authentication: nil,
enable_starttls_auto: true
}
assert_equal settings, ActionMailer::Base.smtp_settings
overridden_options = {user_name: "overridden", password: "somethingobtuse"}
mail_instance = DeliveryMailer.welcome(delivery_method_options: overridden_options)
Expand All @@ -164,6 +168,13 @@ def teardown
end
end

test "undefined delivery methods raises errors" do
DeliveryMailer.delivery_method = nil
assert_raise RuntimeError do
DeliveryMailer.welcome.deliver
end
end

test "does not perform deliveries if requested" do
DeliveryMailer.perform_deliveries = false
DeliveryMailer.deliveries.clear
Expand Down

0 comments on commit fe42eff

Please sign in to comment.