diff options
Diffstat (limited to 'guides/source')
-rw-r--r-- | guides/source/2_3_release_notes.md | 2 | ||||
-rw-r--r-- | guides/source/5_0_release_notes.md | 71 | ||||
-rw-r--r-- | guides/source/action_cable_overview.md | 324 | ||||
-rw-r--r-- | guides/source/active_support_core_extensions.md | 7 | ||||
-rw-r--r-- | guides/source/api_app.md | 9 | ||||
-rw-r--r-- | guides/source/api_documentation_guidelines.md | 2 | ||||
-rw-r--r-- | guides/source/asset_pipeline.md | 17 | ||||
-rw-r--r-- | guides/source/caching_with_rails.md | 6 | ||||
-rw-r--r-- | guides/source/configuring.md | 75 | ||||
-rw-r--r-- | guides/source/documents.yaml | 4 | ||||
-rw-r--r-- | guides/source/security.md | 36 | ||||
-rw-r--r-- | guides/source/testing.md | 2 | ||||
-rw-r--r-- | guides/source/upgrading_ruby_on_rails.md | 2 |
13 files changed, 335 insertions, 222 deletions
diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 2776bc4e6d..06761b67bb 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -614,7 +614,7 @@ A few pieces of older code are deprecated in this release: * Some integration test helpers have been removed. `response.headers["Status"]` and `headers["Status"]` will no longer return anything. Rack does not allow "Status" in its return headers. However you can still use the `status` and `status_message` helpers. `response.headers["cookie"]` and `headers["cookie"]` will no longer return any CGI cookies. You can inspect `headers["Set-Cookie"]` to see the raw cookie header or use the `cookies` helper to get a hash of the cookies sent to the client. * `formatted_polymorphic_url` is deprecated. Use `polymorphic_url` with `:format` instead. * The `:http_only` option in `ActionController::Response#set_cookie` has been renamed to `:httponly`. -* The `:connector` and `:skip_last_comma` options of `to_sentence` have been replaced by `:words_connnector`, `:two_words_connector`, and `:last_word_connector` options. +* The `:connector` and `:skip_last_comma` options of `to_sentence` have been replaced by `:words_connector`, `:two_words_connector`, and `:last_word_connector` options. * Posting a multipart form with an empty `file_field` control used to submit an empty string to the controller. Now it submits a nil, due to differences between Rack's multipart parser and the old Rails one. Credits diff --git a/guides/source/5_0_release_notes.md b/guides/source/5_0_release_notes.md index 2c679ba632..2583b32925 100644 --- a/guides/source/5_0_release_notes.md +++ b/guides/source/5_0_release_notes.md @@ -48,7 +48,74 @@ ToDo... ### Active Record attributes API -ToDo... +Defines an attribute with a type on a model. It will override the type of existing attributes if needed. +This allows control over how values are converted to and from SQL when assigned to a model. +It also changes the behavior of values passed to ActiveRecord::Base.where, which lets use our domain objects across much of Active Record, +without having to rely on implementation details or monkey patching. + +Some things that you can achieve with this: +* The type detected by Active Record can be overridden. +* A default can also be provided. +* Attributes do not need to be backed by a database column. + +```ruby + +# db/schema.rb +create_table :store_listings, force: true do |t| + t.decimal :price_in_cents + t.string :my_string, default: "original default" +end + +# app/models/store_listing.rb +class StoreListing < ActiveRecord::Base +end + +store_listing = StoreListing.new(price_in_cents: '10.1') + +# before +store_listing.price_in_cents # => BigDecimal.new(10.1) +StoreListing.new.my_string # => "original default" + +class StoreListing < ActiveRecord::Base + attribute :price_in_cents, :integer # custom type + attribute :my_string, :string, default: "new default" # default value + attribute :my_default_proc, :datetime, default: -> { Time.now } # default value + attribute :field_without_db_column, :integer, array: true +end + +# after +store_listing.price_in_cents # => 10 +StoreListing.new.my_string # => "new default" +StoreListing.new.my_default_proc # => 2015-05-30 11:04:48 -0600 +model = StoreListing.new(field_without_db_column: ["1", "2", "3"]) +model.attributes #=> {field_without_db_column: [1, 2, 3]} +``` + +**Creating Custom Types:** + +You can define your own custom types, as long as they respond +to the methods defined on the value type. The method +deserialize+ or ++cast+ will be called on your type object, with raw input from the +database or from your controllers. This is useful, for example, when doing custom conversion, +like Money data. + +**Querying:** + +When `ActiveRecord::Base.where` is called, it will +use the type defined by the model class to convert the value to SQL, +calling +serialize+ on your type object. + +This gives the objects ability to specify, how to convert values when performing SQL queries. + +**Dirty Tracking:** + +The type of an attribute is given the opportunity to change how dirty +tracking is performed. + +See its +[documentation](http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html) +for a detailed write up. + ### Test Runner [Pull Request](https://github.com/rails/rails/pull/19216) @@ -814,7 +881,7 @@ Please refer to the [Changelog][active-support] for detailed changes. ([commit](https://github.com/rails/rails/commit/a5e507fa0b8180c3d97458a9b86c195e9857d8f6)) * Added `Integer#positive?` and `Integer#negative?` query methods - in the vein of `Fixnum#zero?`. + in the vein of `Integer#zero?`. ([commit](https://github.com/rails/rails/commit/e54277a45da3c86fecdfa930663d7692fd083daa)) * Added a bang version to `ActiveSupport::OrderedOptions` get methods which will raise diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md index 5cc280072e..93bcb6157a 100644 --- a/guides/source/action_cable_overview.md +++ b/guides/source/action_cable_overview.md @@ -12,41 +12,39 @@ After reading this guide, you will know: Introduction ------------ -Action Cable seamlessly integrates WebSockets with the rest of your Rails application. -It allows for real-time features to be written in Ruby in the same style and form as -the rest of your Rails application, while still being performant and scalable. It's -a full-stack offering that provides both a client-side JavaScript framework and a -server-side Ruby framework. You have access to your full domain model written with -Active Record or your ORM of choice. +Action Cable seamlessly integrates +[WebSockets](https://en.wikipedia.org/wiki/WebSocket) with the rest of your +Rails application. It allows for real-time features to be written in Ruby in the +same style and form as the rest of your Rails application, while still being +performant and scalable. It's a full-stack offering that provides both a +client-side JavaScript framework and a server-side Ruby framework. You have +access to your full domain model written with Active Record or your ORM of +choice. What is Pub/Sub --------------- -Pub/Sub, or Publish-Subscribe, refers to a message queue paradigm whereby senders -of information (publishers), send data to an abstract class of recipients (subscribers), -without specifying individual recipients. Action Cable uses this approach to communicate -between the server and many clients. - -What is Action Cable --------------------- - -Action Cable is a server which can handle multiple connection instances, with one -client-server connection instance established per WebSocket connection. +[Pub/Sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern), or +Publish-Subscribe, refers to a message queue paradigm whereby senders of +information (publishers), send data to an abstract class of recipients +(subscribers), without specifying individual recipients. Action Cable uses this +approach to communicate between the server and many clients. ## Server-Side Components ### Connections -Connections form the foundation of the client-server relationship. For every WebSocket -the cable server is accepting, a Connection object will be instantiated on the server side. -This instance becomes the parent of all the channel subscriptions that are created from there on. -The Connection itself does not deal with any specific application logic beyond authentication -and authorization. The client of a WebSocket connection is called a consumer. An individual -user will create one consumer-connection pair per browser tab, window, or device they have open. +*Connections* form the foundation of the client-server relationship. For every +WebSocket accepted by the server, a connection object is instantiated. This +object becomes the parent of all the *channel subscriptions* that are created +from there on. The connection itself does not deal with any specific application +logic beyond authentication and authorization. The client of a WebSocket +connection is called the connection *consumer*. An individual user will create +one consumer-connection pair per browser tab, window, or device they have open. -Connections are instantiated via the `ApplicationCable::Connection` class in Ruby. -In this class, you authorize the incoming connection, and proceed to establish it -if the user can be identified. +Connections are instances of `ApplicationCable::Connection`. In this class, you +authorize the incoming connection, and proceed to establish it if the user can +be identified. #### Connection Setup @@ -78,17 +76,17 @@ create a delegate by the same name on any channel instances created off the conn This example relies on the fact that you will already have handled authentication of the user somewhere else in your application, and that a successful authentication sets a signed -cookie with the `user_id`. +cookie with the user ID. The cookie is then automatically sent to the connection instance when a new connection is attempted, and you use that to set the `current_user`. By identifying the connection -by this same current_user, you're also ensuring that you can later retrieve all open +by this same current user, you're also ensuring that you can later retrieve all open connections by a given user (and potentially disconnect them all if the user is deleted or deauthorized). ### Channels -A channel encapsulates a logical unit of work, similar to what a controller does in a +A *channel* encapsulates a logical unit of work, similar to what a controller does in a regular MVC setup. By default, Rails creates a parent `ApplicationCable::Channel` class for encapsulating shared logic between your channels. @@ -103,7 +101,7 @@ end ``` Then you would create your own channel classes. For example, you could have a -**ChatChannel** and an **AppearanceChannel**: +`ChatChannel` and an `AppearanceChannel`: ```ruby # app/channels/chat_channel.rb @@ -119,15 +117,15 @@ A consumer could then be subscribed to either or both of these channels. #### Subscriptions -When a consumer is subscribed to a channel, they act as a subscriber; -This connection is called a subscription. -Incoming messages are then routed to these channel subscriptions based on -an identifier sent by the cable consumer. +Consumers subscribe to channels, acting as *subscribers*. Their connection is +called a *subscription*. Produced messages are then routed to these channel +subscriptions based on an identifier sent by the cable consumer. ```ruby # app/channels/chat_channel.rb class ChatChannel < ApplicationCable::Channel - # Called when the consumer has successfully become a subscriber of this channel + # Called when the consumer has successfully + # become a subscriber of this channel. def subscribed end end @@ -138,7 +136,7 @@ end ### Connections Consumers require an instance of the connection on their side. This can be -established using the following Javascript, which is generated by default in Rails: +established using the following JavaScript, which is generated by default by Rails: #### Connect Consumer @@ -155,18 +153,13 @@ established using the following Javascript, which is generated by default in Rai }).call(this); ``` -This will ready a consumer that'll connect against /cable on your server by default. +This will ready a consumer that'll connect against `/cable` on your server by default. The connection won't be established until you've also specified at least one subscription you're interested in having. #### Subscriber -When a consumer is subscribed to a channel, they act as a subscriber. A -consumer can act as a subscriber to a given channel any number of times. -For example, a consumer could subscribe to multiple chat rooms at the same time. -(remember that a physical user may have multiple consumers, one per tab/device open to your connection). - -A consumer becomes a subscriber, by creating a subscription to a given channel: +A consumer becomes a subscriber by creating a subscription to a given channel: ```coffeescript # app/assets/javascripts/cable/subscriptions/chat.coffee @@ -179,12 +172,20 @@ App.cable.subscriptions.create { channel: "AppearanceChannel" } While this creates the subscription, the functionality needed to respond to received data will be described later on. +A consumer can act as a subscriber to a given channel any number of times. For +example, a consumer could subscribe to multiple chat rooms at the same time: + +```coffeescript +App.cable.subscriptions.create { channel: "ChatChannel", room: "1st Room" } +App.cable.subscriptions.create { channel: "ChatChannel", room: "2nd Room" } +``` + ## Client-Server Interactions ### Streams -Streams provide the mechanism by which channels route published content -(broadcasts) to its subscribers. +*Streams* provide the mechanism by which channels route published content +(broadcasts) to their subscribers. ```ruby # app/channels/chat_channel.rb @@ -208,21 +209,30 @@ class CommentsChannel < ApplicationCable::Channel end ``` -You can then broadcast to this channel using: `CommentsChannel.broadcast_to(@post, @comment)` +You can then broadcast to this channel like this: + +```ruby +CommentsChannel.broadcast_to(@post, @comment) +``` -### Broadcastings +### Broadcasting -A broadcasting is a pub/sub link where anything transmitted by a publisher +A *broadcasting* is a pub/sub link where anything transmitted by a publisher is routed directly to the channel subscribers who are streaming that named broadcasting. Each channel can be streaming zero or more broadcastings. -Broadcastings are purely an online queue and time dependent; -If a consumer is not streaming (subscribed to a given channel), they'll not -get the broadcast should they connect later. + +Broadcastings are purely an online queue and time dependent. If a consumer is +not streaming (subscribed to a given channel), they'll not get the broadcast +should they connect later. Broadcasts are called elsewhere in your Rails application: ```ruby - WebNotificationsChannel.broadcast_to current_user, title: 'New things!', body: 'All the news fit to print' +WebNotificationsChannel.broadcast_to( + current_user, + title: 'New things!', + body: 'All the news fit to print' +) ``` The `WebNotificationsChannel.broadcast_to` call places a message in the current @@ -231,14 +241,14 @@ broadcasting name for each user. For a user with an ID of 1, the broadcasting name would be `web_notifications_1`. The channel has been instructed to stream everything that arrives at -`web_notifications_1` directly to the client by invoking the `#received(data)` +`web_notifications_1` directly to the client by invoking the `received` callback. ### Subscriptions -When a consumer is subscribed to a channel, they act as a subscriber; -This connection is called a subscription. Incoming messages are then routed -to these channel subscriptions based on an identifier sent by the cable consumer. +When a consumer is subscribed to a channel, they act as a subscriber. This +connection is called a subscription. Incoming messages are then routed to +these channel subscriptions based on an identifier sent by the cable consumer. ```coffeescript # app/assets/javascripts/cable/subscriptions/chat.coffee @@ -260,10 +270,10 @@ App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" }, """ ``` -### Passing Parameters to Channel +### Passing Parameters to Channels -You can pass parameters from the client-side to the server-side when -creating a subscription. For example: +You can pass parameters from the client side to the server side when creating a +subscription. For example: ```ruby # app/channels/chat_channel.rb @@ -274,8 +284,8 @@ class ChatChannel < ApplicationCable::Channel end ``` -Pass an object as the first argument to `subscriptions.create`, and that object -will become your params hash in your cable channel. The keyword `channel` is required. +An object passed as the first argument to `subscriptions.create` becomes the +params hash in the cable channel. The keyword `channel` is required: ```coffeescript # app/assets/javascripts/cable/subscriptions/chat.coffee @@ -297,14 +307,18 @@ App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" }, ``` ```ruby -# Somewhere in your app this is called, perhaps from a NewCommentJob -ChatChannel.broadcast_to "chat_#{room}", sent_by: 'Paul', body: 'This is a cool chat app.' +# Somewhere in your app this is called, perhaps +# from a NewCommentJob. +ChatChannel.broadcast_to( + "chat_#{room}", + sent_by: 'Paul', + body: 'This is a cool chat app.' +) ``` +### Rebroadcasting a Message -### Rebroadcasting message - -A common use case is to rebroadcast a message sent by one client to any +A common use case is to *rebroadcast* a message sent by one client to any other connected clients. ```ruby @@ -315,7 +329,7 @@ class ChatChannel < ApplicationCable::Channel end def receive(data) - ChatChannel.broadcast_to "chat_#{params[:room]}", data + ChatChannel.broadcast_to("chat_#{params[:room]}", data) end end ``` @@ -333,20 +347,21 @@ The rebroadcast will be received by all connected clients, _including_ the client that sent the message. Note that params are the same as they were when you subscribed to the channel. -## Full-stack examples +## Full-Stack Examples The following setup steps are common to both examples: - 1. [Setup your connection](#connection-setup) - 2. [Setup your parent channel](#parent-channel-setup) - 3. [Connect your consumer](#connect-consumer) + 1. [Setup your connection](#connection-setup). + 2. [Setup your parent channel](#parent-channel-setup). + 3. [Connect your consumer](#connect-consumer). + +### Example 1: User Appearances -### Example 1: User appearances Here's a simple example of a channel that tracks whether a user is online or not and what page they're on. (This is useful for creating presence features like showing a green dot next to a user name if they're online). -#### Create the server-side Appearance Channel: +Create the server-side appearance channel: ```ruby # app/channels/appearance_channel.rb @@ -360,7 +375,7 @@ class AppearanceChannel < ApplicationCable::Channel end def appear(data) - current_user.appear on: data['appearing_on'] + current_user.appear(on: data['appearing_on']) end def away @@ -369,35 +384,34 @@ class AppearanceChannel < ApplicationCable::Channel end ``` -When `#subscribed` callback is invoked by the consumer, a client-side subscription -is initiated. In this case, we take that opportunity to say "the current user has -indeed appeared". That appear/disappear API could be backed by Redis, a database, -or whatever else. +When a subscription is initiated the `subscribed` callback gets fired and we +take that opportunity to say "the current user has indeed appeared". That +appear/disappear API could be backed by Redis, a database, or whatever else. -#### Create the client-side Appearance Channel subscription: +Create the client-side appearance channel subscription: ```coffeescript # app/assets/javascripts/cable/subscriptions/appearance.coffee App.cable.subscriptions.create "AppearanceChannel", - # Called when the subscription is ready for use on the server + # Called when the subscription is ready for use on the server. connected: -> @install() @appear() - # Called when the WebSocket connection is closed + # Called when the WebSocket connection is closed. disconnected: -> @uninstall() - # Called when the subscription is rejected by the server + # Called when the subscription is rejected by the server. rejected: -> @uninstall() appear: -> - # Calls `AppearanceChannel#appear(data)` on the server + # Calls `AppearanceChannel#appear(data)` on the server. @perform("appear", appearing_on: $("main").data("appearing-on")) away: -> - # Calls `AppearanceChannel#away` on the server + # Calls `AppearanceChannel#away` on the server. @perform("away") @@ -419,13 +433,33 @@ App.cable.subscriptions.create "AppearanceChannel", ``` ##### Client-Server Interaction -1. **Client** establishes a connection with the **Server** via `App.cable = ActionCable.createConsumer("ws://cable.example.com")`. [*` cable.js`*] The **Server** identified this connection instance by `current_user`. -2. **Client** initiates a subscription to the `Appearance Channel` for their connection via `App.cable.subscriptions.create "AppearanceChannel"`. [*`appearance.coffee`*] -3. **Server** recognizes a new subscription has been initiated for `AppearanceChannel` channel performs the `subscribed` callback, which calls the `appear` method on the `current_user`. [*`appearance_channel.rb`*] -4. **Client** recognizes that a subscription has been established and calls `connected` [*`appearance.coffee`*] which in turn calls `@install` and `@appear`. `@appear` calls`AppearanceChannel#appear(data)` on the server, and supplies a data hash of `appearing_on: $("main").data("appearing-on")`. This is possible because the server-side channel instance will automatically expose the public methods declared on the class (minus the callbacks), so that these can be reached as remote procedure calls via a subscription's `perform` method. -5. **Server** receives the request for the `appear` action on the `AppearanceChannel` channel for the connection identified by `current_user`. [*`appearance_channel.rb`*] The server retrieves the data with the `appearing_on` key from the data hash and sets it as the value for the `on:` key being passed to `current_user.appear`. -### Example 2: Receiving new web notifications +1. **Client** connects to the **Server** via `App.cable = +ActionCable.createConsumer("ws://cable.example.com")`. (`cable.js`). The +**Server** identifies this connection by `current_user`. + +2. **Client** subscribes to the appearance channel via +`App.cable.subscriptions.create(channel: "AppearanceChannel")`. (`appearance.coffee`) + +3. **Server** recognizes a new subscription has been initiated for the +appearance channel and runs its `subscribed` callback, calling the `appear` +method on `current_user`. (`appearance_channel.rb`) + +4. **Client** recognizes that a subscription has been established and calls +`connected` (`appearance.coffee`) which in turn calls `@install` and `@appear`. +`@appear` calls `AppearanceChannel#appear(data)` on the server, and supplies a +data hash of `{ appearing_on: $("main").data("appearing-on") }`. This is +possible because the server-side channel instance automatically exposes all +public methods declared on the class (minus the callbacks), so that these can be +reached as remote procedure calls via a subscription's `perform` method. + +5. **Server** receives the request for the `appear` action on the appearance +channel for the connection identified by `current_user` +(`appearance_channel.rb`). **Server** retrieves the data with the +`:appearing_on` key from the data hash and sets it as the value for the `:on` +key being passed to `current_user.appear`. + +### Example 2: Receiving New Web Notifications The appearance example was all about exposing server functionality to client-side invocation over the WebSocket connection. But the great thing @@ -435,7 +469,7 @@ where the server invokes an action on the client. This is a web notification channel that allows you to trigger client-side web notifications when you broadcast to the right streams: -#### Create the server-side Web Notifications Channel: +Create the server-side web notifications channel: ```ruby # app/channels/web_notifications_channel.rb @@ -446,34 +480,41 @@ class WebNotificationsChannel < ApplicationCable::Channel end ``` -#### Create the client-side Web Notifications Channel subscription: +Create the client-side web notifications channel subscription: + ```coffeescript # app/assets/javascripts/cable/subscriptions/web_notifications.coffee -# Client-side which assumes you've already requested the right to send web notifications +# Client-side which assumes you've already requested +# the right to send web notifications. App.cable.subscriptions.create "WebNotificationsChannel", received: (data) -> new Notification data["title"], body: data["body"] ``` -#### Broadcast content to a Web Notification Channel instance from elsewhere in your application +Broadcast content to a web notification channel instance from elsewhere in your +application: ```ruby # Somewhere in your app this is called, perhaps from a NewCommentJob - WebNotificationsChannel.broadcast_to current_user, title: 'New things!', body: 'All the news fit to print' +WebNotificationsChannel.broadcast_to( + current_user, + title: 'New things!', + body: 'All the news fit to print' +) ``` The `WebNotificationsChannel.broadcast_to` call places a message in the current -subscription adapter (Redis by default)'s pubsub queue under a separate -broadcasting name for each user. For a user with an ID of 1, the broadcasting -name would be `web_notifications_1`. +subscription adapter's pubsub queue under a separate broadcasting name for each +user. For a user with an ID of 1, the broadcasting name would be +"web_notifications_1". The channel has been instructed to stream everything that arrives at -`web_notifications_1` directly to the client by invoking the `#received(data)` -callback. The data is the hash sent as the second parameter to the server-side -broadcast call, JSON encoded for the trip across the wire, and unpacked for -the data argument arriving to `#received`. +"web_notifications_1" directly to the client by invoking the `received` +callback. The data passed as argument is the hash sent as the second parameter +to the server-side broadcast call, JSON encoded for the trip across the wire, +and unpacked for the data argument arriving to `received`. -### More complete examples +### More Complete Examples See the [rails/actioncable-examples](https://github.com/rails/actioncable-examples) repository for a full example of how to setup Action Cable in a Rails app and adding channels. @@ -484,26 +525,20 @@ Action Cable has two required configurations: a subscription adapter and allowed ### Subscription Adapter -By default, `ActionCable::Server::Base` will look for a configuration file -in `Rails.root.join('config/cable.yml')`. The file must specify an adapter -and a URL for each Rails environment. See the "Dependencies" section for -additional information on adapters. +By default, Action Cable looks for a configuration file in `config/cable.yml`. +The file must specify an adapter and a URL for each Rails environment. See the +[Dependencies](#dependencies) section for additional information on adapters. ```yaml -production: &production - adapter: redis - url: redis://10.10.3.153:6381 -development: &development +development: adapter: async -test: *development -``` -This format allows you to specify one configuration per Rails environment. -You can also change the location of the Action Cable config file in -a Rails initializer with something like: +test: + adapter: async -```ruby -Rails.application.paths.add "config/redis/cable", with: "somewhere/else/cable.yml" +production: + adapter: redis + url: redis://10.10.3.153:6381 ``` ### Allowed Request Origins @@ -513,44 +548,46 @@ passed to the server config as an array. The origins can be instances of strings or regular expressions, against which a check for match will be performed. ```ruby -Rails.application.config.action_cable.allowed_request_origins = ['http://rubyonrails.com', /http:\/\/ruby.*/] +config.action_cable.allowed_request_origins = ['http://rubyonrails.com', %r{http://ruby.*}] ``` To disable and allow requests from any origin: ```ruby -Rails.application.config.action_cable.disable_request_forgery_protection = true +config.action_cable.disable_request_forgery_protection = true ``` By default, Action Cable allows all requests from localhost:3000 when running in the development environment. - ### Consumer Configuration -To configure the URL, add a call to `action_cable_meta_tag` in your HTML layout HEAD. -This uses a url or path typically set via `config.action_cable.url` in the environment configuration files. +To configure the URL, add a call to `action_cable_meta_tag` in your HTML layout +HEAD. This uses a URL or path typically set via `config.action_cable.url` in the +environment configuration files. ### Other Configurations -The other common option to configure is the log tags applied to the per-connection logger. Here's close to what we're using in Basecamp: +The other common option to configure is the log tags applied to the +per-connection logger. Here's close to what we're using in Basecamp: ```ruby -Rails.application.config.action_cable.log_tags = [ +config.action_cable.log_tags = [ -> request { request.env['bc.account_id'] || "no-account" }, :action_cable, -> request { request.uuid } ] ``` -For a full list of all configuration options, see the `ActionCable::Server::Configuration` class. +For a full list of all configuration options, see the +`ActionCable::Server::Configuration` class. -Also note that your server must provide at least the same number of -database connections as you have workers. The default worker pool is -set to 100, so that means you have to make at least that available. -You can change that in `config/database.yml` through the `pool` attribute. +Also note that your server must provide at least the same number of database +connections as you have workers. The default worker pool size is set to 100, so +that means you have to make at least that available. You can change that in +`config/database.yml` through the `pool` attribute. -## Running standalone cable servers +## Running Standalone Cable Servers ### In App @@ -565,30 +602,30 @@ class Application < Rails::Application end ``` -You can use `App.cable = ActionCable.createConsumer()` to connect to the -cable server if `action_cable_meta_tag` is included in the layout. A custom -path is specified as first argument to `createConsumer` -(e.g. `App.cable = ActionCable.createConsumer("/websocket")`). +You can use `App.cable = ActionCable.createConsumer()` to connect to the cable +server if `action_cable_meta_tag` is invoked in the layout. A custom path is +specified as first argument to `createConsumer` (e.g. `App.cable = +ActionCable.createConsumer("/websocket")`). -For every instance of your server you create and for every worker -your server spawns, you will also have a new instance of ActionCable, -but the use of Redis keeps messages synced across connections. +For every instance of your server you create and for every worker your server +spawns, you will also have a new instance of Action Cable, but the use of Redis +keeps messages synced across connections. ### Standalone -The cable servers can be separated from your normal application server. -It's still a Rack application, but it is its own Rack application. -The recommended basic setup is as follows: +The cable servers can be separated from your normal application server. It's +still a Rack application, but it is its own Rack application. The recommended +basic setup is as follows: ```ruby # cable/config.ru -require ::File.expand_path('../../config/environment', __FILE__) +require_relative 'config/environment' Rails.application.eager_load! run ActionCable.server ``` -Then you start the server using a binstub in bin/cable ala: +Then you start the server using a binstub in `bin/cable` ala: ``` #!/bin/bash @@ -624,4 +661,5 @@ The Action Cable server implements the Rack socket hijacking API, thereby allowing the use of a multithreaded pattern for managing connections internally, irrespective of whether the application server is multi-threaded or not. -Accordingly, Action Cable works with all the popular application servers -- Unicorn, Puma and Passenger. +Accordingly, Action Cable works with popular servers like Unicorn, Puma, and +Passenger. diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 5462e6b2b8..a45690c03f 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -252,7 +252,7 @@ Note that `try` will swallow no-method errors, returning nil instead. If you wan ```ruby @number.try(:nest) # => nil -@number.try!(:nest) # NoMethodError: undefined method `nest' for 1:Fixnum +@number.try!(:nest) # NoMethodError: undefined method `nest' for 1:Integer ``` NOTE: Defined in `active_support/core_ext/object/try.rb`. @@ -1742,7 +1742,7 @@ NOTE: Defined in `active_support/core_ext/string/inflections.rb`. The method `constantize` resolves the constant reference expression in its receiver: ```ruby -"Fixnum".constantize # => Fixnum +"Integer".constantize # => Integer module M X = 1 @@ -2611,8 +2611,7 @@ To do so, the method loops over the pairs and builds nodes that depend on the _v ```ruby XML_TYPE_NAMES = { "Symbol" => "symbol", - "Fixnum" => "integer", - "Bignum" => "integer", + "Integer" => "integer", "BigDecimal" => "decimal", "Float" => "float", "TrueClass" => "boolean", diff --git a/guides/source/api_app.md b/guides/source/api_app.md index cad8d53f31..485294dc02 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -289,7 +289,7 @@ You can learn more about how to use `Rack::Sendfile` with popular front-ends in [the Rack::Sendfile documentation](http://rubydoc.info/github/rack/rack/master/Rack/Sendfile). -Here are some values for popular servers, once they are configured, to support +Here are some values for this header for some popular servers, once these servers are configured to support accelerated file sending: ```ruby @@ -395,6 +395,13 @@ included into `ActionController::API` in the rails console: ```bash $ bin/rails c >> ActionController::API.ancestors - ActionController::Metal.ancestors +=> [ActionController::API, + ActiveRecord::Railties::ControllerRuntime, + ActionDispatch::Routing::RouteSet::MountedHelpers, + ActionController::ParamsWrapper, + ... , + AbstractController::Rendering, + ActionView::ViewPaths] ``` ### Adding Other Modules diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index cd208c2e13..5b34330936 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -120,7 +120,7 @@ On the other hand, big chunks of structured documentation may have a separate "E The results of expressions follow them and are introduced by "# => ", vertically aligned: ```ruby -# For checking if a fixnum is even or odd. +# For checking if an integer is even or odd. # # 1.even? # => false # 1.odd? # => true diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 93acebf000..e6631a513c 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -435,11 +435,11 @@ Sprockets uses manifest files to determine which assets to include and serve. These manifest files contain _directives_ - instructions that tell Sprockets which files to require in order to build a single CSS or JavaScript file. With these directives, Sprockets loads the files specified, processes them if -necessary, concatenates them into one single file and then compresses them (if -`Rails.application.config.assets.compress` is true). By serving one file rather -than many, the load time of pages can be greatly reduced because the browser -makes fewer requests. Compression also reduces file size, enabling the -browser to download them faster. +necessary, concatenates them into one single file and then compresses them +(based on value of `Rails.application.config.assets.js_compressor`). By serving +one file rather than many, the load time of pages can be greatly reduced because +the browser makes fewer requests. Compression also reduces file size, enabling +the browser to download them faster. For example, a new Rails application includes a default @@ -1105,11 +1105,6 @@ NOTE: You will need an [ExecJS](https://github.com/rails/execjs#readme) supported runtime in order to use `uglifier`. If you are using Mac OS X or Windows you have a JavaScript runtime installed in your operating system. -NOTE: The `config.assets.compress` initialization option is no longer used in -Rails to enable either CSS or JavaScript compression. Setting it will have no -effect on the application. Instead, setting `config.assets.css_compressor` and -`config.assets.js_compressor` will control compression of CSS and JavaScript -assets. ### Serving GZipped version of assets @@ -1291,7 +1286,7 @@ config.assets.js_compressor = :uglifier # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = false -# Generate digests for assets URLs. This is planned for deprecation. +# Generate digests for assets URLs. config.assets.digest = true # Precompile additional assets (application.js, application.css, and all diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index 745f09f523..6c734c1d78 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -100,8 +100,8 @@ called key-based expiration. Cache fragments will also be expired when the view fragment changes (e.g., the HTML in the view changes). The string of characters at the end of the key is a -template tree digest. It is an md5 hash computed based on the contents of the -view fragment you are caching. If you change the view fragment, the md5 hash +template tree digest. It is an MD5 hash computed based on the contents of the +view fragment you are caching. If you change the view fragment, the MD5 hash will change, expiring the existing file. TIP: Cache stores like Memcached will automatically delete old cache files. @@ -258,7 +258,7 @@ comment format anywhere in the template, like: If you use a helper method, for example, inside a cached block and you then update that helper, you'll have to bump the cache as well. It doesn't really matter how -you do it, but the md5 of the template file must change. One recommendation is to +you do it, but the MD5 of the template file must change. One recommendation is to simply be explicit in a comment, like: ```html+erb diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 2afb9356ec..66aae112d8 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -60,11 +60,11 @@ These configuration methods are to be called on a `Rails::Railtie` object, such * `config.asset_host` sets the host for the assets. Useful when CDNs are used for hosting assets, or when you want to work around the concurrency constraints built-in in browsers using different domain aliases. Shorter version of `config.action_controller.asset_host`. -* `config.autoload_once_paths` accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if `config.cache_classes` is false, which is the case in development mode by default. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array. +* `config.autoload_once_paths` accepts an array of paths from which Rails will autoload constants that won't be wiped per request. Relevant if `config.cache_classes` is `false`, which is the case in development mode by default. Otherwise, all autoloading happens only once. All elements of this array must also be in `autoload_paths`. Default is an empty array. * `config.autoload_paths` accepts an array of paths from which Rails will autoload constants. Default is all directories under `app`. -* `config.cache_classes` controls whether or not application classes and modules should be reloaded on each request. Defaults to false in development mode, and true in test and production modes. +* `config.cache_classes` controls whether or not application classes and modules should be reloaded on each request. Defaults to `false` in development mode, and `true` in test and production modes. * `config.action_view.cache_template_loading` controls whether or not templates should be reloaded on each request. Defaults to whatever is set for `config.cache_classes`. @@ -73,9 +73,9 @@ application. Accepts a valid week day symbol (e.g. `:monday`). * `config.cache_store` configures which cache store to use for Rails caching. Options include one of the symbols `:memory_store`, `:file_store`, `:mem_cache_store`, `:null_store`, or an object that implements the cache API. Defaults to `:file_store` if the directory `tmp/cache` exists, and to `:memory_store` otherwise. -* `config.colorize_logging` specifies whether or not to use ANSI color codes when logging information. Defaults to true. +* `config.colorize_logging` specifies whether or not to use ANSI color codes when logging information. Defaults to `true`. -* `config.consider_all_requests_local` is a flag. If true then any error will cause detailed debugging information to be dumped in the HTTP response, and the `Rails::Info` controller will show the application runtime context in `/rails/info/properties`. True by default in development and test environments, and false in production mode. For finer-grained control, set this to false and implement `local_request?` in controllers to specify which requests should provide debugging information on errors. +* `config.consider_all_requests_local` is a flag. If `true` then any error will cause detailed debugging information to be dumped in the HTTP response, and the `Rails::Info` controller will show the application runtime context in `/rails/info/properties`. `true` by default in development and test environments, and `false` in production mode. For finer-grained control, set this to `false` and implement `local_request?` in controllers to specify which requests should provide debugging information on errors. * `config.console` allows you to set class that will be used as console you run `rails console`. It's best to run it in `console` block: @@ -88,9 +88,9 @@ application. Accepts a valid week day symbol (e.g. `:monday`). end ``` -* `config.eager_load` when true, eager loads all registered `config.eager_load_namespaces`. This includes your application, engines, Rails frameworks and any other registered namespace. +* `config.eager_load` when `true`, eager loads all registered `config.eager_load_namespaces`. This includes your application, engines, Rails frameworks and any other registered namespace. -* `config.eager_load_namespaces` registers namespaces that are eager loaded when `config.eager_load` is true. All namespaces in the list must respond to the `eager_load!` method. +* `config.eager_load_namespaces` registers namespaces that are eager loaded when `config.eager_load` is `true`. All namespaces in the list must respond to the `eager_load!` method. * `config.eager_load_paths` accepts an array of paths from which Rails will eager load on boot if cache classes is enabled. Defaults to every folder in the `app` directory of the application. @@ -100,7 +100,7 @@ application. Accepts a valid week day symbol (e.g. `:monday`). * `config.debug_exception_response_format` sets the format used in responses when errors occur in development mode. Defaults to `:api` for API only apps and `:default` for normal apps. -* `config.file_watcher` is the class used to detect file updates in the file system when `config.reload_classes_only_on_change` is true. Rails ships with `ActiveSupport::FileUpdateChecker`, the default, and `ActiveSupport::EventedFileUpdateChecker` (this one depends on the [listen](https://github.com/guard/listen) gem). Custom classes must conform to the `ActiveSupport::FileUpdateChecker` API. +* `config.file_watcher` is the class used to detect file updates in the file system when `config.reload_classes_only_on_change` is `true`. Rails ships with `ActiveSupport::FileUpdateChecker`, the default, and `ActiveSupport::EventedFileUpdateChecker` (this one depends on the [listen](https://github.com/guard/listen) gem). Custom classes must conform to the `ActiveSupport::FileUpdateChecker` API. * `config.filter_parameters` used for filtering out the parameters that you don't want shown in the logs, such as passwords or credit card @@ -134,11 +134,11 @@ defaults to `:debug` for all environments. The available log levels are: `:debug * `config.middleware` allows you to configure the application's middleware. This is covered in depth in the [Configuring Middleware](#configuring-middleware) section below. -* `config.reload_classes_only_on_change` enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to true. If `config.cache_classes` is true, this option is ignored. +* `config.reload_classes_only_on_change` enables or disables reloading of classes only when tracked files change. By default tracks everything on autoload paths and is set to `true`. If `config.cache_classes` is `true`, this option is ignored. * `secrets.secret_key_base` is used for specifying a key which allows sessions for the application to be verified against a known secure key to prevent tampering. Applications get `secrets.secret_key_base` initialized to a random key present in `config/secrets.yml`. -* `config.public_file_server.enabled` configures Rails to serve static files from the public directory. This option defaults to true, but in the production environment it is set to false because the server software (e.g. NGINX or Apache) used to run the application should serve static files instead. If you are running or testing your app in production mode using WEBrick (it is not recommended to use WEBrick in production) set the option to true. Otherwise, you won't be able to use page caching and request for files that exist under the public directory. +* `config.public_file_server.enabled` configures Rails to serve static files from the public directory. This option defaults to `true`, but in the production environment it is set to `false` because the server software (e.g. NGINX or Apache) used to run the application should serve static files instead. If you are running or testing your app in production mode using WEBrick (it is not recommended to use WEBrick in production) set the option to `true.` Otherwise, you won't be able to use page caching and request for files that exist under the public directory. * `config.session_store` is usually set up in `config/initializers/session_store.rb` and specifies what class to use to store the session. Possible values are `:cookie_store` which is the default, `:mem_cache_store`, and `:disabled`. The last one tells Rails not to deal with sessions. Custom session stores can also be specified: @@ -153,12 +153,10 @@ defaults to `:debug` for all environments. The available log levels are: `:debug ### Configuring Assets * `config.assets.enabled` a flag that controls whether the asset -pipeline is enabled. It is set to true by default. +pipeline is enabled. It is set to `true` by default. * `config.assets.raise_runtime_errors` Set this flag to `true` to enable additional runtime error checking. Recommended in `config/environments/development.rb` to minimize unexpected behavior when deploying to `production`. -* `config.assets.compress` a flag that enables the compression of compiled assets. It is explicitly set to true in `config/environments/production.rb`. - * `config.assets.css_compressor` defines the CSS compressor to use. It is set by default by `sass-rails`. The unique alternative value at the moment is `:yui`, which uses the `yui-compressor` gem. * `config.assets.js_compressor` defines the JavaScript compressor to use. Possible values are `:closure`, `:uglifier` and `:yui` which require the use of the `closure-compiler`, `uglifier` or `yui-compressor` gems respectively. @@ -179,7 +177,7 @@ pipeline is enabled. It is set to true by default. * `config.assets.compile` is a boolean that can be used to turn on live Sprockets compilation in production. -* `config.assets.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to the same configured at `config.logger`. Setting `config.assets.logger` to false will turn off served assets logging. +* `config.assets.logger` accepts a logger conforming to the interface of Log4r or the default Ruby `Logger` class. Defaults to the same configured at `config.logger`. Setting `config.assets.logger` to `false` will turn off served assets logging. ### Configuring Generators @@ -292,17 +290,17 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.schema_migrations_table_name` lets you set a string to be used as the name of the schema migrations table. -* `config.active_record.pluralize_table_names` specifies whether Rails will look for singular or plural table names in the database. If set to true (the default), then the Customer class will use the `customers` table. If set to false, then the Customer class will use the `customer` table. +* `config.active_record.pluralize_table_names` specifies whether Rails will look for singular or plural table names in the database. If set to `true` (the default), then the Customer class will use the `customers` table. If set to false, then the Customer class will use the `customer` table. * `config.active_record.default_timezone` determines whether to use `Time.local` (if set to `:local`) or `Time.utc` (if set to `:utc`) when pulling dates and times from the database. The default is `:utc`. * `config.active_record.schema_format` controls the format for dumping the database schema to a file. The options are `:ruby` (the default) for a database-independent version that depends on migrations, or `:sql` for a set of (potentially database-dependent) SQL statements. -* `config.active_record.error_on_ignored_order_or_limit` specifies if an error should be raised if the order or limit of a query is ignored during a batch query. The options are true (raise error) or false (warn). Default is false. +* `config.active_record.error_on_ignored_order_or_limit` specifies if an error should be raised if the order or limit of a query is ignored during a batch query. The options are `true` (raise error) or `false` (warn). Default is `false`. -* `config.active_record.timestamped_migrations` controls whether migrations are numbered with serial integers or with timestamps. The default is true, to use timestamps, which are preferred if there are multiple developers working on the same application. +* `config.active_record.timestamped_migrations` controls whether migrations are numbered with serial integers or with timestamps. The default is `true`, to use timestamps, which are preferred if there are multiple developers working on the same application. -* `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is true by default. +* `config.active_record.lock_optimistically` controls whether Active Record will use optimistic locking and is `true` by default. * `config.active_record.cache_timestamp_format` controls the format of the timestamp value in the cache key. Default is `:nsec`. @@ -310,13 +308,13 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.partial_writes` is a boolean value and controls whether or not partial writes are used (i.e. whether updates only set attributes that are dirty). Note that when using partial writes, you should also use optimistic locking `config.active_record.lock_optimistically` since concurrent updates may write attributes based on a possibly stale read state. The default value is `true`. -* `config.active_record.maintain_test_schema` is a boolean value which controls whether Active Record should try to keep your test database schema up-to-date with `db/schema.rb` (or `db/structure.sql`) when you run your tests. The default is true. +* `config.active_record.maintain_test_schema` is a boolean value which controls whether Active Record should try to keep your test database schema up-to-date with `db/schema.rb` (or `db/structure.sql`) when you run your tests. The default is `true`. * `config.active_record.dump_schema_after_migration` is a flag which controls whether or not schema dump should happen (`db/schema.rb` or - `db/structure.sql`) when you run migrations. This is set to false in + `db/structure.sql`) when you run migrations. This is set to `false` in `config/environments/production.rb` which is generated by Rails. The - default value is true if this configuration is not set. + default value is `true` if this configuration is not set. * `config.active_record.dump_schemas` controls which database schemas will be dumped when calling db:structure:dump. The options are `:schema_search_path` (the default) which dumps any schemas listed in schema_search_path, @@ -334,11 +332,11 @@ All these configuration options are delegated to the `I18n` library. * `config.active_record.index_nested_attribute_errors` allows errors for nested has_many relationships to be displayed with an index as well as the error. - Defaults to false. + Defaults to `false`. The MySQL adapter adds one additional configuration option: -* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. True by default. +* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`. The schema dumper adds one additional configuration option: @@ -350,7 +348,7 @@ The schema dumper adds one additional configuration option: * `config.action_controller.asset_host` sets the host for the assets. Useful when CDNs are used for hosting assets rather than the application server itself. -* `config.action_controller.perform_caching` configures whether the application should perform the caching features provided by the Action Controller component or not. Set to false in development mode, true in production. +* `config.action_controller.perform_caching` configures whether the application should perform the caching features provided by the Action Controller component or not. Set to `false` in development mode, `true` in production. * `config.action_controller.default_static_extension` configures the extension used for cached pages. Defaults to `.html`. @@ -392,6 +390,10 @@ The schema dumper adds one additional configuration option: * `config.action_dispatch.tld_length` sets the TLD (top-level domain) length for the application. Defaults to `1`. +* `config.action_dispatch.ignore_accept_header` is used to determine whether to ignore accept headers from a request. Defaults to `false`. + +* `config.action_dispatch.x_sendfile_header` specifies server specific X-Sendfile header. This is useful for accelerated file sending from server. For example it can be set to 'X-Sendfile' for Apache. + * `config.action_dispatch.http_auth_salt` sets the HTTP Auth salt value. Defaults to `'http authentication'`. @@ -406,7 +408,7 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. * `config.action_dispatch.perform_deep_munge` configures whether `deep_munge` method should be performed on the parameters. See [Security Guide](security.html#unsafe-query-generation) - for more information. It defaults to true. + for more information. It defaults to `true`. * `config.action_dispatch.rescue_responses` configures what exceptions are assigned to an HTTP status. It accepts a hash and you can specify pairs of exception/status. By default, this is defined as: @@ -461,7 +463,7 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. * `config.action_view.embed_authenticity_token_in_remote_forms` allows you to set the default behavior for `authenticity_token` in forms with `remote: - true`. By default it's set to false, which means that remote forms will not + true`. By default it's set to `false`, which means that remote forms will not include `authenticity_token`, which is helpful when you're fragment-caching the form. Remote forms get the authenticity from the `meta` tag, so embedding is unnecessary unless you support browsers without JavaScript. In such case @@ -480,9 +482,9 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. error should be raised for missing translations. * `config.action_view.automatically_disable_submit_tag` determines whether - submit_tag should automatically disable on click, this defaults to true. + submit_tag should automatically disable on click, this defaults to `true`. -* `config.action_view.debug_missing_translation` determines whether to wrap the missing translations key in a `<span>` tag or not. This defaults to true. +* `config.action_view.debug_missing_translation` determines whether to wrap the missing translations key in a `<span>` tag or not. This defaults to `true`. ### Configuring Action Mailer @@ -497,16 +499,19 @@ There are a number of settings available on `config.action_mailer`: * `:user_name` - If your mail server requires authentication, set the username in this setting. * `:password` - If your mail server requires authentication, set the password in this setting. * `:authentication` - If your mail server requires authentication, you need to specify the authentication type here. This is a symbol and one of `:plain`, `:login`, `:cram_md5`. + * `:enable_starttls_auto` - Detects if STARTTLS is enabled in your SMTP server and starts to use it. It defaults to `true`. + * `:openssl_verify_mode` - When using TLS, you can set how OpenSSL checks the certificate. This is useful if you need to validate a self-signed and/or a wildcard certificate. This can be one of the OpenSSL verify constants, `:none`, `:peer`, `:client_once`, `:fail_if_no_peer_cert`, or the constant directly `OpenSSL::SSL::VERIFY_NONE`. + * `:ssl/:tls` - Enables the SMTP connection to use SMTP/TLS (SMTPS: SMTP over direct TLS connection). * `config.action_mailer.sendmail_settings` allows detailed configuration for the `sendmail` delivery method. It accepts a hash of options, which can include any of these options: * `:location` - The location of the sendmail executable. Defaults to `/usr/sbin/sendmail`. * `:arguments` - The command line arguments. Defaults to `-i -t`. -* `config.action_mailer.raise_delivery_errors` specifies whether to raise an error if email delivery cannot be completed. It defaults to true. +* `config.action_mailer.raise_delivery_errors` specifies whether to raise an error if email delivery cannot be completed. It defaults to `true`. * `config.action_mailer.delivery_method` defines the delivery method and defaults to `:smtp`. See the [configuration section in the Action Mailer guide](action_mailer_basics.html#action-mailer-configuration) for more info. -* `config.action_mailer.perform_deliveries` specifies whether mail will actually be delivered and is true by default. It can be convenient to set it to false for testing. +* `config.action_mailer.perform_deliveries` specifies whether mail will actually be delivered and is true by default. It can be convenient to set it to `false` for testing. * `config.action_mailer.default_options` configures Action Mailer defaults. Use to set options like `from` or `reply_to` for every mailer. These default to: @@ -552,7 +557,7 @@ There are a number of settings available on `config.action_mailer`: * `config.action_mailer.deliver_later_queue_name` specifies the queue name for mailers. By default this is `mailers`. -* `config.action_mailer.perform_caching` specifies whether the mailer templates should perform fragment caching or not. By default this is false in all environments. +* `config.action_mailer.perform_caching` specifies whether the mailer templates should perform fragment caching or not. By default this is `false` in all environments. ### Configuring Active Support @@ -569,7 +574,7 @@ There are a few configuration options available in Active Support: * `config.active_support.time_precision` sets the precision of JSON encoded time values. Defaults to `3`. -* `ActiveSupport.halt_callback_chains_on_return_false` specifies whether Active Record and Active Model callback chains can be halted by returning `false` in a 'before' callback. When set to `false`, callback chains are halted only when explicitly done so with `throw(:abort)`. When set to `true`, callback chains are halted when a callback returns false (the previous behavior before Rails 5) and a deprecation warning is given. Defaults to `true` during the deprecation period. New Rails 5 apps generate an initializer file called `callback_terminator.rb` which sets the value to `false`. This file is *not* added when running `rails app:update`, so returning `false` will still work on older apps ported to Rails 5 and display a deprecation warning to prompt users to update their code. +* `ActiveSupport.halt_callback_chains_on_return_false` specifies whether Active Record and Active Model callback chains can be halted by returning `false` in a 'before' callback. When set to `false`, callback chains are halted only when explicitly done so with `throw(:abort)`. When set to `true`, callback chains are halted when a callback returns `false` (the previous behavior before Rails 5) and a deprecation warning is given. Defaults to `true` during the deprecation period. New Rails 5 apps generate an initializer file called `callback_terminator.rb` which sets the value to `false`. This file is *not* added when running `rails app:update`, so returning `false` will still work on older apps ported to Rails 5 and display a deprecation warning to prompt users to update their code. * `ActiveSupport::Logger.silencer` is set to `false` to disable the ability to silence logging in a block. The default is `true`. @@ -1063,7 +1068,7 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `action_controller.compile_config_methods`: Initializes methods for the config settings specified so that they are quicker to access. -* `active_record.initialize_timezone`: Sets `ActiveRecord::Base.time_zone_aware_attributes` to true, as well as setting `ActiveRecord::Base.default_timezone` to UTC. When attributes are read from the database, they will be converted into the time zone specified by `Time.zone`. +* `active_record.initialize_timezone`: Sets `ActiveRecord::Base.time_zone_aware_attributes` to `true`, as well as setting `ActiveRecord::Base.default_timezone` to UTC. When attributes are read from the database, they will be converted into the time zone specified by `Time.zone`. * `active_record.logger`: Sets `ActiveRecord::Base.logger` - if it's not already set - to `Rails.logger`. @@ -1122,13 +1127,13 @@ Below is a comprehensive list of all the initializers found in Rails in the orde * `build_middleware_stack`: Builds the middleware stack for the application, returning an object which has a `call` method which takes a Rack environment object for the request. -* `eager_load!`: If `config.eager_load` is true, runs the `config.before_eager_load` hooks and then calls `eager_load!` which will load all `config.eager_load_namespaces`. +* `eager_load!`: If `config.eager_load` is `true`, runs the `config.before_eager_load` hooks and then calls `eager_load!` which will load all `config.eager_load_namespaces`. * `finisher_hook`: Provides a hook for after the initialization of process of the application is complete, as well as running all the `config.after_initialize` blocks for the application, railties and engines. * `set_routes_reloader`: Configures Action Dispatch to reload the routes file using `ActionDispatch::Callbacks.to_prepare`. -* `disable_dependency_loading`: Disables the automatic dependency loading if the `config.eager_load` is set to true. +* `disable_dependency_loading`: Disables the automatic dependency loading if the `config.eager_load` is set to `true`. Database pooling ---------------- @@ -1233,7 +1238,7 @@ Evented File System Monitor If the [listen gem](https://github.com/guard/listen) is loaded Rails uses an evented file system monitor to detect changes when `config.cache_classes` is -false: +`false`: ```ruby group :development do diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 03943d0f25..a5b8a75509 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -139,6 +139,10 @@ name: Using Rails for API-only Applications url: api_app.html description: This guide explains how to effectively use Rails to develop a JSON API application. + - + name: Action Cable Overview + url: action_cable_overview.html + description: This guide explains how Action Cable works, and how to use WebSockets to create real-time features. - name: Extending Rails diff --git a/guides/source/security.md b/guides/source/security.md index 16c5291037..c6bc1f3878 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -41,24 +41,24 @@ NOTE: _HTTP is a stateless protocol. Sessions make it stateful._ Most applications need to keep track of certain state of a particular user. This could be the contents of a shopping basket or the user id of the currently logged in user. Without the idea of sessions, the user would have to identify, and probably authenticate, on every request. Rails will create a new session automatically if a new user accesses the application. It will load an existing session if the user has already used the application. -A session usually consists of a hash of values and a session id, usually a 32-character string, to identify the hash. Every cookie sent to the client's browser includes the session id. And the other way round: the browser will send it to the server on every request from the client. In Rails you can save and retrieve values using the session method: +A session usually consists of a hash of values and a session ID, usually a 32-character string, to identify the hash. Every cookie sent to the client's browser includes the session ID. And the other way round: the browser will send it to the server on every request from the client. In Rails you can save and retrieve values using the session method: ```ruby session[:user_id] = @current_user.id User.find(session[:user_id]) ``` -### Session id +### Session ID -NOTE: _The session id is a 32 byte long MD5 hash value._ +NOTE: _The session ID is a 32-character random hex string._ -A session id consists of the hash value of a random string. The random string is the current time, a random number between 0 and 1, the process id number of the Ruby interpreter (also basically a random number) and a constant string. Currently it is not feasible to brute-force Rails' session ids. To date MD5 is uncompromised, but there have been collisions, so it is theoretically possible to create another input text with the same hash value. But this has had no security impact to date. +The session ID is generated using `SecureRandom.hex` which generates a random hex string using platform specific methods (such as OpenSSL, /dev/urandom or Win32) for generating cryptographically secure random numbers. Currently it is not feasible to brute-force Rails' session IDs. ### Session Hijacking -WARNING: _Stealing a user's session id lets an attacker use the web application in the victim's name._ +WARNING: _Stealing a user's session ID lets an attacker use the web application in the victim's name._ -Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session id in the cookie identifies the session. +Many web applications have an authentication system: a user provides a user name and password, the web application checks them and stores the corresponding user id in the session hash. From now on, the session is valid. On every request the application will load the user, identified by the user id in the session, without the need for new authentication. The session ID in the cookie identifies the session. Hence, the cookie serves as temporary authentication for the web application. Anyone who seizes a cookie from someone else, may use the web application as this user - with possibly severe consequences. Here are some ways to hijack a session, and their countermeasures: @@ -89,7 +89,7 @@ This will also be a good idea, if you modify the structure of an object and old NOTE: _Rails provides several storage mechanisms for the session hashes. The most important is `ActionDispatch::Session::CookieStore`._ -Rails 2 introduced a new default session storage, CookieStore. CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session id. That will greatly increase the speed of the application, but it is a controversial storage option and you have to think about the security implications of it: +Rails 2 introduced a new default session storage, CookieStore. CookieStore saves the session hash directly in a cookie on the client-side. The server retrieves the session hash from the cookie and eliminates the need for a session ID. That will greatly increase the speed of the application, but it is a controversial storage option and you have to think about the security implications of it: * Cookies imply a strict size limit of 4kB. This is fine as you should not store large amounts of data in a session anyway, as described before. _Storing the current user's database id in a session is usually ok_. @@ -137,16 +137,16 @@ The best _solution against it is not to store this kind of data in a session, bu ### Session Fixation -NOTE: _Apart from stealing a user's session id, the attacker may fix a session id known to them. This is called session fixation._ +NOTE: _Apart from stealing a user's session ID, the attacker may fix a session ID known to them. This is called session fixation._ ![Session fixation](images/session_fixation.png) -This attack focuses on fixing a user's session id known to the attacker, and forcing the user's browser into using this id. It is therefore not necessary for the attacker to steal the session id afterwards. Here is how this attack works: +This attack focuses on fixing a user's session ID known to the attacker, and forcing the user's browser into using this ID. It is therefore not necessary for the attacker to steal the session ID afterwards. Here is how this attack works: -* The attacker creates a valid session id: They load the login page of the web application where they want to fix the session, and take the session id in the cookie from the response (see number 1 and 2 in the image). +* The attacker creates a valid session ID: They load the login page of the web application where they want to fix the session, and take the session ID in the cookie from the response (see number 1 and 2 in the image). * They maintain the session by accessing the web application periodically in order to keep an expiring session alive. -* The attacker forces the user's browser into using this session id (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on. -* The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session id to the trap session id. +* The attacker forces the user's browser into using this session ID (see number 3 in the image). As you may not change a cookie of another domain (because of the same origin policy), the attacker has to run a JavaScript from the domain of the target web application. Injecting the JavaScript code into the application by XSS accomplishes this attack. Here is an example: `<script>document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";</script>`. Read more about XSS and injection later on. +* The attacker lures the victim to the infected page with the JavaScript code. By viewing the page, the victim's browser will change the session ID to the trap session ID. * As the new trap session is unused, the web application will require the user to authenticate. * From now on, the victim and the attacker will co-use the web application with the same session: The session became valid and the victim didn't notice the attack. @@ -168,7 +168,7 @@ Another countermeasure is to _save user-specific properties in the session_, ver NOTE: _Sessions that never expire extend the time-frame for attacks such as cross-site request forgery (CSRF), session hijacking and session fixation._ -One possibility is to set the expiry time-stamp of the cookie with the session id. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago. +One possibility is to set the expiry time-stamp of the cookie with the session ID. However the client can edit cookies that are stored in the web browser so expiring sessions on the server is safer. Here is an example of how to _expire sessions in a database table_. Call `Session.sweep("20 minutes")` to expire sessions that were used longer than 20 minutes ago. ```ruby class Session < ApplicationRecord @@ -196,11 +196,11 @@ This attack method works by including malicious code or a link in a page that ac ![](images/csrf.png) -In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session id in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is that if the request comes from a site of a different domain, it will also send the cookie. Let's start with an example: +In the [session chapter](#sessions) you have learned that most Rails applications use cookie-based sessions. Either they store the session ID in the cookie and have a server-side session hash, or the entire session hash is on the client-side. In either case the browser will automatically send along the cookie on every request to a domain, if it can find a cookie for that domain. The controversial point is that if the request comes from a site of a different domain, it will also send the cookie. Let's start with an example: * Bob browses a message board and views a post from a hacker where there is a crafted HTML image element. The element references a command in Bob's project management application, rather than an image file: `<img src="http://www.webapp.com/project/1/destroy">` * Bob's session at `www.webapp.com` is still alive, because he didn't log out a few minutes ago. -* By viewing the post, the browser finds an image tag. It tries to load the suspected image from `www.webapp.com`. As explained before, it will also send along the cookie with the valid session id. +* By viewing the post, the browser finds an image tag. It tries to load the suspected image from `www.webapp.com`. As explained before, it will also send along the cookie with the valid session ID. * The web application at `www.webapp.com` verifies the user information in the corresponding session hash and destroys the project with the ID 1. It then returns a result page which is an unexpected result for the browser, so it will not display the image. * Bob doesn't notice the attack - but a few days later he finds out that project number one is gone. @@ -677,14 +677,12 @@ INFO: _The most widespread, and one of the most devastating security vulnerabili An entry point is a vulnerable URL and its parameters where an attacker can start an attack. -The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications, such as the [Live HTTP Headers Firefox plugin](http://livehttpheaders.mozdev.org/), or client-site proxies make it easy to change requests. +The most common entry points are message posts, user comments, and guest books, but project titles, document names and search result pages have also been vulnerable - just about everywhere where the user can input data. But the input does not necessarily have to come from input boxes on web sites, it can be in any URL parameter - obvious, hidden or internal. Remember that the user may intercept any traffic. Applications or client-site proxies make it easy to change requests. There are also other attack vectors like banner advertisements. XSS attacks work like this: An attacker injects some code, the web application saves it and displays it on a page, later presented to a victim. Most XSS examples simply display an alert box, but it is more powerful than that. XSS can steal the cookie, hijack the session, redirect the victim to a fake website, display advertisements for the benefit of the attacker, change elements on the web site to get confidential information or install malicious software through security holes in the web browser. During the second half of 2007, there were 88 vulnerabilities reported in Mozilla browsers, 22 in Safari, 18 in IE, and 12 in Opera. The [Symantec Global Internet Security threat report](http://eval.symantec.com/mktginfo/enterprise/white_papers/b-whitepaper_internet_security_threat_report_xiii_04-2008.en-us.pdf) also documented 239 browser plug-in vulnerabilities in the last six months of 2007. [Mpack](http://pandalabs.pandasecurity.com/mpack-uncovered/) is a very active and up-to-date attack framework which exploits these vulnerabilities. For criminal hackers, it is very attractive to exploit an SQL-Injection vulnerability in a web application framework and insert malicious code in every textual table column. In April 2008 more than 510,000 sites were hacked like this, among them the British government, United Nations, and many more high targets. -A relatively new, and unusual, form of entry points are banner advertisements. In earlier 2008, malicious code appeared in banner ads on popular sites, such as MySpace and Excite, according to [Trend Micro](http://blog.trendmicro.com/myspace-excite-and-blick-serve-up-malicious-banner-ads/). - #### HTML/JavaScript Injection The most common XSS language is of course the most popular client-side scripting language JavaScript, often in combination with HTML. _Escaping user input is essential_. @@ -722,7 +720,7 @@ The log files on www.attacker.com will read like this: GET http://www.attacker.com/_app_session=836c1c25278e5b321d6bea4f19cb57e2 ``` -You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. Http only cookies can be used from IE v6.SP1, Firefox v2.0.0.5 and Opera 9.5. Safari is still considering, it ignores the option. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly), though. +You can mitigate these attacks (in the obvious way) by adding the **httpOnly** flag to cookies, so that document.cookie may not be read by JavaScript. HTTP only cookies can be used from IE v6.SP1, Firefox v2.0.0.5, Opera 9.5, Safari 4 and Chrome 1.0.154 onwards. But other, older browsers (such as WebTV and IE 5.5 on Mac) can actually cause the page to fail to load. Be warned that cookies [will still be visible using Ajax](https://www.owasp.org/index.php/HTTPOnly#Browsers_Supporting_HttpOnly), though. ##### Defacement diff --git a/guides/source/testing.md b/guides/source/testing.md index 34c831c802..050bdda9e3 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -1289,5 +1289,5 @@ end assert_equal Date.new(2004, 10, 24), user.activation_date # The change was visible only inside the `travel_to` block. ``` -Please see [`ActiveSupport::TimeHelpers` API Documentation](http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html) +Please see [`ActiveSupport::Testing::TimeHelpers` API Documentation](http://api.rubyonrails.org/classes/ActiveSupport/Testing/TimeHelpers.html) for in-depth information about the available time helpers. diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 59eddb6302..82080c4def 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -881,7 +881,7 @@ Rails 4.0 no longer supports loading plugins from `vendor/plugins`. You must rep * Rails 4.0 has removed the identity map from Active Record, due to [some inconsistencies with associations](https://github.com/rails/rails/commit/302c912bf6bcd0fa200d964ec2dc4a44abe328a6). If you have manually enabled it in your application, you will have to remove the following config that has no effect anymore: `config.active_record.identity_map`. -* The `delete` method in collection associations can now receive `Fixnum` or `String` arguments as record ids, besides records, pretty much like the `destroy` method does. Previously it raised `ActiveRecord::AssociationTypeMismatch` for such arguments. From Rails 4.0 on `delete` automatically tries to find the records matching the given ids before deleting them. +* The `delete` method in collection associations can now receive `Integer` or `String` arguments as record ids, besides records, pretty much like the `destroy` method does. Previously it raised `ActiveRecord::AssociationTypeMismatch` for such arguments. From Rails 4.0 on `delete` automatically tries to find the records matching the given ids before deleting them. * In Rails 4.0 when a column or a table is renamed the related indexes are also renamed. If you have migrations which rename the indexes, they are no longer needed. |