rails 4.1.4 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -10
- data/guides/CHANGELOG.md +15 -25
- data/guides/Rakefile +5 -3
- data/guides/assets/javascripts/guides.js +6 -0
- data/guides/assets/stylesheets/main.css +4 -1
- data/guides/bug_report_templates/action_controller_gem.rb +2 -2
- data/guides/bug_report_templates/action_controller_master.rb +3 -2
- data/guides/rails_guides/helpers.rb +1 -1
- data/guides/rails_guides/levenshtein.rb +29 -21
- data/guides/rails_guides/markdown/renderer.rb +1 -1
- data/guides/rails_guides/markdown.rb +11 -7
- data/guides/rails_guides.rb +2 -2
- data/guides/source/2_2_release_notes.md +1 -1
- data/guides/source/2_3_release_notes.md +4 -4
- data/guides/source/3_0_release_notes.md +8 -8
- data/guides/source/3_1_release_notes.md +5 -2
- data/guides/source/3_2_release_notes.md +6 -3
- data/guides/source/4_0_release_notes.md +6 -3
- data/guides/source/4_1_release_notes.md +10 -11
- data/guides/source/4_2_release_notes.md +850 -0
- data/guides/source/_license.html.erb +1 -1
- data/guides/source/_welcome.html.erb +2 -8
- data/guides/source/action_controller_overview.md +84 -10
- data/guides/source/action_mailer_basics.md +91 -28
- data/guides/source/action_view_overview.md +140 -130
- data/guides/source/active_job_basics.md +318 -0
- data/guides/source/active_model_basics.md +371 -17
- data/guides/source/active_record_basics.md +19 -18
- data/guides/source/active_record_callbacks.md +12 -9
- data/guides/source/{migrations.md → active_record_migrations.md} +135 -226
- data/guides/source/active_record_postgresql.md +433 -0
- data/guides/source/active_record_querying.md +269 -259
- data/guides/source/active_record_validations.md +21 -12
- data/guides/source/active_support_core_extensions.md +113 -73
- data/guides/source/active_support_instrumentation.md +10 -7
- data/guides/source/api_documentation_guidelines.md +62 -16
- data/guides/source/asset_pipeline.md +264 -67
- data/guides/source/association_basics.md +81 -74
- data/guides/source/caching_with_rails.md +32 -7
- data/guides/source/command_line.md +52 -30
- data/guides/source/configuring.md +132 -29
- data/guides/source/constant_autoloading_and_reloading.md +1297 -0
- data/guides/source/contributing_to_ruby_on_rails.md +192 -112
- data/guides/source/credits.html.erb +2 -2
- data/guides/source/debugging_rails_applications.md +448 -294
- data/guides/source/development_dependencies_install.md +47 -36
- data/guides/source/documents.yaml +19 -7
- data/guides/source/engines.md +210 -189
- data/guides/source/form_helpers.md +79 -56
- data/guides/source/generators.md +24 -11
- data/guides/source/getting_started.md +339 -201
- data/guides/source/i18n.md +111 -68
- data/guides/source/index.html.erb +1 -0
- data/guides/source/initialization.md +109 -62
- data/guides/source/layout.html.erb +1 -4
- data/guides/source/layouts_and_rendering.md +18 -17
- data/guides/source/maintenance_policy.md +26 -4
- data/guides/source/nested_model_forms.md +7 -4
- data/guides/source/plugins.md +27 -27
- data/guides/source/rails_application_templates.md +21 -3
- data/guides/source/rails_on_rack.md +12 -9
- data/guides/source/routing.md +100 -74
- data/guides/source/ruby_on_rails_guides_guidelines.md +11 -12
- data/guides/source/security.md +40 -34
- data/guides/source/testing.md +188 -117
- data/guides/source/upgrading_ruby_on_rails.md +284 -29
- data/guides/source/working_with_javascript_in_rails.md +18 -16
- data/guides/w3c_validator.rb +2 -0
- metadata +40 -94
- data/guides/code/getting_started/Gemfile +0 -40
- data/guides/code/getting_started/Gemfile.lock +0 -125
- data/guides/code/getting_started/README.rdoc +0 -28
- data/guides/code/getting_started/Rakefile +0 -6
- data/guides/code/getting_started/app/assets/javascripts/application.js +0 -15
- data/guides/code/getting_started/app/assets/javascripts/comments.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/posts.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/javascripts/welcome.js.coffee +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/application.css +0 -13
- data/guides/code/getting_started/app/assets/stylesheets/comments.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/posts.css.scss +0 -3
- data/guides/code/getting_started/app/assets/stylesheets/welcome.css.scss +0 -3
- data/guides/code/getting_started/app/controllers/application_controller.rb +0 -5
- data/guides/code/getting_started/app/controllers/comments_controller.rb +0 -23
- data/guides/code/getting_started/app/controllers/posts_controller.rb +0 -53
- data/guides/code/getting_started/app/controllers/welcome_controller.rb +0 -4
- data/guides/code/getting_started/app/helpers/application_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/comments_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/posts_helper.rb +0 -2
- data/guides/code/getting_started/app/helpers/welcome_helper.rb +0 -2
- data/guides/code/getting_started/app/models/comment.rb +0 -3
- data/guides/code/getting_started/app/models/post.rb +0 -7
- data/guides/code/getting_started/app/views/comments/_comment.html.erb +0 -15
- data/guides/code/getting_started/app/views/comments/_form.html.erb +0 -13
- data/guides/code/getting_started/app/views/layouts/application.html.erb +0 -14
- data/guides/code/getting_started/app/views/posts/_form.html.erb +0 -27
- data/guides/code/getting_started/app/views/posts/edit.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/index.html.erb +0 -21
- data/guides/code/getting_started/app/views/posts/new.html.erb +0 -5
- data/guides/code/getting_started/app/views/posts/show.html.erb +0 -18
- data/guides/code/getting_started/app/views/welcome/index.html.erb +0 -4
- data/guides/code/getting_started/bin/bundle +0 -4
- data/guides/code/getting_started/bin/rails +0 -4
- data/guides/code/getting_started/bin/rake +0 -4
- data/guides/code/getting_started/config/application.rb +0 -18
- data/guides/code/getting_started/config/boot.rb +0 -4
- data/guides/code/getting_started/config/database.yml +0 -25
- data/guides/code/getting_started/config/environment.rb +0 -5
- data/guides/code/getting_started/config/environments/development.rb +0 -30
- data/guides/code/getting_started/config/environments/production.rb +0 -80
- data/guides/code/getting_started/config/environments/test.rb +0 -36
- data/guides/code/getting_started/config/initializers/backtrace_silencers.rb +0 -7
- data/guides/code/getting_started/config/initializers/filter_parameter_logging.rb +0 -4
- data/guides/code/getting_started/config/initializers/inflections.rb +0 -16
- data/guides/code/getting_started/config/initializers/locale.rb +0 -9
- data/guides/code/getting_started/config/initializers/mime_types.rb +0 -5
- data/guides/code/getting_started/config/initializers/secret_token.rb +0 -12
- data/guides/code/getting_started/config/initializers/session_store.rb +0 -3
- data/guides/code/getting_started/config/initializers/wrap_parameters.rb +0 -14
- data/guides/code/getting_started/config/locales/en.yml +0 -23
- data/guides/code/getting_started/config/routes.rb +0 -7
- data/guides/code/getting_started/config.ru +0 -4
- data/guides/code/getting_started/db/migrate/20130122042648_create_posts.rb +0 -10
- data/guides/code/getting_started/db/migrate/20130122045842_create_comments.rb +0 -11
- data/guides/code/getting_started/db/schema.rb +0 -33
- data/guides/code/getting_started/db/seeds.rb +0 -7
- data/guides/code/getting_started/public/404.html +0 -60
- data/guides/code/getting_started/public/422.html +0 -60
- data/guides/code/getting_started/public/500.html +0 -59
- data/guides/code/getting_started/public/favicon.ico +0 -0
- data/guides/code/getting_started/public/robots.txt +0 -5
- data/guides/code/getting_started/test/controllers/comments_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/posts_controller_test.rb +0 -7
- data/guides/code/getting_started/test/controllers/welcome_controller_test.rb +0 -9
- data/guides/code/getting_started/test/fixtures/comments.yml +0 -11
- data/guides/code/getting_started/test/fixtures/posts.yml +0 -9
- data/guides/code/getting_started/test/helpers/comments_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/posts_helper_test.rb +0 -4
- data/guides/code/getting_started/test/helpers/welcome_helper_test.rb +0 -4
- data/guides/code/getting_started/test/models/comment_test.rb +0 -7
- data/guides/code/getting_started/test/models/post_test.rb +0 -7
- data/guides/code/getting_started/test/test_helper.rb +0 -12
@@ -56,11 +56,11 @@ the comment operator on that line to later enable the asset pipeline:
|
|
56
56
|
|
57
57
|
To set asset compression methods, set the appropriate configuration options
|
58
58
|
in `production.rb` - `config.assets.css_compressor` for your CSS and
|
59
|
-
`config.assets.js_compressor` for your
|
59
|
+
`config.assets.js_compressor` for your JavaScript:
|
60
60
|
|
61
61
|
```ruby
|
62
62
|
config.assets.css_compressor = :yui
|
63
|
-
config.assets.js_compressor = :
|
63
|
+
config.assets.js_compressor = :uglifier
|
64
64
|
```
|
65
65
|
|
66
66
|
NOTE: The `sass-rails` gem is automatically used for CSS compression if included
|
@@ -124,19 +124,22 @@ with a built-in helper. In the source the generated code looked like this:
|
|
124
124
|
The query string strategy has several disadvantages:
|
125
125
|
|
126
126
|
1. **Not all caches will reliably cache content where the filename only differs by
|
127
|
-
query parameters
|
127
|
+
query parameters**
|
128
|
+
|
128
129
|
[Steve Souders recommends](http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/),
|
129
130
|
"...avoiding a querystring for cacheable resources". He found that in this
|
130
131
|
case 5-20% of requests will not be cached. Query strings in particular do not
|
131
132
|
work at all with some CDNs for cache invalidation.
|
132
133
|
|
133
|
-
2. **The file name can change between nodes in multi-server environments
|
134
|
+
2. **The file name can change between nodes in multi-server environments.**
|
135
|
+
|
134
136
|
The default query string in Rails 2.x is based on the modification time of
|
135
137
|
the files. When assets are deployed to a cluster, there is no guarantee that the
|
136
138
|
timestamps will be the same, resulting in different values being used depending
|
137
139
|
on which server handles the request.
|
138
140
|
|
139
|
-
3. **Too much cache invalidation
|
141
|
+
3. **Too much cache invalidation**
|
142
|
+
|
140
143
|
When static assets are deployed with each new release of code, the mtime
|
141
144
|
(time of last modification) of _all_ these files changes, forcing all remote
|
142
145
|
clients to fetch them again, even when the content of those assets has not changed.
|
@@ -163,9 +166,9 @@ pipeline, the preferred location for these assets is now the `app/assets`
|
|
163
166
|
directory. Files in this directory are served by the Sprockets middleware.
|
164
167
|
|
165
168
|
Assets can still be placed in the `public` hierarchy. Any assets under `public`
|
166
|
-
will be served as static files by the application or web server
|
167
|
-
`
|
168
|
-
served.
|
169
|
+
will be served as static files by the application or web server when
|
170
|
+
`config.serve_static_files` is set to true. You should use `app/assets` for
|
171
|
+
files that must undergo some pre-processing before they are served.
|
169
172
|
|
170
173
|
In production, Rails precompiles these files to `public/assets` by default. The
|
171
174
|
precompiled copies are then served as static assets by the web server. The files
|
@@ -198,18 +201,13 @@ will result in your assets being included more than once.
|
|
198
201
|
|
199
202
|
WARNING: When using asset precompilation, you will need to ensure that your
|
200
203
|
controller assets will be precompiled when loading them on a per page basis. By
|
201
|
-
default .coffee and .scss files will not be precompiled on their own.
|
202
|
-
|
203
|
-
|
204
|
-
production, however, you will see 500 errors since live compilation is turned
|
205
|
-
off by default. See [Precompiling Assets](#precompiling-assets) for more
|
206
|
-
information on how precompiling works.
|
204
|
+
default .coffee and .scss files will not be precompiled on their own. See
|
205
|
+
[Precompiling Assets](#precompiling-assets) for more information on how
|
206
|
+
precompiling works.
|
207
207
|
|
208
208
|
NOTE: You must have an ExecJS supported runtime in order to use CoffeeScript.
|
209
209
|
If you are using Mac OS X or Windows, you have a JavaScript runtime installed in
|
210
|
-
your operating system. Check
|
211
|
-
[ExecJS](https://github.com/sstephenson/execjs#readme) documentation to know all
|
212
|
-
supported JavaScript runtimes.
|
210
|
+
your operating system. Check [ExecJS](https://github.com/sstephenson/execjs#readme) documentation to know all supported JavaScript runtimes.
|
213
211
|
|
214
212
|
You can also disable generation of controller specific asset files by adding the
|
215
213
|
following to your `config/application.rb` configuration:
|
@@ -232,7 +230,9 @@ images, JavaScript files or stylesheets.
|
|
232
230
|
scope of the application or those libraries which are shared across applications.
|
233
231
|
|
234
232
|
* `vendor/assets` is for assets that are owned by outside entities, such as
|
235
|
-
code for JavaScript plugins and CSS frameworks.
|
233
|
+
code for JavaScript plugins and CSS frameworks. Keep in mind that third party
|
234
|
+
code with references to other files also processed by the asset Pipeline (images,
|
235
|
+
stylesheets, etc.), will need to be rewritten to use helpers like `asset_path`.
|
236
236
|
|
237
237
|
WARNING: If you are upgrading from Rails 3, please take into account that assets
|
238
238
|
under `lib/assets` or `vendor/assets` are available for inclusion via the
|
@@ -302,7 +302,7 @@ Sprockets uses files named `index` (with the relevant extensions) for a special
|
|
302
302
|
purpose.
|
303
303
|
|
304
304
|
For example, if you have a jQuery library with many modules, which is stored in
|
305
|
-
`lib/assets/library_name`, the file `lib/assets/library_name/index.js` serves as
|
305
|
+
`lib/assets/javascripts/library_name`, the file `lib/assets/javascripts/library_name/index.js` serves as
|
306
306
|
the manifest for all files in this library. This file could include a list of
|
307
307
|
all the required files in order, or a simple `require_tree` directive.
|
308
308
|
|
@@ -493,14 +493,13 @@ The directives that work in JavaScript files also work in stylesheets
|
|
493
493
|
one, requiring all stylesheets from the current directory.
|
494
494
|
|
495
495
|
In this example, `require_self` is used. This puts the CSS contained within the
|
496
|
-
file (if any) at the precise location of the `require_self` call.
|
497
|
-
`require_self` is called more than once, only the last call is respected.
|
496
|
+
file (if any) at the precise location of the `require_self` call.
|
498
497
|
|
499
498
|
NOTE. If you want to use multiple Sass files, you should generally use the [Sass `@import` rule](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#import)
|
500
|
-
instead of these Sprockets directives.
|
499
|
+
instead of these Sprockets directives. When using Sprockets directives, Sass files exist within
|
501
500
|
their own scope, making variables or mixins only available within the document they were defined in.
|
502
|
-
|
503
|
-
equivalent to how `require_tree` works. Check the [sass-rails documentation](https://github.com/rails/sass-rails#features) for more info and important caveats.
|
501
|
+
|
502
|
+
You can do file globbing as well using `@import "*"`, and `@import "**/*"` to add the whole tree which is equivalent to how `require_tree` works. Check the [sass-rails documentation](https://github.com/rails/sass-rails#features) for more info and important caveats.
|
504
503
|
|
505
504
|
You can have as many manifest files as you need. For example, the `admin.css`
|
506
505
|
and `admin.js` manifest could contain the JS and CSS files that are used for the
|
@@ -581,23 +580,21 @@ runtime. To disable this behavior you can set:
|
|
581
580
|
config.assets.raise_runtime_errors = false
|
582
581
|
```
|
583
582
|
|
584
|
-
When
|
583
|
+
When this option is true, the asset pipeline will check if all the assets loaded
|
584
|
+
in your application are included in the `config.assets.precompile` list.
|
585
|
+
If `config.assets.digest` is also true, the asset pipeline will require that
|
586
|
+
all requests for assets include digests.
|
585
587
|
|
586
|
-
|
588
|
+
### Turning Digests Off
|
587
589
|
|
588
|
-
|
589
|
-
|
590
|
-
```
|
591
|
-
|
592
|
-
Then you must declare that `logo.png` is a dependency of `application.css.erb`, so when the image gets re-compiled, the css file does as well. You can do this using the `//= depend_on_asset` declaration:
|
590
|
+
You can turn off digests by updating `config/environments/development.rb` to
|
591
|
+
include:
|
593
592
|
|
594
|
-
```
|
595
|
-
|
596
|
-
#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
|
593
|
+
```ruby
|
594
|
+
config.assets.digest = false
|
597
595
|
```
|
598
596
|
|
599
|
-
|
600
|
-
|
597
|
+
When this option is true, digests will be generated for asset URLs.
|
601
598
|
|
602
599
|
### Turning Debugging Off
|
603
600
|
|
@@ -714,7 +711,7 @@ The default matcher for compiling files includes `application.js`,
|
|
714
711
|
automatically) from `app/assets` folders including your gems:
|
715
712
|
|
716
713
|
```ruby
|
717
|
-
[ Proc.new { |
|
714
|
+
[ Proc.new { |filename, path| path =~ /app\/assets/ && !%w(.js .css).include?(File.extname(filename)) },
|
718
715
|
/application.(css|js)$/ ]
|
719
716
|
```
|
720
717
|
|
@@ -739,10 +736,10 @@ Rails.application.config.assets.precompile << Proc.new do |path|
|
|
739
736
|
full_path = Rails.application.assets.resolve(path).to_path
|
740
737
|
app_assets_path = Rails.root.join('app', 'assets').to_path
|
741
738
|
if full_path.starts_with? app_assets_path
|
742
|
-
|
739
|
+
logger.info "including asset: " + full_path
|
743
740
|
true
|
744
741
|
else
|
745
|
-
|
742
|
+
logger.info "excluding asset: " + full_path
|
746
743
|
false
|
747
744
|
end
|
748
745
|
else
|
@@ -765,7 +762,7 @@ typical manifest file looks like:
|
|
765
762
|
"digest":"12b3c7dd74d2e9df37e7cbb1efa76a6d"},"application-1c5752789588ac18d7e1a50b1f0fd4c2.css":{"logical_path":"application.css","mtime":"2013-07-26T22:56:17-07:00","size":1591,
|
766
763
|
"digest":"1c5752789588ac18d7e1a50b1f0fd4c2"},"favicon-a9c641bf2b81f0476e876f7c5e375969.ico":{"logical_path":"favicon.ico","mtime":"2013-07-26T23:00:10-07:00","size":1406,
|
767
764
|
"digest":"a9c641bf2b81f0476e876f7c5e375969"},"my_image-231a680f23887d9dd70710ea5efd3c62.png":{"logical_path":"my_image.png","mtime":"2013-07-26T23:00:27-07:00","size":6646,
|
768
|
-
"digest":"231a680f23887d9dd70710ea5efd3c62"}},"assets"{"application.js":
|
765
|
+
"digest":"231a680f23887d9dd70710ea5efd3c62"}},"assets":{"application.js":
|
769
766
|
"application-723d1be6cc741a3aabb1cec24276d681.js","application.css":
|
770
767
|
"application-1c5752789588ac18d7e1a50b1f0fd4c2.css",
|
771
768
|
"favicon.ico":"favicona9c641bf2b81f0476e876f7c5e375969.ico","my_image.png":
|
@@ -781,7 +778,7 @@ exception indicating the name of the missing file(s).
|
|
781
778
|
|
782
779
|
#### Far-future Expires Header
|
783
780
|
|
784
|
-
Precompiled assets exist on the
|
781
|
+
Precompiled assets exist on the file system and are served directly by your web
|
785
782
|
server. They do not have far-future headers by default, so to get the benefit of
|
786
783
|
fingerprinting you'll have to update your server configuration to add those
|
787
784
|
headers.
|
@@ -793,13 +790,15 @@ For Apache:
|
|
793
790
|
# `mod_expires` to be enabled.
|
794
791
|
<Location /assets/>
|
795
792
|
# Use of ETag is discouraged when Last-Modified is present
|
796
|
-
Header unset ETag
|
793
|
+
Header unset ETag
|
794
|
+
FileETag None
|
797
795
|
# RFC says only cache for 1 year
|
798
|
-
ExpiresActive On
|
796
|
+
ExpiresActive On
|
797
|
+
ExpiresDefault "access plus 1 year"
|
799
798
|
</Location>
|
800
799
|
```
|
801
800
|
|
802
|
-
For
|
801
|
+
For NGINX:
|
803
802
|
|
804
803
|
```nginx
|
805
804
|
location ~ ^/assets/ {
|
@@ -821,7 +820,7 @@ compression ratio, thus reducing the size of the data transfer to the minimum.
|
|
821
820
|
On the other hand, web servers can be configured to serve compressed content
|
822
821
|
directly from disk, rather than deflating non-compressed files themselves.
|
823
822
|
|
824
|
-
|
823
|
+
NGINX is able to do this automatically enabling `gzip_static`:
|
825
824
|
|
826
825
|
```nginx
|
827
826
|
location ~ ^/(assets)/ {
|
@@ -840,7 +839,7 @@ the module compiled. Otherwise, you may need to perform a manual compilation:
|
|
840
839
|
./configure --with-http_gzip_static_module
|
841
840
|
```
|
842
841
|
|
843
|
-
If you're compiling
|
842
|
+
If you're compiling NGINX with Phusion Passenger you'll need to pass that option
|
844
843
|
when prompted.
|
845
844
|
|
846
845
|
A robust configuration for Apache is possible but tricky; please Google around.
|
@@ -859,10 +858,12 @@ duplication of work.
|
|
859
858
|
Local compilation allows you to commit the compiled files into source control,
|
860
859
|
and deploy as normal.
|
861
860
|
|
862
|
-
There are
|
861
|
+
There are three caveats:
|
863
862
|
|
864
863
|
* You must not run the Capistrano deployment task that precompiles assets.
|
865
|
-
* You must
|
864
|
+
* You must ensure any necessary compressors or minifiers are
|
865
|
+
available on your development system.
|
866
|
+
* You must change the following application configuration setting:
|
866
867
|
|
867
868
|
In `config/environments/development.rb`, place the following line:
|
868
869
|
|
@@ -876,9 +877,6 @@ development mode, and pass all requests to Sprockets. The prefix is still set to
|
|
876
877
|
would serve the precompiled assets from `/assets` in development, and you would
|
877
878
|
not see any local changes until you compile assets again.
|
878
879
|
|
879
|
-
You will also need to ensure any necessary compressors or minifiers are
|
880
|
-
available on your development system.
|
881
|
-
|
882
880
|
In practice, this will allow you to precompile locally, have those files in your
|
883
881
|
working tree, and commit those files to source control when needed. Development
|
884
882
|
mode will work as expected.
|
@@ -918,15 +916,206 @@ end
|
|
918
916
|
|
919
917
|
### CDNs
|
920
918
|
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
919
|
+
CDN stands for [Content Delivery
|
920
|
+
Network](http://en.wikipedia.org/wiki/Content_delivery_network), they are
|
921
|
+
primarily designed to cache assets all over the world so that when a browser
|
922
|
+
requests the asset, a cached copy will be geographically close to that browser.
|
923
|
+
If you are serving assets directly from your Rails server in production, the
|
924
|
+
best practice is to use a CDN in front of your application.
|
925
|
+
|
926
|
+
A common pattern for using a CDN is to set your production application as the
|
927
|
+
"origin" server. This means when a browser requests an asset from the CDN and
|
928
|
+
there is a cache miss, it will grab the file from your server on the fly and
|
929
|
+
then cache it. For example if you are running a Rails application on
|
930
|
+
`example.com` and have a CDN configured at `mycdnsubdomain.fictional-cdn.com`,
|
931
|
+
then when a request is made to `mycdnsubdomain.fictional-
|
932
|
+
cdn.com/assets/smile.png`, the CDN will query your server once at
|
933
|
+
`example.com/assets/smile.png` and cache the request. The next request to the
|
934
|
+
CDN that comes in to the same URL will hit the cached copy. When the CDN can
|
935
|
+
serve an asset directly the request never touches your Rails server. Since the
|
936
|
+
assets from a CDN are geographically closer to the browser, the request is
|
937
|
+
faster, and since your server doesn't need to spend time serving assets, it can
|
938
|
+
focus on serving application code as fast as possible.
|
939
|
+
|
940
|
+
#### Set up a CDN to Serve Static Assets
|
941
|
+
|
942
|
+
To set up your CDN you have to have your application running in production on
|
943
|
+
the internet at a publically available URL, for example `example.com`. Next
|
944
|
+
you'll need to sign up for a CDN service from a cloud hosting provider. When you
|
945
|
+
do this you need to configure the "origin" of the CDN to point back at your
|
946
|
+
website `example.com`, check your provider for documentation on configuring the
|
947
|
+
origin server.
|
948
|
+
|
949
|
+
The CDN you provisioned should give you a custom subdomain for your application
|
950
|
+
such as `mycdnsubdomain.fictional-cdn.com` (note fictional-cdn.com is not a
|
951
|
+
valid CDN provider at the time of this writing). Now that you have configured
|
952
|
+
your CDN server, you need to tell browsers to use your CDN to grab assets
|
953
|
+
instead of your Rails server directly. You can do this by configuring Rails to
|
954
|
+
set your CDN as the asset host instead of using a relative path. To set your
|
955
|
+
asset host in Rails, you need to set `config.action_controller.asset_host` in
|
956
|
+
`config/production.rb`:
|
957
|
+
|
958
|
+
```ruby
|
959
|
+
config.action_controller.asset_host = 'mycdnsubdomain.fictional-cdn.com'
|
960
|
+
```
|
961
|
+
|
962
|
+
NOTE: You only need to provide the "host", this is the subdomain and root
|
963
|
+
domain, you do not need to specify a protocol or "scheme" such as `http://` or
|
964
|
+
`https://`. When a web page is requested, the protocol in the link to your asset
|
965
|
+
that is generated will match how the webpage is accessed by default.
|
966
|
+
|
967
|
+
You can also set this value through an [environment
|
968
|
+
variable](http://en.wikipedia.org/wiki/Environment_variable) to make running a
|
969
|
+
staging copy of your site easier:
|
970
|
+
|
971
|
+
```
|
972
|
+
config.action_controller.asset_host = ENV['CDN_HOST']
|
973
|
+
```
|
974
|
+
|
975
|
+
|
925
976
|
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
you
|
977
|
+
Note: You would need to set `CDN_HOST` on your server to `mycdnsubdomain
|
978
|
+
.fictional-cdn.com` for this to work.
|
979
|
+
|
980
|
+
Once you have configured your server and your CDN when you serve a webpage that
|
981
|
+
has an asset:
|
982
|
+
|
983
|
+
```erb
|
984
|
+
<%= asset_path('smile.png') %>
|
985
|
+
```
|
986
|
+
|
987
|
+
Instead of returning a path such as `/assets/smile.png` (digests are left out
|
988
|
+
for readability). The URL generated will have the full path to your CDN.
|
989
|
+
|
990
|
+
```
|
991
|
+
http://mycdnsubdomain.fictional-cdn.com/assets/smile.png
|
992
|
+
```
|
993
|
+
|
994
|
+
If the CDN has a copy of `smile.png` it will serve it to the browser and your
|
995
|
+
server doesn't even know it was requested. If the CDN does not have a copy it
|
996
|
+
will try to find it a the "origin" `example.com/assets/smile.png` and then store
|
997
|
+
it for future use.
|
998
|
+
|
999
|
+
If you want to serve only some assets from your CDN, you can use custom `:host`
|
1000
|
+
option your asset helper, which overwrites value set in
|
1001
|
+
`config.action_controller.asset_host`.
|
1002
|
+
|
1003
|
+
```erb
|
1004
|
+
<%= asset_path 'image.png', host: 'mycdnsubdomain.fictional-cdn.com' %>
|
1005
|
+
```
|
1006
|
+
|
1007
|
+
#### Customize CDN Caching Behavior
|
1008
|
+
|
1009
|
+
A CDN works by caching content. If the CDN has stale or bad content, then it is
|
1010
|
+
hurting rather than helping your application. The purpose of this section is to
|
1011
|
+
describe general caching behavior of most CDNs, your specific provider may
|
1012
|
+
behave slightly differently.
|
1013
|
+
|
1014
|
+
##### CDN Request Caching
|
1015
|
+
|
1016
|
+
While a CDN is described as being good for caching assets, in reality caches the
|
1017
|
+
entire request. This includes the body of the asset as well as any headers. The
|
1018
|
+
most important one being `Cache-Control` which tells the CDN (and web browsers)
|
1019
|
+
how to cache contents. This means that if someone requests an asset that does
|
1020
|
+
not exist `/assets/i-dont-exist.png` and your Rails application returns a 404,
|
1021
|
+
then your CDN will likely cache the 404 page if a valid `Cache-Control` header
|
1022
|
+
is present.
|
1023
|
+
|
1024
|
+
##### CDN Header Debugging
|
1025
|
+
|
1026
|
+
One way to check the headers are cached properly in your CDN is by using [curl](
|
1027
|
+
http://explainshell.com/explain?cmd=curl+-I+http%3A%2F%2Fwww.example.com). You
|
1028
|
+
can request the headers from both your server and your CDN to verify they are
|
1029
|
+
the same:
|
1030
|
+
|
1031
|
+
```
|
1032
|
+
$ curl -I http://www.example/assets/application-
|
1033
|
+
d0e099e021c95eb0de3615fd1d8c4d83.css
|
1034
|
+
HTTP/1.1 200 OK
|
1035
|
+
Server: Cowboy
|
1036
|
+
Date: Sun, 24 Aug 2014 20:27:50 GMT
|
1037
|
+
Connection: keep-alive
|
1038
|
+
Last-Modified: Thu, 08 May 2014 01:24:14 GMT
|
1039
|
+
Content-Type: text/css
|
1040
|
+
Cache-Control: public, max-age=2592000
|
1041
|
+
Content-Length: 126560
|
1042
|
+
Via: 1.1 vegur
|
1043
|
+
```
|
1044
|
+
|
1045
|
+
Versus the CDN copy.
|
1046
|
+
|
1047
|
+
```
|
1048
|
+
$ curl -I http://mycdnsubdomain.fictional-cdn.com/application-
|
1049
|
+
d0e099e021c95eb0de3615fd1d8c4d83.css
|
1050
|
+
HTTP/1.1 200 OK Server: Cowboy Last-
|
1051
|
+
Modified: Thu, 08 May 2014 01:24:14 GMT Content-Type: text/css
|
1052
|
+
Cache-Control:
|
1053
|
+
public, max-age=2592000
|
1054
|
+
Via: 1.1 vegur
|
1055
|
+
Content-Length: 126560
|
1056
|
+
Accept-Ranges:
|
1057
|
+
bytes
|
1058
|
+
Date: Sun, 24 Aug 2014 20:28:45 GMT
|
1059
|
+
Via: 1.1 varnish
|
1060
|
+
Age: 885814
|
1061
|
+
Connection: keep-alive
|
1062
|
+
X-Served-By: cache-dfw1828-DFW
|
1063
|
+
X-Cache: HIT
|
1064
|
+
X-Cache-Hits:
|
1065
|
+
68
|
1066
|
+
X-Timer: S1408912125.211638212,VS0,VE0
|
1067
|
+
```
|
1068
|
+
|
1069
|
+
Check your CDN documentation for any additional information they may provide
|
1070
|
+
such as `X-Cache` or for any additional headers they may add.
|
1071
|
+
|
1072
|
+
##### CDNs and the Cache-Control Header
|
1073
|
+
|
1074
|
+
The [cache control
|
1075
|
+
header](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) is a W3C
|
1076
|
+
specification that describes how a request can be cached. When no CDN is used, a
|
1077
|
+
browser will use this information to cache contents. This is very helpful for
|
1078
|
+
assets that are not modified so that a browser does not need to re-download a
|
1079
|
+
website's CSS or javascript on every request. Generally we want our Rails server
|
1080
|
+
to tell our CDN (and browser) that the asset is "public", that means any cache
|
1081
|
+
can store the request. Also we commonly want to set `max-age` which is how long
|
1082
|
+
the cache will store the object before invalidating the cache. The `max-age`
|
1083
|
+
value is set to seconds with a maximum possible value of `31536000` which is one
|
1084
|
+
year. You can do this in your rails application by setting
|
1085
|
+
|
1086
|
+
```
|
1087
|
+
config.static_cache_control = "public, max-age=31536000"
|
1088
|
+
```
|
1089
|
+
|
1090
|
+
Now when your application serves an asset in production, the CDN will store the
|
1091
|
+
asset for up to a year. Since most CDNs also cache headers of the request, this
|
1092
|
+
`Cache-Control` will be passed along to all future browsers seeking this asset,
|
1093
|
+
the browser then knows that it can store this asset for a very long time before
|
1094
|
+
needing to re-request it.
|
1095
|
+
|
1096
|
+
##### CDNs and URL based Cache Invalidation
|
1097
|
+
|
1098
|
+
Most CDNs will cache contents of an asset based on the complete URL. This means
|
1099
|
+
that a request to
|
1100
|
+
|
1101
|
+
```
|
1102
|
+
http://mycdnsubdomain.fictional-cdn.com/assets/smile-123.png
|
1103
|
+
```
|
1104
|
+
|
1105
|
+
Will be a completely different cache from
|
1106
|
+
|
1107
|
+
```
|
1108
|
+
http://mycdnsubdomain.fictional-cdn.com/assets/smile.png
|
1109
|
+
```
|
1110
|
+
|
1111
|
+
If you want to set far future `max-age` in your `Cache-Control` (and you do),
|
1112
|
+
then make sure when you change your assets that your cache is invalidated. For
|
1113
|
+
example when changing the smiley face in an image from yellow to blue, you want
|
1114
|
+
all visitors of your site to get the new blue face. When using a CDN with the
|
1115
|
+
Rails asset pipeline `config.assets.digest` is set to true by default so that
|
1116
|
+
each asset will have a different file name when it is changed. This way you
|
1117
|
+
don't have to ever manually invalidate any items in your cache. By using a
|
1118
|
+
different unique asset name instead, your users get the latest asset.
|
930
1119
|
|
931
1120
|
Customizing the Pipeline
|
932
1121
|
------------------------
|
@@ -943,7 +1132,7 @@ gem.
|
|
943
1132
|
```ruby
|
944
1133
|
config.assets.css_compressor = :yui
|
945
1134
|
```
|
946
|
-
The other option for compressing CSS if you have the sass-rails gem installed is
|
1135
|
+
The other option for compressing CSS if you have the sass-rails gem installed is
|
947
1136
|
|
948
1137
|
```ruby
|
949
1138
|
config.assets.css_compressor = :sass
|
@@ -1018,15 +1207,15 @@ The X-Sendfile header is a directive to the web server to ignore the response
|
|
1018
1207
|
from the application, and instead serve a specified file from disk. This option
|
1019
1208
|
is off by default, but can be enabled if your server supports it. When enabled,
|
1020
1209
|
this passes responsibility for serving the file to the web server, which is
|
1021
|
-
faster. Have a look at [send_file](http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_file)
|
1210
|
+
faster. Have a look at [send_file](http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_file)
|
1022
1211
|
on how to use this feature.
|
1023
1212
|
|
1024
|
-
Apache and
|
1213
|
+
Apache and NGINX support this option, which can be enabled in
|
1025
1214
|
`config/environments/production.rb`:
|
1026
1215
|
|
1027
1216
|
```ruby
|
1028
|
-
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for
|
1029
|
-
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for
|
1217
|
+
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
|
1218
|
+
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
|
1030
1219
|
```
|
1031
1220
|
|
1032
1221
|
WARNING: If you are upgrading an existing application and intend to use this
|
@@ -1036,7 +1225,7 @@ and any other environments you define with production behavior (not
|
|
1036
1225
|
|
1037
1226
|
TIP: For further details have a look at the docs of your production web server:
|
1038
1227
|
- [Apache](https://tn123.org/mod_xsendfile/)
|
1039
|
-
- [
|
1228
|
+
- [NGINX](http://wiki.nginx.org/XSendfile)
|
1040
1229
|
|
1041
1230
|
Assets Cache Store
|
1042
1231
|
------------------
|
@@ -1056,6 +1245,14 @@ cache store.
|
|
1056
1245
|
config.assets.cache_store = :memory_store, { size: 32.megabytes }
|
1057
1246
|
```
|
1058
1247
|
|
1248
|
+
To disable the assets cache store:
|
1249
|
+
|
1250
|
+
```ruby
|
1251
|
+
config.assets.configure do |env|
|
1252
|
+
env.cache = ActiveSupport::Cache.lookup_store(:null_store)
|
1253
|
+
end
|
1254
|
+
```
|
1255
|
+
|
1059
1256
|
Adding Assets to Your Gems
|
1060
1257
|
--------------------------
|
1061
1258
|
|
@@ -1151,8 +1348,8 @@ config.assets.digest = true
|
|
1151
1348
|
|
1152
1349
|
Rails 4 no longer sets default config values for Sprockets in `test.rb`, so
|
1153
1350
|
`test.rb` now requires Sprockets configuration. The old defaults in the test
|
1154
|
-
environment are: `config.assets.compile = true`, `config.assets.compress =
|
1155
|
-
|
1351
|
+
environment are: `config.assets.compile = true`, `config.assets.compress = false`,
|
1352
|
+
`config.assets.debug = false` and `config.assets.digest = false`.
|
1156
1353
|
|
1157
1354
|
The following should also be added to `Gemfile`:
|
1158
1355
|
|