panda_pal 4.1.0.beta3 → 5.0.0.beta.1
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 +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
|