panda_pal 4.1.0.beta3 → 5.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +81 -71
- data/app/models/panda_pal/organization.rb +46 -17
- data/app/views/panda_pal/lti/iframe_cookie_authorize.html.erb +19 -0
- data/db/618eef7c0380ba654ad16f867a919e72.sqlite3 +0 -0
- data/db/9ff93d4f7e0e9dc80a43f68997caf4a1.sqlite3 +0 -0
- data/db/a3fda4044a7215bc2c9eb01a4b9e517a.sqlite3 +0 -0
- data/db/daa0e6378a5ec76fcce83b7070dad219.sqlite3 +0 -0
- data/lib/panda_pal/helpers/controller_helper.rb +60 -15
- data/lib/panda_pal/version.rb +1 -1
- data/panda_pal.gemspec +0 -3
- data/spec/dummy/config/application.rb +1 -7
- data/spec/dummy/config/environments/development.rb +14 -0
- data/spec/dummy/config/environments/production.rb +11 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +15058 -0
- data/spec/dummy/log/test.log +0 -0
- data/spec/models/panda_pal/organization_spec.rb +89 -0
- data/spec/spec_helper.rb +0 -4
- metadata +18 -38
- data/app/models/panda_pal/organization/settings_validation.rb +0 -111
- data/app/models/panda_pal/organization/task_scheduling.rb +0 -172
- data/spec/models/panda_pal/organization/settings_validation_spec.rb +0 -175
- data/spec/models/panda_pal/organization/task_scheduling_spec.rb +0 -144
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 417de10d63af26bbeadb9b1fa5d57f74fad8070dec477ecf42f7ba914c46be4e
|
4
|
+
data.tar.gz: '0268833a242fda47935ec01207644c3a74daaa31b37b311401ac216b9e34f9bf'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1093764dca3b51778eb98cf8c8ce64bc88af73fb970e9f61597c3f71c92761729ad636ea156da7f2aad7d656ca2f35311f4cce72a338c3eb49f8cb85b788f229
|
7
|
+
data.tar.gz: ee960dc3a06b1da790af9ce3f9a7e6bb76bb06e75a2645097654833226ed84f1f9655455c396607b74981879bed44029147b55ead6efc6437b4abe1c9feb4699
|
data/README.md
CHANGED
@@ -28,38 +28,6 @@ Use one of these 6 options in `PandaPal.lti_options` hash.
|
|
28
28
|
5. Leave this property off, and you will get the dynamic host with the root path ('http://appdomain.com/') by default.
|
29
29
|
6. If you really do not want this property use the option `launch_url: false` for it to be left off.
|
30
30
|
|
31
|
-
### Task Scheduling
|
32
|
-
`PandaPal` includes an integration with `sidekiq-scheduler`. You can define tasks on an Organization class Stub like so:
|
33
|
-
```ruby
|
34
|
-
# <your_app>/app/models/organization.rb
|
35
|
-
module PandaPal
|
36
|
-
class Organization
|
37
|
-
# Will invoke CanvasSyncStarterWorker.perform_async() according to the cron schedule
|
38
|
-
scheduled_task '0 15 05 * * *', :identifier, worker: CanvasSyncStarterWorker
|
39
|
-
|
40
|
-
# Will invoke the method 'organization_method' on the Organization
|
41
|
-
scheduled_task '0 15 05 * * *', :organization_method_and_identifier
|
42
|
-
|
43
|
-
# If you need to invoke the same method on multiple schedules
|
44
|
-
scheduled_task '0 15 05 * * *', :identifier, worker: :organization_method
|
45
|
-
|
46
|
-
# You can also use a block
|
47
|
-
scheduled_task '0 15 05 * * *', :identifier do
|
48
|
-
# Do Stuff
|
49
|
-
end
|
50
|
-
|
51
|
-
# You can use a Proc (called in the context of the Organization) to determine the schedule
|
52
|
-
scheduled_task -> { settings[:cron] }, :identifier
|
53
|
-
|
54
|
-
# You can specify a timezone. If a TZ is not coded and settings[:timezone] is present, it will be appended automatically
|
55
|
-
scheduled_task '0 15 05 * * * America/Denver', :identifier, worker: :organization_method
|
56
|
-
|
57
|
-
# Setting settings[:task_schedules][:identifier] will override the code cron schedule. Setting it to false will disable the Task
|
58
|
-
# :identifer values _must_ be unique, but can be nil, in which case they will be determined by where (lineno etc) scheduled_task is called
|
59
|
-
end
|
60
|
-
end
|
61
|
-
```
|
62
|
-
|
63
31
|
# Organization Attributes
|
64
32
|
id: Primary Key
|
65
33
|
name: Name of the organization. Used to on requests to select the tenant
|
@@ -258,43 +226,9 @@ In your panda_pal initializer (i.e. config/initializers/panda_pal.rb or config/i
|
|
258
226
|
You can specify options that can include a structure for your settings. If specified, PandaPal will
|
259
227
|
enforce this structure on any new / updated organizations.
|
260
228
|
|
261
|
-
```ruby
|
262
|
-
PandaPal.lti_options = {
|
263
|
-
title: 'LBS Gradebook',
|
264
|
-
settings_structure: {
|
265
|
-
allow_additional: true, # Allow additional properties that aren't included in the :properties Hash.
|
266
|
-
allow_additional: { type: 'String' }, # You can also set :allow_additional to a settings specification that will be used to validate each additional setting
|
267
|
-
validate: ->(value, spec, **kwargs) {
|
268
|
-
# kwargs currently includes:
|
269
|
-
# :errors => [An array to push errors to]
|
270
|
-
# :path => [An array representation of the current path in the settings object]
|
271
|
-
|
272
|
-
# To add errors, you may:
|
273
|
-
# Push strings to the kwargs[:errors] Array:
|
274
|
-
kwargs[:errors] << "Your error message at <path>" unless value < 10
|
275
|
-
# Or return a string or string array:
|
276
|
-
value.valid? ? nil : "Your error message at <path>" # <path> will be replaced with the actual path that the error occurred at
|
277
|
-
},
|
278
|
-
properties: {
|
279
|
-
canvas_api_token: { type: 'String', required: true, },
|
280
|
-
catalog: { # :validate, :allow_additional, :properties keys are all supported at this level as well
|
281
|
-
type: 'Hash',
|
282
|
-
required: false,
|
283
|
-
validate: -> (*args) {},
|
284
|
-
allow_additional: false,
|
285
|
-
properties: {
|
286
|
-
|
287
|
-
},
|
288
|
-
}
|
289
|
-
}
|
290
|
-
},
|
291
|
-
}
|
292
|
-
```
|
293
|
-
|
294
|
-
#### Legacy Settings Structure:
|
295
229
|
Here is an example options specification:
|
296
230
|
|
297
|
-
```
|
231
|
+
```
|
298
232
|
PandaPal.lti_options = {
|
299
233
|
title: 'LBS Gradebook',
|
300
234
|
settings_structure: YAML.load("
|
@@ -347,7 +281,83 @@ Safari is weird, and you'll potentially run into issues getting `POST` requests
|
|
347
281
|
|
348
282
|
This will allow `PandaPal` to apply an iframe cookie fix that will allow CSRF validation to work.
|
349
283
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
284
|
+
|
285
|
+
### PandaPal 5
|
286
|
+
|
287
|
+
It has been a constant struggle to force safari to store and allow
|
288
|
+
access to a rails session while the application is embedded in Canvas.
|
289
|
+
|
290
|
+
As of PandaPal 5, a forced persistent session is now optional, and defaults to off.
|
291
|
+
|
292
|
+
This means that safari will likely refuse to send info about your rails session
|
293
|
+
back to the LTI, and the application will start up a new session each time the
|
294
|
+
browser navigates. This likely means a new session each time the LTI launches.
|
295
|
+
|
296
|
+
You will want to watch out for a few scenarios:
|
297
|
+
|
298
|
+
1) Make sure you are using "redirect_with_session_to" if you need to redirect
|
299
|
+
and have your PandaPal session_key persisted server side.
|
300
|
+
2) Use the "Authorization" header with "token={session_key}" to send your
|
301
|
+
PandaPal session info into api calls.
|
302
|
+
|
303
|
+
You can force a persistent session with -
|
304
|
+
PandaPal.lti_options = {
|
305
|
+
require_persistent_session: true
|
306
|
+
}
|
307
|
+
in your config/initializer. With that setting, the user will be required to
|
308
|
+
allow our application to store / access cookies in safari before they can use
|
309
|
+
the LTI.
|
310
|
+
|
311
|
+
# Notes on require_persistent_session
|
312
|
+
|
313
|
+
IF you must have a persistent session this is the logical flow of how panda_pal
|
314
|
+
attempts to set that up.
|
315
|
+
|
316
|
+
1) LTI laumches.
|
317
|
+
2) LTI will attempt to POST message from iframe to top window (canvas) telling
|
318
|
+
canvas to relaunch in full screen so we aren't inhibited by safari.
|
319
|
+
3) LTI will setup session and cookies in full-screen mode. Session will be saved
|
320
|
+
in browser.
|
321
|
+
4) LTI will redirect to an authorization page, that will require user to give
|
322
|
+
access to the session store to our application.
|
323
|
+
5) Once the user gives access to the session store, we will reload the LTI
|
324
|
+
and the cookie should now be persistent.
|
325
|
+
|
326
|
+
# Upgrading from PandaPal 4 to 5:
|
327
|
+
|
328
|
+
If your tool is setup according to a pretty standard pattern (see pace_plans,
|
329
|
+
canvas_group_enrollment, etc), you shouldn't have to do anything to upgrade.
|
330
|
+
|
331
|
+
You will want to make sure that IF your launch controller is redirecting, it is
|
332
|
+
using "redirect_with_session_to".
|
333
|
+
|
334
|
+
Here is an example launch / account controller setup, assuming an account launch.
|
335
|
+
|
336
|
+
```
|
337
|
+
class LaunchController < ApplicationController
|
338
|
+
# We don't verify CSRF on launch because the LTI launch is done via a POST
|
339
|
+
# request, and Canvas wouldn't know anything about the CSRF
|
340
|
+
skip_before_action :verify_authenticity_token
|
341
|
+
skip_before_action :forbid_access_if_lacking_session # We don't have a session yet
|
342
|
+
around_action :switch_tenant
|
343
|
+
before_action :validate_launch!
|
344
|
+
before_action :handle_launch
|
345
|
+
|
346
|
+
def handle_launch
|
347
|
+
current_session_data[:canvas_user_id] = params[:custom_canvas_user_id]
|
348
|
+
current_session_data[:canvas_course_id] = params[:custom_canvas_course_id]
|
349
|
+
end
|
350
|
+
|
351
|
+
def account
|
352
|
+
redirect_with_session_to :accounts_url
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
class AccountController < ApplicationController
|
357
|
+
prepend_before_action :forbid_access_if_lacking_session
|
358
|
+
|
359
|
+
def index
|
360
|
+
end
|
361
|
+
end
|
362
|
+
```
|
363
|
+
|
@@ -1,23 +1,15 @@
|
|
1
|
-
Dir[File.dirname(__FILE__) + "/organization/*.rb"].each { |file| require file }
|
2
|
-
|
3
1
|
module PandaPal
|
4
|
-
module OrganizationConcerns; end
|
5
2
|
|
6
3
|
class Organization < ActiveRecord::Base
|
7
|
-
include OrganizationConcerns::SettingsValidation
|
8
|
-
include OrganizationConcerns::TaskScheduling if defined?(Sidekiq.schedule)
|
9
|
-
|
10
4
|
attribute :settings
|
11
|
-
serialize :settings, Hash
|
12
5
|
attr_encrypted :settings, marshal: true, key: :encryption_key
|
13
6
|
before_save {|a| a.settings = a.settings} # this is a hacky work-around to a bug where attr_encrypted is not saving settings in place
|
14
|
-
|
15
7
|
validates :key, uniqueness: { case_sensitive: false }, presence: true
|
16
8
|
validates :secret, presence: true
|
17
9
|
validates :name, uniqueness: { case_sensitive: false }, presence: true, format: { with: /\A[a-z0-9_]+\z/i }
|
18
10
|
validates :canvas_account_id, presence: true
|
19
11
|
validates :salesforce_id, presence: true, uniqueness: true
|
20
|
-
|
12
|
+
validate :validate_settings
|
21
13
|
after_create :create_schema
|
22
14
|
after_commit :destroy_schema, on: :destroy
|
23
15
|
|
@@ -25,6 +17,8 @@ module PandaPal
|
|
25
17
|
errors.add(:name, 'should not be changed after creation') if name_changed?
|
26
18
|
end
|
27
19
|
|
20
|
+
serialize :settings, Hash
|
21
|
+
|
28
22
|
def encryption_key
|
29
23
|
# production environment might not have loaded secret_key_base yet.
|
30
24
|
# In that case, just read it from env.
|
@@ -35,14 +29,6 @@ module PandaPal
|
|
35
29
|
end
|
36
30
|
end
|
37
31
|
|
38
|
-
def switch_tenant(&block)
|
39
|
-
if block_given?
|
40
|
-
Apartment::Tenant.switch(name, &block)
|
41
|
-
else
|
42
|
-
Apartment::Tenant.switch!(name)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
32
|
private
|
47
33
|
|
48
34
|
def create_schema
|
@@ -52,5 +38,48 @@ module PandaPal
|
|
52
38
|
def destroy_schema
|
53
39
|
Apartment::Tenant.drop name
|
54
40
|
end
|
41
|
+
|
42
|
+
def validate_settings
|
43
|
+
record = self
|
44
|
+
if PandaPal.lti_options && PandaPal.lti_options[:settings_structure]
|
45
|
+
validate_level(record, PandaPal.lti_options[:settings_structure], record.settings, [])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
def validate_level(record, expectation, reality, previous_keys)
|
49
|
+
# Verify that the data elements at this level conform to requirements.
|
50
|
+
if expectation
|
51
|
+
expectation.each do |key, value|
|
52
|
+
is_required = expectation[key].try(:delete, :is_required)
|
53
|
+
data_type = expectation[key].try(:delete, :data_type)
|
54
|
+
value = reality.is_a?(Hash) ? reality.dig(key) : reality
|
55
|
+
|
56
|
+
if is_required && !value
|
57
|
+
record.errors[:settings] << "PandaPal::Organization.settings requires key [:#{previous_keys.push(key).join("][:")}]. It was not found."
|
58
|
+
end
|
59
|
+
if data_type && value
|
60
|
+
if value.class.to_s != data_type
|
61
|
+
record.errors[:settings] << "PandaPal::Organization.settings expected key [:#{previous_keys.push(key).join("][:")}] to be #{data_type} but it was instead #{value.class}."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
# Verify that anything that is in the real settings has an expectation.
|
67
|
+
if reality
|
68
|
+
if reality.is_a? Hash
|
69
|
+
reality.each do |key, value|
|
70
|
+
was_expected = expectation.has_key?(key)
|
71
|
+
if !was_expected
|
72
|
+
record.errors[:settings] << "PandaPal::Organization.settings had unexpected key: #{key}. If settings have expanded please update your lti_options accordingly."
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
# Recursively check out any children settings as well.
|
78
|
+
if expectation
|
79
|
+
expectation.each do |key, value|
|
80
|
+
validate_level(record, expectation[key], (reality.is_a?(Hash) ? reality.dig(key) : nil), previous_keys.deep_dup.push(key))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
55
84
|
end
|
56
85
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<html>
|
2
|
+
<p>Safari requires your consent to access session information when applications are hosted inside of Canvas. Please consent by clicking the following button.</p>
|
3
|
+
<button id="myButton">Authorize application to use browser session</button>
|
4
|
+
<script nonce=<%= content_security_policy_script_nonce %>>
|
5
|
+
function makeRequestWithUserGesture() {
|
6
|
+
var promise = document.requestStorageAccess();
|
7
|
+
promise.then(
|
8
|
+
function () {
|
9
|
+
var referrer = document.referrer;
|
10
|
+
window.location='?safari_cookie_authorized=true&return_to='.concat(encodeURI(window.location));
|
11
|
+
},
|
12
|
+
function () {
|
13
|
+
// If the user doesn't consent, then do nothing.
|
14
|
+
}
|
15
|
+
);
|
16
|
+
}
|
17
|
+
document.getElementById("myButton").addEventListener("click", makeRequestWithUserGesture);
|
18
|
+
</script>
|
19
|
+
</html>
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -42,20 +42,29 @@ module PandaPal::Helpers::ControllerHelper
|
|
42
42
|
render plain: 'Invalid Credentials, please contact your Administrator.', :status => :unauthorized unless authorized
|
43
43
|
return authorized
|
44
44
|
end
|
45
|
-
if
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
if require_persistent_session
|
46
|
+
if cookies_need_iframe_fix?(false)
|
47
|
+
fix_iframe_cookies
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
# For safari we may have been launched temporarily full-screen by canvas. This allows us to set the session cookie.
|
51
|
+
# In this case, we should make sure the session cookie is fixed and redirect back to canvas to properly launch the embedded LTI.
|
52
|
+
if params[:platform_redirect_url]
|
53
|
+
session[:safari_cookie_fixed] = true
|
54
|
+
redirect_to params[:platform_redirect_url]
|
55
|
+
return false
|
56
|
+
end
|
55
57
|
end
|
56
58
|
return authorized
|
57
59
|
end
|
58
60
|
|
61
|
+
def require_persistent_session
|
62
|
+
if PandaPal.lti_options.has_key?(:require_persistent_session) && PandaPal.lti_options[:require_persistent_session] == true
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
|
59
68
|
def switch_tenant(organization = current_organization, &block)
|
60
69
|
return unless organization
|
61
70
|
raise 'This method should be called in an around_action callback' unless block_given?
|
@@ -70,20 +79,26 @@ module PandaPal::Helpers::ControllerHelper
|
|
70
79
|
# redirect the current page to the LTI using JavaScript, which will set the cookie,
|
71
80
|
# and then immediately redirect back to Canvas.
|
72
81
|
def fix_iframe_cookies
|
73
|
-
if params[:
|
74
|
-
session[:
|
82
|
+
if params[:safari_cookie_authorized].present?
|
83
|
+
session[:safari_cookie_authorized] = true
|
75
84
|
redirect_to params[:return_to]
|
85
|
+
elsif (session[:safari_cookie_fixed] && !params[:safari_cookie_authorized])
|
86
|
+
render 'panda_pal/lti/iframe_cookie_authorize', layout: false
|
76
87
|
else
|
77
88
|
render 'panda_pal/lti/iframe_cookie_fix', layout: false
|
78
89
|
end
|
79
90
|
end
|
80
91
|
|
81
|
-
def cookies_need_iframe_fix?
|
82
|
-
|
92
|
+
def cookies_need_iframe_fix?(check_authorized=true)
|
93
|
+
if check_authorized
|
94
|
+
return browser.safari? && !request.referrer&.include?('sessionless_launch') && !(session[:safari_cookie_fixed] && session[:safari_cookie_authorized]) && !params[:platform_redirect_url]
|
95
|
+
else
|
96
|
+
return browser.safari? && !request.referrer&.include?('sessionless_launch') && !session[:safari_cookie_fixed] && !params[:platform_redirect_url]
|
97
|
+
end
|
83
98
|
end
|
84
99
|
|
85
100
|
def forbid_access_if_lacking_session
|
86
|
-
if cookies_need_iframe_fix?
|
101
|
+
if require_persistent_session && cookies_need_iframe_fix?(true)
|
87
102
|
fix_iframe_cookies
|
88
103
|
else
|
89
104
|
render plain: 'You should do an LTI Tool Launch.', status: :unauthorized unless valid_session?
|
@@ -122,4 +137,34 @@ module PandaPal::Helpers::ControllerHelper
|
|
122
137
|
match[1]
|
123
138
|
end
|
124
139
|
end
|
140
|
+
|
141
|
+
# Redirect with the session key intact. In production,
|
142
|
+
# handle this by saving it to the flash. In dev,
|
143
|
+
# just put it in the URL. Putting it in the URL
|
144
|
+
# is insecure, but is fine in development.
|
145
|
+
# Keeping it in the URL in development means that it plays
|
146
|
+
# nicely with webpack-dev-server live reloading (otherwise
|
147
|
+
# you get an access error everytime it tries to live reload).
|
148
|
+
|
149
|
+
def redirect_with_session_to(location, params = {})
|
150
|
+
if Rails.env.development?
|
151
|
+
redirect_development_mode(location, params)
|
152
|
+
else
|
153
|
+
redirect_production_mode(location, params)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def redirect_development_mode(location, params)
|
158
|
+
redirect_to send(location, {
|
159
|
+
session_key: current_session.session_key,
|
160
|
+
organization_id: current_organization.id
|
161
|
+
}.merge(params))
|
162
|
+
end
|
163
|
+
|
164
|
+
def redirect_production_mode(location, params)
|
165
|
+
flash['session_key'] = current_session.session_key
|
166
|
+
redirect_to send(location, {
|
167
|
+
organization_id: current_organization.id
|
168
|
+
}.merge(params))
|
169
|
+
end
|
125
170
|
end
|
data/lib/panda_pal/version.rb
CHANGED
data/panda_pal.gemspec
CHANGED
@@ -22,9 +22,6 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.add_dependency 'browser', '2.5.0'
|
23
23
|
s.add_dependency 'attr_encrypted', '~> 3.0.0'
|
24
24
|
s.add_dependency 'secure_headers', '~> 6.1.2'
|
25
|
-
|
26
|
-
s.add_development_dependency 'sidekiq'
|
27
|
-
s.add_development_dependency 'sidekiq-scheduler'
|
28
25
|
s.add_development_dependency 'rspec-rails'
|
29
26
|
s.add_development_dependency 'factory_girl_rails'
|
30
27
|
end
|
@@ -1,12 +1,6 @@
|
|
1
1
|
require File.expand_path('../boot', __FILE__)
|
2
2
|
|
3
|
-
require
|
4
|
-
require "active_job/railtie"
|
5
|
-
require "active_record/railtie"
|
6
|
-
# require "active_storage/engine"
|
7
|
-
require "action_controller/railtie"
|
8
|
-
require "action_mailer/railtie"
|
9
|
-
require "action_view/railtie"
|
3
|
+
require 'rails/all'
|
10
4
|
|
11
5
|
Bundler.require(*Rails.groups)
|
12
6
|
require "panda_pal"
|
@@ -22,6 +22,20 @@ Rails.application.configure do
|
|
22
22
|
# Raise an error on page load if there are pending migrations.
|
23
23
|
config.active_record.migration_error = :page_load
|
24
24
|
|
25
|
+
# Debug mode disables concatenation and preprocessing of assets.
|
26
|
+
# This option may cause significant delays in view rendering with a large
|
27
|
+
# number of complex assets.
|
28
|
+
config.assets.debug = true
|
29
|
+
|
30
|
+
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
31
|
+
# yet still be able to expire them through the digest params.
|
32
|
+
config.assets.digest = true
|
33
|
+
|
34
|
+
# Adds additional error checking when serving assets at runtime.
|
35
|
+
# Checks for improperly declared sprockets dependencies.
|
36
|
+
# Raises helpful error messages.
|
37
|
+
config.assets.raise_runtime_errors = true
|
38
|
+
|
25
39
|
# Raises error for missing translations
|
26
40
|
# config.action_view.raise_on_missing_translations = true
|
27
41
|
end
|
@@ -24,6 +24,17 @@ Rails.application.configure do
|
|
24
24
|
# Apache or NGINX already handles this.
|
25
25
|
config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
|
26
26
|
|
27
|
+
# Compress JavaScripts and CSS.
|
28
|
+
config.assets.js_compressor = :uglifier
|
29
|
+
# config.assets.css_compressor = :sass
|
30
|
+
|
31
|
+
# Do not fallback to assets pipeline if a precompiled asset is missed.
|
32
|
+
config.assets.compile = false
|
33
|
+
|
34
|
+
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
|
35
|
+
# yet still be able to expire them through the digest params.
|
36
|
+
config.assets.digest = true
|
37
|
+
|
27
38
|
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
|
28
39
|
|
29
40
|
# Specifies the header that your server uses for sending files.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Be sure to restart your server when you modify this file.
|
2
|
+
|
3
|
+
# Version of your assets, change this if you want to expire all your assets.
|
4
|
+
Rails.application.config.assets.version = '1.0'
|
5
|
+
|
6
|
+
# Add additional assets to the asset load path
|
7
|
+
# Rails.application.config.assets.paths << Emoji.images_path
|
8
|
+
|
9
|
+
# Precompile additional assets.
|
10
|
+
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
|
11
|
+
# Rails.application.config.assets.precompile += %w( search.js )
|
Binary file
|
Binary file
|