Skip to content

Commit bc5a168

Browse files
committed
Merge pull request #1389 from rspec/backport-1388
Back port pull request #1388 from rspec/fix-regression-mailer-preview-path
2 parents a046a70 + 538fb62 commit bc5a168

File tree

5 files changed

+104
-17
lines changed

5 files changed

+104
-17
lines changed

Changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
### Development
2+
3+
Bug Fixes:
4+
5+
* Fix regression with the railtie resulting in undefined method `preview_path=`
6+
on Rails 3.x and 4.0 (Aaron Kromer, #1388)
7+
18
### 3.2.2 / 2015-06-03
29
[Full Changelog](http://github.com/rspec/rspec-rails/compare/v3.2.1...v3.2.2)
310

example_app_generator/generate_action_mailer_specs.rb

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,25 @@ def comment_lines(path, flag, *args)
1414

1515
initializer 'action_mailer.rb', <<-CODE
1616
if ENV['DEFAULT_URL']
17-
Rails.application.configure do
18-
config.action_mailer.default_url_options = { :host => ENV['DEFAULT_URL'] }
17+
if ::Rails::VERSION::STRING < '4.1'
18+
ExampleApp::Application.configure do
19+
config.action_mailer.default_url_options = { :host => ENV['DEFAULT_URL'] }
20+
end
21+
else
22+
Rails.application.configure do
23+
config.action_mailer.default_url_options = { :host => ENV['DEFAULT_URL'] }
24+
end
1925
end
2026
end
27+
28+
if defined?(ActionMailer)
29+
# This will force the loading of ActionMailer settings
30+
ActionMailer::Base.smtp_settings
31+
end
2132
CODE
33+
gsub_file 'config/initializers/action_mailer.rb',
34+
/ExampleApp/,
35+
Rails.application.class.parent.to_s
2236

2337
copy_file 'spec/support/default_preview_path'
2438
chmod 'spec/support/default_preview_path', 0755

example_app_generator/spec/support/default_preview_path

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ require_file_stub 'config/environment' do
3232
module ExampleApp
3333
class Application < Rails::Application
3434
config.eager_load = false
35+
config.eager_load_paths.clear
3536

3637
# Don't care if the mailer can't send.
3738
config.action_mailer.raise_delivery_errors = false unless ENV['NO_ACTION_MAILER']
@@ -58,3 +59,7 @@ if ENV['DEFAULT_URL']
5859
elsif defined?(::ActionMailer::Preview)
5960
puts Rails.application.config.action_mailer.preview_path
6061
end
62+
63+
# This will force the loading of ActionMailer settings to ensure we do not
64+
# accicentally set something we should not
65+
ActionMailer::Base.smtp_settings

example_app_generator/spec/verify_mailer_preview_path_spec.rb

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,25 @@ def ==(str)
88
end
99
end
1010

11+
def as_commandline(ops)
12+
cmd, ops = ops.reverse
13+
ops ||= {}
14+
cmd_parts = ops.map { |k, v| "#{k}=#{v}" } << cmd << '2>&1'
15+
cmd_parts.join(' ')
16+
end
17+
1118
def capture_exec(*ops)
1219
io = if RUBY_VERSION.to_f < 1.9
13-
IO.popen(ops.join(' '))
20+
IO.popen(as_commandline(ops))
1421
else
1522
ops << { :err => [:child, :out] }
1623
IO.popen(ops)
1724
end
1825
# Necessary to ignore warnings from Rails code base
19-
out = io.readlines.reject { |line|
20-
line =~ /warning: circular argument reference/
21-
}.join.chomp
26+
out = io.readlines.
27+
reject { |line| line =~ /warning: circular argument reference/ }.
28+
join.
29+
chomp
2230
CaptureExec.new(out, $?.exitstatus)
2331
end
2432

@@ -176,8 +184,58 @@ def have_no_preview
176184
end
177185
end
178186
else
179-
it 'handles no action mailer preview' do
180-
expect(capture_exec(exec_script)).to have_no_preview
187+
context 'in the development environment' do
188+
let(:custom_env) { { 'RAILS_ENV' => rails_env } }
189+
let(:rails_env) { 'development' }
190+
191+
it 'handles no action mailer preview' do
192+
expect(capture_exec(custom_env, exec_script)).to have_no_preview
193+
end
194+
195+
it 'allows initializers to set options' do
196+
expect(
197+
capture_exec(
198+
custom_env.merge('DEFAULT_URL' => 'test-host'),
199+
exec_script
200+
)
201+
).to eq('test-host')
202+
end
203+
204+
it 'handles action mailer not being available' do
205+
expect(
206+
capture_exec(
207+
custom_env.merge('NO_ACTION_MAILER' => 'true'),
208+
exec_script
209+
)
210+
).to have_no_preview
211+
end
212+
end
213+
214+
context 'in a non-development environment' do
215+
let(:custom_env) { { 'RAILS_ENV' => rails_env } }
216+
let(:rails_env) { 'test' }
217+
218+
it 'handles no action mailer preview' do
219+
expect(capture_exec(custom_env, exec_script)).to have_no_preview
220+
end
221+
222+
it 'allows initializers to set options' do
223+
expect(
224+
capture_exec(
225+
custom_env.merge('DEFAULT_URL' => 'test-host'),
226+
exec_script
227+
)
228+
).to eq('test-host')
229+
end
230+
231+
it 'handles action mailer not being available' do
232+
expect(
233+
capture_exec(
234+
custom_env.merge('NO_ACTION_MAILER' => 'true'),
235+
exec_script
236+
)
237+
).to have_no_preview
238+
end
181239
end
182240
end
183241
end

lib/rspec-rails.rb

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,12 @@ class Railtie < ::Rails::Railtie
2929
private
3030

3131
def setup_preview_path(app)
32-
# If the action mailer railtie isn't loaded the config will not respond
3332
return unless supports_action_mailer_previews?(app.config)
3433
options = app.config.action_mailer
3534
config_default_preview_path(options) if config_preview_path?(options)
3635
end
3736

3837
def config_preview_path?(options)
39-
# This string version check avoids loading the ActionMailer class, as
40-
# would happen using `defined?`. This is necessary because the
41-
# ActionMailer class only loads it's settings once, at load time. If we
42-
# load the class now any settings declared in a config block in an
43-
# initializer will be ignored.
44-
#
4538
# We cannot use `respond_to?(:show_previews)` here as it will always
4639
# return `true`.
4740
if ::Rails::VERSION::STRING < '4.2'
@@ -59,8 +52,18 @@ def config_default_preview_path(options)
5952
end
6053

6154
def supports_action_mailer_previews?(config)
62-
config.respond_to?(:action_mailer) &&
63-
config.action_mailer.respond_to?(:preview_path)
55+
# These checks avoid loading `ActionMailer`. Using `defined?` has the
56+
# side-effect of the class getting loaded if it is available. This is
57+
# problematic because loading `ActionMailer::Base` will cause it to
58+
# read the config settings; this is the only time the config is read.
59+
# If the config is loaded now, any settings declared in a config block
60+
# in an initializer will be ignored.
61+
#
62+
# If the action mailer railtie has not been loaded then `config` will
63+
# not respond to the method. However, we cannot use
64+
# `config.action_mailer.respond_to?(:preview_path)` here as it will
65+
# always return `true`.
66+
config.respond_to?(:action_mailer) && ::Rails::VERSION::STRING > '4.1'
6467
end
6568
end
6669
end

0 commit comments

Comments
 (0)