signinable 2.0.10 → 2.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +6 -4
- data/app/models/signin.rb +24 -5
- data/config/routes.rb +2 -0
- data/db/migrate/20140103165607_create_signins.rb +7 -5
- data/db/migrate/20180530131006_add_custom_data_to_sigins.rb +5 -5
- data/lib/signinable/engine.rb +6 -9
- data/lib/signinable/model_additions.rb +117 -51
- data/lib/signinable/version.rb +3 -1
- data/lib/signinable.rb +3 -1
- data/spec/dummy/Rakefile +3 -1
- data/spec/dummy/app/models/user.rb +3 -1
- data/spec/dummy/bin/bundle +3 -1
- data/spec/dummy/bin/rails +3 -1
- data/spec/dummy/bin/rake +2 -0
- data/spec/dummy/config/application.rb +5 -20
- data/spec/dummy/config/boot.rb +5 -3
- data/spec/dummy/config/environment.rb +3 -1
- data/spec/dummy/config/environments/development.rb +4 -2
- data/spec/dummy/config/environments/production.rb +2 -0
- data/spec/dummy/config/environments/test.rb +4 -2
- data/spec/dummy/config/initializers/backtrace_silencers.rb +1 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +2 -0
- data/spec/dummy/config/initializers/inflections.rb +1 -0
- data/spec/dummy/config/initializers/mime_types.rb +1 -0
- data/spec/dummy/config/initializers/secret_token.rb +2 -0
- data/spec/dummy/config/initializers/session_store.rb +2 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/config.ru +3 -1
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20140103165606_create_users.rb +3 -1
- data/spec/dummy/db/schema.rb +23 -24
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +427 -0
- data/spec/dummy/log/test.log +20023 -0
- data/spec/factories/signins.rb +8 -0
- data/spec/factories/users.rb +7 -0
- data/spec/models/signin_spec.rb +85 -33
- data/spec/models/user_spec.rb +204 -84
- data/spec/rails_helper.rb +20 -0
- data/spec/spec_helper.rb +11 -12
- data/spec/support/utilities.rb +3 -2
- metadata +76 -38
- data/spec/factories/signin.rb +0 -8
- data/spec/factories/user.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e090b91cbbcbbfe860ca07984e3a19a965cc96bf2909f4e469e5d0ed48794dbe
|
4
|
+
data.tar.gz: c84bacb35618b62991ab60c984ec8f8c9786d783c3dd3dc8dc6a9ea76ed4881e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e96a9511dd6560c05ddfdc03b94d71ea83720e982526412a59a8e4a0461d475a4fb970ceb680636f23f144cb2273a811a0014897bf77597eeff7c7652d7e962
|
7
|
+
data.tar.gz: 2dcc381256505cebdeb990ac0340200c3134c8e1337f1bbe41082e233d35187ecdc4e30aebf71d316ea99da7de861649415514d9043eaf958df59b630c38d439
|
data/Rakefile
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
4
|
require 'bundler/setup'
|
3
5
|
rescue LoadError
|
4
6
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
7
|
end
|
6
8
|
|
7
|
-
APP_RAKEFILE = File.expand_path(
|
9
|
+
APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
|
8
10
|
load 'rails/tasks/engine.rake'
|
9
11
|
|
10
12
|
Bundler::GemHelper.install_tasks
|
@@ -12,7 +14,7 @@ Bundler::GemHelper.install_tasks
|
|
12
14
|
require 'rspec/core'
|
13
15
|
require 'rspec/core/rake_task'
|
14
16
|
|
15
|
-
desc
|
16
|
-
RSpec::Core::RakeTask.new(:
|
17
|
+
desc 'Run all specs in spec directory (excluding plugin specs)'
|
18
|
+
RSpec::Core::RakeTask.new(spec: 'app:db:test:prepare')
|
17
19
|
|
18
|
-
task :
|
20
|
+
task default: :spec
|
data/app/models/signin.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'resolv'
|
2
4
|
|
3
5
|
class Signin < ActiveRecord::Base
|
@@ -8,19 +10,36 @@ class Signin < ActiveRecord::Base
|
|
8
10
|
presence: true,
|
9
11
|
format: { with: Regexp.union(Resolv::IPv4::Regex, Resolv::IPv6::Regex) }
|
10
12
|
|
13
|
+
scope :active, -> { where('expiration_time IS NULL OR expiration_time > ?', Time.zone.now) }
|
14
|
+
|
11
15
|
before_validation on: :create do
|
12
|
-
self.token =
|
16
|
+
self.token = generate_token
|
13
17
|
end
|
14
18
|
|
19
|
+
serialize :custom_data if ActiveRecord::Base.connection.instance_values['config'][:adapter].match('mysql')
|
20
|
+
|
15
21
|
def expire!
|
16
|
-
|
22
|
+
renew!(period: 0, ip: ip, user_agent: user_agent)
|
17
23
|
end
|
18
24
|
|
19
25
|
def expired?
|
20
|
-
|
26
|
+
expireable? && expiration_time.past?
|
27
|
+
end
|
28
|
+
|
29
|
+
def expireable?
|
30
|
+
!expiration_time.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def renew!(period:, ip:, user_agent:, refresh_token: false)
|
34
|
+
update_hash = { ip: ip, user_agent: user_agent }
|
35
|
+
update_hash[:expiration_time] = Time.zone.now + period if expireable?
|
36
|
+
update_hash[:token] = generate_token if refresh_token
|
37
|
+
update!(update_hash)
|
21
38
|
end
|
22
39
|
|
23
|
-
|
24
|
-
|
40
|
+
private
|
41
|
+
|
42
|
+
def generate_token
|
43
|
+
SecureRandom.urlsafe_base64(rand(50..100))
|
25
44
|
end
|
26
45
|
end
|
data/config/routes.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
migration_kls = Rails::VERSION::MAJOR > 4 ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
|
2
4
|
class CreateSignins < migration_kls
|
3
5
|
def self.up
|
@@ -5,18 +7,18 @@ class CreateSignins < migration_kls
|
|
5
7
|
t.integer :signinable_id, null: false
|
6
8
|
t.string :signinable_type, null: false
|
7
9
|
t.string :token, null: false
|
8
|
-
t.string :referer, default:
|
9
|
-
t.string :user_agent, default:
|
10
|
+
t.string :referer, default: ''
|
11
|
+
t.string :user_agent, default: ''
|
10
12
|
t.string :ip, null: false
|
11
13
|
t.datetime :expiration_time
|
12
14
|
t.timestamps
|
13
15
|
end
|
14
16
|
|
15
|
-
if ActiveRecord::Base.connection.instance_values[
|
16
|
-
execute
|
17
|
+
if ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'postgresql'
|
18
|
+
execute 'ALTER TABLE signins ALTER COLUMN ip TYPE inet USING ip::inet'
|
17
19
|
end
|
18
20
|
|
19
|
-
add_index :signins, [
|
21
|
+
add_index :signins, %i[signinable_id signinable_type]
|
20
22
|
add_index :signins, :token
|
21
23
|
end
|
22
24
|
|
@@ -1,13 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
migration_kls = Rails::VERSION::MAJOR > 4 ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
|
2
4
|
|
3
5
|
class AddCustomDataToSigins < migration_kls
|
4
6
|
def change
|
5
|
-
|
6
|
-
|
7
|
-
add_column :signins, :custom_data, :jsonb, null:false, default: {}
|
7
|
+
if ActiveRecord::Base.connection.instance_values['config'][:adapter] == 'postgresql'
|
8
|
+
add_column :signins, :custom_data, :jsonb, null: false, default: {}
|
8
9
|
else
|
9
|
-
add_column :signins, :custom_data, :string, null:false, default: {}.to_json
|
10
|
+
add_column :signins, :custom_data, :string, null: false, default: {}.to_json
|
10
11
|
end
|
11
|
-
|
12
12
|
end
|
13
13
|
end
|
data/lib/signinable/engine.rb
CHANGED
@@ -1,18 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwt'
|
4
|
+
|
1
5
|
module Signinable
|
2
6
|
class Engine < ::Rails::Engine
|
3
7
|
initializer :append_migrations do |app|
|
4
8
|
unless app.root.to_s.match(root.to_s)
|
5
|
-
config.paths[
|
6
|
-
app.config.paths[
|
9
|
+
config.paths['db/migrate'].expanded.each do |path|
|
10
|
+
app.config.paths['db/migrate'] << path
|
7
11
|
end
|
8
12
|
end
|
9
13
|
end
|
10
|
-
|
11
|
-
config.generators do |g|
|
12
|
-
g.test_framework :rspec, :fixture => false
|
13
|
-
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
14
|
-
g.assets false
|
15
|
-
g.helper false
|
16
|
-
end
|
17
14
|
end
|
18
15
|
end
|
@@ -1,87 +1,153 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Signinable
|
2
4
|
module ModelAdditions
|
3
5
|
extend ActiveSupport::Concern
|
4
6
|
|
5
7
|
module ClassMethods
|
8
|
+
ALLOWED_RESTRICTIONS = %i[ip user_agent].freeze
|
9
|
+
DEFAULT_REFRESH_EXP = 7200
|
10
|
+
DEFAULT_JWT_EXP = 900
|
11
|
+
|
12
|
+
cattr_reader :refresh_exp
|
13
|
+
cattr_reader :simultaneous_signings
|
14
|
+
cattr_reader :signin_restrictions
|
15
|
+
cattr_reader :jwt_secret
|
16
|
+
cattr_reader :jwt_exp
|
17
|
+
|
6
18
|
def signinable(options = {})
|
7
|
-
|
8
|
-
|
9
|
-
cattr_accessor :signin_restrictions
|
10
|
-
self.signin_expiration = options.fetch(:expiration, 2.hours)
|
11
|
-
self.signin_simultaneous = options.fetch(:simultaneous, true)
|
19
|
+
self.refresh_exp = options.fetch(:expiration, DEFAULT_REFRESH_EXP)
|
20
|
+
self.simultaneous_signings = options.fetch(:simultaneous, true)
|
12
21
|
self.signin_restrictions = options[:restrictions]
|
22
|
+
self.jwt_secret = options.fetch(:jwt_secret)
|
23
|
+
self.jwt_exp = options.fetch(:jwt_exp, DEFAULT_JWT_EXP)
|
13
24
|
|
14
25
|
has_many :signins, as: :signinable, dependent: :destroy
|
26
|
+
|
27
|
+
attr_accessor :jwt
|
15
28
|
end
|
16
29
|
|
17
|
-
def authenticate_with_token(
|
18
|
-
|
19
|
-
|
20
|
-
self.signin_expiration = self.signin_expiration.call(signin.signinable)
|
21
|
-
end
|
30
|
+
def authenticate_with_token(jwt, ip, user_agent, skip_restrictions: [])
|
31
|
+
jwt_payload = extract_jwt_payload(jwt)
|
32
|
+
return refresh_jwt(jwt, ip, user_agent, skip_restrictions: skip_restrictions) unless jwt_payload
|
22
33
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
34
|
+
find_by(primary_key => jwt_payload['signinable_id'])
|
35
|
+
end
|
26
36
|
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
def check_signin_permission(signin, restrictions_to_check, skip_restrictions)
|
38
|
+
signin_permitted?(signin, restrictions_to_check, skip_restrictions)
|
39
|
+
end
|
30
40
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
41
|
+
def expiration_period
|
42
|
+
return refresh_exp.call if refresh_exp.respond_to?(:call)
|
43
|
+
|
44
|
+
refresh_exp
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_jwt(refresh_token, signinable_id)
|
48
|
+
JWT.encode(
|
49
|
+
{
|
50
|
+
refresh_token: refresh_token,
|
51
|
+
signinable_id: signinable_id,
|
52
|
+
exp: Time.zone.now.to_i + jwt_exp
|
53
|
+
},
|
54
|
+
jwt_secret,
|
55
|
+
'HS256'
|
56
|
+
)
|
35
57
|
end
|
36
58
|
|
37
|
-
def
|
38
|
-
|
59
|
+
def refresh_jwt(jwt, ip, user_agent, skip_restrictions: [])
|
60
|
+
token = refresh_token_from_jwt(jwt)
|
61
|
+
return nil unless token
|
62
|
+
|
63
|
+
signin = Signin.find_by(token: token)
|
64
|
+
|
65
|
+
return unless signin
|
66
|
+
return nil if signin.expired?
|
67
|
+
return nil unless check_signin_permission(signin, { ip: ip, user_agent: user_agent }, skip_restrictions)
|
68
|
+
|
69
|
+
signin.renew!(period: expiration_period, ip: ip, user_agent: user_agent, refresh_token: true)
|
70
|
+
signin.signinable.jwt = generate_jwt(signin.token, signin.signinable_id)
|
71
|
+
signin.signinable
|
39
72
|
end
|
40
73
|
|
41
74
|
private
|
42
|
-
def signin_permitted?(signin, ip, user_agent, skip_restrictions)
|
43
|
-
restriction_fields = case
|
44
|
-
when self.signin_restrictions.respond_to?(:call)
|
45
|
-
self.signin_restrictions.call(signin.signinable)
|
46
|
-
when self.signin_restrictions.is_a?(Array)
|
47
|
-
self.signin_restrictions
|
48
|
-
else
|
49
|
-
[]
|
50
|
-
end
|
51
75
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
76
|
+
cattr_writer :refresh_exp
|
77
|
+
cattr_writer :simultaneous_signings
|
78
|
+
cattr_writer :signin_restrictions
|
79
|
+
cattr_writer :jwt_secret
|
80
|
+
cattr_writer :jwt_exp
|
81
|
+
|
82
|
+
def extract_jwt_payload(jwt)
|
83
|
+
JWT.decode(jwt, jwt_secret, true, { algorithm: 'HS256' })[0]
|
84
|
+
rescue JWT::DecodeError
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
|
88
|
+
def refresh_token_from_jwt(jwt)
|
89
|
+
JWT.decode(jwt, jwt_secret, true, { verify_expiration: false, algorithm: 'HS256' })[0]['refresh_token']
|
90
|
+
rescue JWT::DecodeError
|
91
|
+
nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def signin_permitted?(signin, restrictions_to_check, skip_restrictions)
|
95
|
+
restriction_fields = signin_restriction_fields(signin, skip_restrictions)
|
96
|
+
|
97
|
+
restrictions_to_check.slice(*restriction_fields).each do |field, value|
|
98
|
+
return false unless signin.send(field) == value
|
56
99
|
end
|
57
100
|
|
58
|
-
|
101
|
+
true
|
59
102
|
end
|
60
|
-
end
|
61
103
|
|
62
|
-
|
63
|
-
|
64
|
-
|
104
|
+
def signin_restriction_fields(signin, skip_restrictions)
|
105
|
+
fields = if signin_restrictions.respond_to?(:call)
|
106
|
+
signin_restrictions.call(signin.signinable)
|
107
|
+
elsif signin_restrictions.is_a?(Array)
|
108
|
+
signin_restrictions
|
109
|
+
else
|
110
|
+
[]
|
111
|
+
end
|
112
|
+
(fields - skip_restrictions) & ALLOWED_RESTRICTIONS
|
65
113
|
end
|
66
|
-
expiration_time = (self.class.signin_expiration == 0 || permanent) ? nil : (Time.zone.now + self.class.signin_expiration)
|
67
|
-
Signin.create!(custom_data: custom_data, signinable: self, ip: ip, referer: referer, user_agent: user_agent, expiration_time: expiration_time).token
|
68
114
|
end
|
69
115
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
73
|
-
|
116
|
+
def signin(ip, user_agent, referer, permanent: false, custom_data: {})
|
117
|
+
expires_in = self.class.expiration_period
|
118
|
+
expiration_time = expires_in.zero? || permanent ? nil : expires_in.seconds.from_now
|
119
|
+
Signin.where(signinable: self).active.map(&:expire!) unless self.class.simultaneous_signings
|
120
|
+
signin = Signin.create!(
|
121
|
+
signinable: self,
|
122
|
+
ip: ip,
|
123
|
+
referer: referer,
|
124
|
+
user_agent: user_agent,
|
125
|
+
expiration_time: expiration_time,
|
126
|
+
custom_data: custom_data
|
127
|
+
)
|
128
|
+
|
129
|
+
self.jwt = self.class.generate_jwt(signin.token, signin.signinable_id)
|
130
|
+
end
|
131
|
+
|
132
|
+
def signout(token, ip, user_agent, skip_restrictions: [])
|
133
|
+
signin = Signin.find_by_token(token)
|
74
134
|
|
75
|
-
|
76
|
-
|
135
|
+
return unless signin
|
136
|
+
return unless self.class.check_signin_permission(
|
137
|
+
signin,
|
138
|
+
{ ip: ip, user_agent: user_agent },
|
139
|
+
skip_restrictions
|
140
|
+
)
|
141
|
+
|
142
|
+
signin.expire!
|
77
143
|
|
78
|
-
|
144
|
+
true
|
79
145
|
end
|
80
146
|
|
81
147
|
def last_signin
|
82
|
-
signins.last
|
148
|
+
signins.active.last
|
83
149
|
end
|
84
150
|
end
|
85
151
|
end
|
86
152
|
|
87
|
-
ActiveRecord::Base.
|
153
|
+
ActiveRecord::Base.include Signinable::ModelAdditions
|
data/lib/signinable/version.rb
CHANGED
data/lib/signinable.rb
CHANGED
data/spec/dummy/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
4
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
5
|
|
4
|
-
require File.expand_path('
|
6
|
+
require File.expand_path('config/application', __dir__)
|
5
7
|
|
6
8
|
Dummy::Application.load_tasks
|
data/spec/dummy/bin/bundle
CHANGED
data/spec/dummy/bin/rails
CHANGED
data/spec/dummy/bin/rake
CHANGED
@@ -1,28 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require
|
6
|
-
require "action_mailer/railtie"
|
7
|
-
require "sprockets/railtie"
|
8
|
-
# require "rails/test_unit/railtie"
|
3
|
+
require File.expand_path('boot', __dir__)
|
4
|
+
|
5
|
+
require 'active_record/railtie'
|
9
6
|
|
10
7
|
Bundler.require(*Rails.groups)
|
11
|
-
require
|
8
|
+
require 'signinable'
|
12
9
|
|
13
10
|
module Dummy
|
14
11
|
class Application < Rails::Application
|
15
|
-
# Settings in config/environments/* take precedence over those specified here.
|
16
|
-
# Application configuration should go into files in config/initializers
|
17
|
-
# -- all .rb files in that directory are automatically loaded.
|
18
|
-
|
19
|
-
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
20
|
-
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
21
|
-
# config.time_zone = 'Central Time (US & Canada)'
|
22
|
-
|
23
|
-
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
24
|
-
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
25
|
-
# config.i18n.default_locale = :de
|
26
12
|
end
|
27
13
|
end
|
28
|
-
|
data/spec/dummy/config/boot.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Set up gems listed in the Gemfile.
|
2
|
-
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('
|
4
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__)
|
3
5
|
|
4
|
-
require 'bundler/setup' if File.
|
5
|
-
$LOAD_PATH.unshift File.expand_path('
|
6
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
7
|
+
$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Dummy::Application.configure do
|
2
4
|
# Settings specified here will take precedence over those in config/application.rb.
|
3
5
|
|
@@ -14,7 +16,7 @@ Dummy::Application.configure do
|
|
14
16
|
config.action_controller.perform_caching = false
|
15
17
|
|
16
18
|
# Don't care if the mailer can't send.
|
17
|
-
config.action_mailer.raise_delivery_errors = false
|
19
|
+
# config.action_mailer.raise_delivery_errors = false
|
18
20
|
|
19
21
|
# Print deprecation notices to the Rails logger.
|
20
22
|
config.active_support.deprecation = :log
|
@@ -25,5 +27,5 @@ Dummy::Application.configure do
|
|
25
27
|
# Debug mode disables concatenation and preprocessing of assets.
|
26
28
|
# This option may cause significant delays in view rendering with a large
|
27
29
|
# number of complex assets.
|
28
|
-
config.assets.debug = true
|
30
|
+
# config.assets.debug = true
|
29
31
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Dummy::Application.configure do
|
2
4
|
# Settings specified here will take precedence over those in config/application.rb.
|
3
5
|
|
@@ -14,7 +16,7 @@ Dummy::Application.configure do
|
|
14
16
|
|
15
17
|
# Configure static asset server for tests with Cache-Control for performance.
|
16
18
|
config.serve_static_assets = true
|
17
|
-
config.static_cache_control =
|
19
|
+
config.static_cache_control = 'public, max-age=3600'
|
18
20
|
|
19
21
|
# Show full error reports and disable caching.
|
20
22
|
config.consider_all_requests_local = true
|
@@ -29,7 +31,7 @@ Dummy::Application.configure do
|
|
29
31
|
# Tell Action Mailer not to deliver emails to the real world.
|
30
32
|
# The :test delivery method accumulates sent emails in the
|
31
33
|
# ActionMailer::Base.deliveries array.
|
32
|
-
config.action_mailer.delivery_method = :test
|
34
|
+
# config.action_mailer.delivery_method = :test
|
33
35
|
|
34
36
|
# Print deprecation notices to the stderr.
|
35
37
|
config.active_support.deprecation = :stderr
|
data/spec/dummy/config/routes.rb
CHANGED
data/spec/dummy/config.ru
CHANGED
File without changes
|