diff options
Diffstat (limited to 'guides')
24 files changed, 111 insertions, 314 deletions
diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb index 1d059cc2a5..8b7aa893fd 100644 --- a/guides/bug_report_templates/action_controller_gem.rb +++ b/guides/bug_report_templates/action_controller_gem.rb @@ -15,7 +15,7 @@ require "rack/test" require "action_controller/railtie" class TestApp < Rails::Application - config.root = File.dirname(__FILE__) + config.root = __dir__ config.session_store :cookie_store, key: "cookie_store_key" secrets.secret_token = "secret_token" secrets.secret_key_base = "secret_key_base" diff --git a/guides/bug_report_templates/action_controller_master.rb b/guides/bug_report_templates/action_controller_master.rb index 7644f6fe4a..3dd66c95ec 100644 --- a/guides/bug_report_templates/action_controller_master.rb +++ b/guides/bug_report_templates/action_controller_master.rb @@ -14,7 +14,7 @@ end require "action_controller/railtie" class TestApp < Rails::Application - config.root = File.dirname(__FILE__) + config.root = __dir__ secrets.secret_token = "secret_token" secrets.secret_key_base = "secret_key_base" diff --git a/guides/rails_guides/helpers.rb b/guides/rails_guides/helpers.rb index 2a193ca6b5..520aa7f7cc 100644 --- a/guides/rails_guides/helpers.rb +++ b/guides/rails_guides/helpers.rb @@ -15,7 +15,7 @@ module RailsGuides end def documents_by_section - @documents_by_section ||= YAML.load_file(File.expand_path("../../source/#{@language ? @language + '/' : ''}documents.yaml", __FILE__)) + @documents_by_section ||= YAML.load_file(File.expand_path("../source/#{@language ? @language + '/' : ''}documents.yaml", __dir__)) end def documents_flat diff --git a/guides/rails_guides/markdown/renderer.rb b/guides/rails_guides/markdown/renderer.rb index 9d43c10be6..7ac3d417a4 100644 --- a/guides/rails_guides/markdown/renderer.rb +++ b/guides/rails_guides/markdown/renderer.rb @@ -93,7 +93,7 @@ HTML def github_file_url(file_path) tree = version || edge - root = file_path[%r{(.+)/}, 1] + root = file_path[%r{(\w+)/}, 1] path = \ case root when "abstract_controller", "action_controller", "action_dispatch" diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 5d987264f5..22537f960c 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -715,6 +715,9 @@ end Now, the `LoginsController`'s `new` and `create` actions will work as before without requiring the user to be logged in. The `:only` option is used to skip this filter only for these actions, and there is also an `:except` option which works the other way. These options can be used when adding filters too, so you can add a filter which only runs for selected actions in the first place. +NOTE: Calling the same filter multiple times with different options will not work, +since the last filter definition will overwrite the previous ones. + ### After Filters and Around Filters In addition to "before" filters, you can also run filters after an action has been executed, or both before and after. diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index 65146ee7da..7751ac00df 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -781,7 +781,8 @@ config.action_mailer.smtp_settings = { enable_starttls_auto: true } ``` Note: As of July 15, 2014, Google increased [its security measures](https://support.google.com/accounts/answer/6010255) and now blocks attempts from apps it deems less secure. -You can change your gmail settings [here](https://www.google.com/settings/security/lesssecureapps) to allow the attempts or +You can change your Gmail settings [here](https://www.google.com/settings/security/lesssecureapps) to allow the attempts. If your Gmail account has 2-factor authentication enabled, +then you will need to set an [app password](https://myaccount.google.com/apppasswords) and use that instead of your regular password. Alternatively, you can use another ESP to send email by replacing 'smtp.gmail.com' above with the address of your provider. Mailer Testing diff --git a/guides/source/action_view_overview.md b/guides/source/action_view_overview.md index c835adeab6..10412128cc 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -419,7 +419,7 @@ image_tag("rails.png") # => <img src="http://assets.example.com/images/rails.png #### auto_discovery_link_tag -Returns a link tag that browsers and feed readers can use to auto-detect an RSS or Atom feed. +Returns a link tag that browsers and feed readers can use to auto-detect an RSS, Atom, or JSON feed. ```ruby auto_discovery_link_tag(:rss, "http://www.example.com/feed.rss", { title: "RSS Feed" }) # => diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md index b58ca61848..443be77934 100644 --- a/guides/source/active_job_basics.md +++ b/guides/source/active_job_basics.md @@ -310,6 +310,12 @@ UserMailer.welcome(@user).deliver_now UserMailer.welcome(@user).deliver_later ``` +NOTE: Using the asynchronous queue from a Rake task (for example, to +send an email using `.deliver_later`) will generally not work because Rake will +likely end, causing the in-process thread pool to be deleted, before any/all +of the `.deliver_later` emails are processed. To avoid this problem, use +`.deliver_now` or run a persistent queue in development. + Internationalization -------------------- diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 26d01d4ede..aea7515974 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -118,7 +118,7 @@ You can also use this method to query for multiple objects. Call the `find` meth ```ruby # Find the clients with primary keys 1 and 10. -client = Client.find([1, 10]) # Or even Client.find(1, 10) +clients = Client.find([1, 10]) # Or even Client.find(1, 10) # => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10, first_name: "Ryan">] ``` @@ -150,7 +150,7 @@ The `take` method returns `nil` if no record is found and no exception will be r You can pass in a numerical argument to the `take` method to return up to that number of results. For example ```ruby -client = Client.take(2) +clients = Client.take(2) # => [ # #<Client id: 1, first_name: "Lifo">, # #<Client id: 220, first_name: "Sara"> @@ -189,7 +189,7 @@ If your [default scope](active_record_querying.html#applying-a-default-scope) co You can pass in a numerical argument to the `first` method to return up to that number of results. For example ```ruby -client = Client.first(3) +clients = Client.first(3) # => [ # #<Client id: 1, first_name: "Lifo">, # #<Client id: 2, first_name: "Fifo">, @@ -240,7 +240,7 @@ If your [default scope](active_record_querying.html#applying-a-default-scope) co You can pass in a numerical argument to the `last` method to return up to that number of results. For example ```ruby -client = Client.last(3) +clients = Client.last(3) # => [ # #<Client id: 219, first_name: "James">, # #<Client id: 220, first_name: "Sara">, @@ -557,6 +557,19 @@ In other words, this query can be generated by calling `where` with no argument, SELECT * FROM clients WHERE (clients.locked != 1) ``` +### OR Conditions + +`OR` condition between two relations can be build by calling `or` on the first relation +and passing the second one as an argument. + +```ruby +Client.where(locked: true).or(Client.where(orders_count: [1,3,5])) +``` + +```sql +SELECT * FROM clients WHERE (clients.locked = 1 OR clients.orders_count IN (1,3,5)) +``` + Ordering -------- diff --git a/guides/source/api_app.md b/guides/source/api_app.md index f373d313cc..64200ec242 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -206,16 +206,17 @@ An API application comes with the following middleware by default: - `ActiveSupport::Cache::Strategy::LocalCache::Middleware` - `Rack::Runtime` - `ActionDispatch::RequestId` +- `ActionDispatch::RemoteIp` - `Rails::Rack::Logger` - `ActionDispatch::ShowExceptions` - `ActionDispatch::DebugExceptions` -- `ActionDispatch::RemoteIp` - `ActionDispatch::Reloader` - `ActionDispatch::Callbacks` - `ActiveRecord::Migration::CheckPending` - `Rack::Head` - `Rack::ConditionalGet` - `Rack::ETag` +- `MyApi::Application::Routes` See the [internal middleware](rails_on_rack.html#internal-middleware-stack) section of the Rack guide for further information on them. @@ -360,7 +361,7 @@ middleware set, you can remove it with: config.middleware.delete ::Rack::Sendfile ``` -Keep in mind that removing these middleware will remove support for certain +Keep in mind that removing these middlewares will remove support for certain features in Action Controller. Choosing Controller Modules @@ -385,8 +386,9 @@ controller modules by default: hooks defined by Action Controller (see [the instrumentation guide](active_support_instrumentation.html#action-controller) for more information regarding this). -- `ActionController::ParamsWrapper`: Wraps the parameters hash into a nested hash, +- `ActionController::ParamsWrapper`: Wraps the parameters hash into a nested hash, so that you don't have to specify root elements sending POST requests for instance. +- `ActionController::Head`: Support for returning a response with no content, only headers Other plugins may add additional modules. You can get a list of all modules included into `ActionController::API` in the rails console: @@ -394,12 +396,12 @@ 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, +=> [ActionController::API, + ActiveRecord::Railties::ControllerRuntime, + ActionDispatch::Routing::RouteSet::MountedHelpers, + ActionController::ParamsWrapper, + ... , + AbstractController::Rendering, ActionView::ViewPaths] ``` diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index 3c61754982..c3c7367304 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -281,7 +281,7 @@ Methods created with `(module|class)_eval(STRING)` have a comment by their side ```ruby for severity in Severity.constants - class_eval <<-EOT, __FILE__, __LINE__ + class_eval <<-EOT, __FILE__, __LINE__ + 1 def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block) add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block) end # end diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 5794bfa666..5c7d1f5365 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -599,7 +599,7 @@ class CreateBooks < ActiveRecord::Migration[5.0] t.string :book_number t.integer :author_id end - + add_index :books, :author_id add_foreign_key :books, :authors end @@ -1417,7 +1417,7 @@ If either of these saves fails due to validation errors, then the assignment sta If the parent object (the one declaring the `has_one` association) is unsaved (that is, `new_record?` returns `true`) then the child objects are not saved. They will automatically when the parent object is saved. -If you want to assign an object to a `has_one` association without saving the object, use the `association.build` method. +If you want to assign an object to a `has_one` association without saving the object, use the `build_association` method. ### `has_many` Association Reference @@ -1559,7 +1559,7 @@ The `collection.size` method returns the number of objects in the collection. The `collection.find` method finds objects within the collection. It uses the same syntax and options as `ActiveRecord::Base.find`. ```ruby -@available_books = @author.books.find(1) +@available_book = @author.books.find(1) ``` ##### `collection.where(...)` diff --git a/guides/source/configuring.md b/guides/source/configuring.md index bf9456a482..6a7eaf00e1 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -456,10 +456,14 @@ to `'http authentication'`. Defaults to `'signed cookie'`. * `config.action_dispatch.encrypted_cookie_salt` sets the encrypted cookies salt -value. Defaults to `'encrypted cookie'`. + value. Defaults to `'encrypted cookie'`. * `config.action_dispatch.encrypted_signed_cookie_salt` sets the signed -encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. + encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. + +* `config.action_dispatch.authenticated_encrypted_cookie_salt` sets the + authenticated encrypted cookie salt. Defaults to `'authenticated 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) diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 39f4272b3c..2f2962a3e6 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -141,14 +141,15 @@ NOTE: To help our CI servers you should add [ci skip] to your documentation comm Translating Rails Guides ------------------------ -We are happy to have people volunteer to translate the Rails guides into their own language. -If you want to translate the Rails guides in your own language, follows these steps: +We are happy to have people volunteer to translate the Rails guides. Just follow these steps: -* Fork the project (rails/rails). +* Fork https://github.com/rails/rails. * Add a source folder for your own language, for example: *guides/source/it-IT* for Italian. * Copy the contents of *guides/source* into your own language directory and translate them. * Do NOT translate the HTML files, as they are automatically generated. +Note that translations are not submitted to the Rails repository. As detailed above, your work happens in a fork. This is so because in practice documentation maintenance via patches is only sustainable in English. + To generate the guides in HTML format cd into the *guides* directory then run (eg. for it-IT): ```bash diff --git a/guides/source/generators.md b/guides/source/generators.md index a554e08204..d4ed2355d4 100644 --- a/guides/source/generators.md +++ b/guides/source/generators.md @@ -96,7 +96,7 @@ This is the generator just created: ```ruby class InitializerGenerator < Rails::Generators::NamedBase - source_root File.expand_path("../templates", __FILE__) + source_root File.expand_path("templates", __dir__) end ``` @@ -122,7 +122,7 @@ And now let's change the generator to copy this template when invoked: ```ruby class InitializerGenerator < Rails::Generators::NamedBase - source_root File.expand_path("../templates", __FILE__) + source_root File.expand_path("templates", __dir__) def copy_initializer_file copy_file "initializer.rb", "config/initializers/#{file_name}.rb" diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index f3ae5a5b28..5553f08456 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -20,16 +20,7 @@ Guide Assumptions This guide is designed for beginners who want to get started with a Rails application from scratch. It does not assume that you have any prior experience -with Rails. However, to get the most out of it, you need to have some -prerequisites installed: - -* The [Ruby](https://www.ruby-lang.org/en/downloads) language version 2.2.2 or newer. -* Right version of [Development Kit](http://rubyinstaller.org/downloads/), if you - are using Windows. -* The [RubyGems](https://rubygems.org) packaging system, which is installed with - Ruby by default. To learn more about RubyGems, please read the - [RubyGems Guides](http://guides.rubygems.org). -* A working installation of the [SQLite3 Database](https://www.sqlite.org). +with Rails. Rails is a web application framework running on the Ruby programming language. If you have no prior experience with Ruby, you will find a very steep learning @@ -86,6 +77,9 @@ your prompt will look something like `c:\source_code>` ### Installing Rails +Before you install Rails, you should check to make sure that your system has the +proper prerequisites installed. These include Ruby and SQLite3. + Open up a command line prompt. On macOS open Terminal.app, on Windows choose "Run" from your Start menu and type 'cmd.exe'. Any commands prefaced with a dollar sign `$` should be run in the command line. Verify that you have a @@ -96,12 +90,19 @@ $ ruby -v ruby 2.3.1p112 ``` +Rails requires Ruby version 2.2.2 or later. If the version number returned is +less than that number, you'll need to install a fresh copy of Ruby. + TIP: A number of tools exist to help you quickly install Ruby and Ruby on Rails on your system. Windows users can use [Rails Installer](http://railsinstaller.org), while macOS users can use [Tokaido](https://github.com/tokaido/tokaidoapp). For more installation methods for most Operating Systems take a look at [ruby-lang.org](https://www.ruby-lang.org/en/documentation/installation/). +If you are working on Windows, you should also install the +[Ruby Installer Development Kit](http://rubyinstaller.org/downloads/). + +You will also need an installation of the SQLite3 database. Many popular UNIX-like OSes ship with an acceptable version of SQLite3. On Windows, if you installed Rails through Rails Installer, you already have SQLite installed. Others can find installation instructions @@ -127,7 +128,7 @@ run the following: $ rails --version ``` -If it says something like "Rails 5.1.0", you are ready to continue. +If it says something like "Rails 5.1.1", you are ready to continue. ### Creating the Blog Application @@ -1195,7 +1196,7 @@ it look as follows: This time we point the form to the `update` action, which is not defined yet but will be very soon. -Passing the article object to the method, will automagically create url for submitting the edited article form. +Passing the article object to the method, will automagically create url for submitting the edited article form. This option tells Rails that we want this form to be submitted via the `PATCH` HTTP method which is the HTTP method you're expected to use to **update** resources according to the REST protocol. diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index 48bb3147f3..caa3d21d23 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -768,7 +768,7 @@ WARNING: The asset tag helpers do _not_ verify the existence of the assets at th #### Linking to Feeds with the `auto_discovery_link_tag` -The `auto_discovery_link_tag` helper builds HTML that most browsers and feed readers can use to detect the presence of RSS or Atom feeds. It takes the type of the link (`:rss` or `:atom`), a hash of options that are passed through to url_for, and a hash of options for the tag: +The `auto_discovery_link_tag` helper builds HTML that most browsers and feed readers can use to detect the presence of RSS, Atom, or JSON feeds. It takes the type of the link (`:rss`, `:atom`, or `:json`), a hash of options that are passed through to url_for, and a hash of options for the tag: ```erb <%= auto_discovery_link_tag(:rss, {action: "feed"}, diff --git a/guides/source/nested_model_forms.md b/guides/source/nested_model_forms.md deleted file mode 100644 index 71efa4b0d0..0000000000 --- a/guides/source/nested_model_forms.md +++ /dev/null @@ -1,230 +0,0 @@ -**DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** - -Rails Nested Model Forms -======================== - -Creating a form for a model _and_ its associations can become quite tedious. Therefore Rails provides helpers to assist in dealing with the complexities of generating these forms _and_ the required CRUD operations to create, update, and destroy associations. - -After reading this guide, you will know: - -* do stuff. - --------------------------------------------------------------------------------- - -NOTE: This guide assumes the user knows how to use the [Rails form helpers](form_helpers.html) in general. Also, it's **not** an API reference. For a complete reference please visit [the Rails API documentation](http://api.rubyonrails.org/). - - -Model setup ------------ - -To be able to use the nested model functionality in your forms, the model will need to support some basic operations. - -First of all, it needs to define a writer method for the attribute that corresponds to the association you are building a nested model form for. The `fields_for` form helper will look for this method to decide whether or not a nested model form should be built. - -If the associated object is an array, a form builder will be yielded for each object, else only a single form builder will be yielded. - -Consider a Person model with an associated Address. When asked to yield a nested FormBuilder for the `:address` attribute, the `fields_for` form helper will look for a method on the Person instance named `address_attributes=`. - -### ActiveRecord::Base model - -For an ActiveRecord::Base model and association this writer method is commonly defined with the `accepts_nested_attributes_for` class method: - -#### has_one - -```ruby -class Person < ApplicationRecord - has_one :address - accepts_nested_attributes_for :address -end -``` - -#### belongs_to - -```ruby -class Person < ApplicationRecord - belongs_to :firm - accepts_nested_attributes_for :firm -end -``` - -#### has_many / has_and_belongs_to_many - -```ruby -class Person < ApplicationRecord - has_many :projects - accepts_nested_attributes_for :projects -end -``` - -NOTE: For greater detail on associations see [Active Record Associations](association_basics.html). -For a complete reference on associations please visit the API documentation for [ActiveRecord::Associations::ClassMethods](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html). - -### Custom model - -As you might have inflected from this explanation, you _don't_ necessarily need an ActiveRecord::Base model to use this functionality. The following examples are sufficient to enable the nested model form behavior: - -#### Single associated object - -```ruby -class Person - def address - Address.new - end - - def address_attributes=(attributes) - # ... - end -end -``` - -#### Association collection - -```ruby -class Person - def projects - [Project.new, Project.new] - end - - def projects_attributes=(attributes) - # ... - end -end -``` - -NOTE: See (TODO) in the advanced section for more information on how to deal with the CRUD operations in your custom model. - -Views ------ - -### Controller code - -A nested model form will _only_ be built if the associated object(s) exist. This means that for a new model instance you would probably want to build the associated object(s) first. - -Consider the following typical RESTful controller which will prepare a new Person instance and its `address` and `projects` associations before rendering the `new` template: - -```ruby -class PeopleController < ApplicationController - def new - @person = Person.new - @person.build_address - 2.times { @person.projects.build } - end - - def create - @person = Person.new(params[:person]) - if @person.save - # ... - end - end -end -``` - -NOTE: Obviously the instantiation of the associated object(s) can become tedious and not DRY, so you might want to move that into the model itself. ActiveRecord::Base provides an `after_initialize` callback which is a good way to refactor this. - -### Form code - -Now that you have a model instance, with the appropriate methods and associated object(s), you can start building the nested model form. - -#### Standard form - -Start out with a regular RESTful form: - -```erb -<%= form_for @person do |f| %> - <%= f.text_field :name %> -<% end %> -``` - -This will generate the following html: - -```html -<form action="/people" class="new_person" id="new_person" method="post"> - <input id="person_name" name="person[name]" type="text" /> -</form> -``` - -#### Nested form for a single associated object - -Now add a nested form for the `address` association: - -```erb -<%= form_for @person do |f| %> - <%= f.text_field :name %> - - <%= f.fields_for :address do |af| %> - <%= af.text_field :street %> - <% end %> -<% end %> -``` - -This generates: - -```html -<form action="/people" class="new_person" id="new_person" method="post"> - <input id="person_name" name="person[name]" type="text" /> - - <input id="person_address_attributes_street" name="person[address_attributes][street]" type="text" /> -</form> -``` - -Notice that `fields_for` recognized the `address` as an association for which a nested model form should be built by the way it has namespaced the `name` attribute. - -When this form is posted the Rails parameter parser will construct a hash like the following: - -```ruby -{ - "person" => { - "name" => "Eloy Duran", - "address_attributes" => { - "street" => "Nieuwe Prinsengracht" - } - } -} -``` - -That's it. The controller will simply pass this hash on to the model from the `create` action. The model will then handle building the `address` association for you and automatically save it when the parent (`person`) is saved. - -#### Nested form for a collection of associated objects - -The form code for an association collection is pretty similar to that of a single associated object: - -```erb -<%= form_for @person do |f| %> - <%= f.text_field :name %> - - <%= f.fields_for :projects do |pf| %> - <%= pf.text_field :name %> - <% end %> -<% end %> -``` - -Which generates: - -```html -<form action="/people" class="new_person" id="new_person" method="post"> - <input id="person_name" name="person[name]" type="text" /> - - <input id="person_projects_attributes_0_name" name="person[projects_attributes][0][name]" type="text" /> - <input id="person_projects_attributes_1_name" name="person[projects_attributes][1][name]" type="text" /> -</form> -``` - -As you can see it has generated 2 `project name` inputs, one for each new `project` that was built in the controller's `new` action. Only this time the `name` attribute of the input contains a digit as an extra namespace. This will be parsed by the Rails parameter parser as: - -```ruby -{ - "person" => { - "name" => "Eloy Duran", - "projects_attributes" => { - "0" => { "name" => "Project 1" }, - "1" => { "name" => "Project 2" } - } - } -} -``` - -You can basically see the `projects_attributes` hash as an array of attribute hashes, one for each model instance. - -NOTE: The reason that `fields_for` constructed a hash instead of an array is that it won't work for any form nested deeper than one level deep. - -TIP: You _can_ however pass an array to the writer method generated by `accepts_nested_attributes_for` if you're using plain Ruby or some other API access. See (TODO) for more info and example. diff --git a/guides/source/profiling.md b/guides/source/profiling.md deleted file mode 100644 index ce093f78ba..0000000000 --- a/guides/source/profiling.md +++ /dev/null @@ -1,16 +0,0 @@ -*DO NOT READ THIS FILE ON GITHUB, GUIDES ARE PUBLISHED ON http://guides.rubyonrails.org.** - -A Guide to Profiling Rails Applications -======================================= - -This guide covers built-in mechanisms in Rails for profiling your application. - -After reading this guide, you will know: - -* Rails profiling terminology. -* How to write benchmark tests for your application. -* Other benchmarking approaches and plugins. - --------------------------------------------------------------------------------- - - diff --git a/guides/source/rails_application_templates.md b/guides/source/rails_application_templates.md index 3e99ee7021..e087834a2f 100644 --- a/guides/source/rails_application_templates.md +++ b/guides/source/rails_application_templates.md @@ -277,6 +277,6 @@ relative paths to your template's location. ```ruby def source_paths - [File.expand_path(File.dirname(__FILE__))] + [__dir__] end ``` diff --git a/guides/source/rails_on_rack.md b/guides/source/rails_on_rack.md index f25b185fb5..cef8450ee4 100644 --- a/guides/source/rails_on_rack.md +++ b/guides/source/rails_on_rack.md @@ -110,11 +110,12 @@ use ActiveSupport::Cache::Strategy::LocalCache::Middleware use Rack::Runtime use Rack::MethodOverride use ActionDispatch::RequestId +use ActionDispatch::RemoteIp +use Sprockets::Rails::QuietAssets use Rails::Rack::Logger use ActionDispatch::ShowExceptions use WebConsole::Middleware use ActionDispatch::DebugExceptions -use ActionDispatch::RemoteIp use ActionDispatch::Reloader use ActionDispatch::Callbacks use ActiveRecord::Migration::CheckPending @@ -124,7 +125,7 @@ use ActionDispatch::Flash use Rack::Head use Rack::ConditionalGet use Rack::ETag -run Rails.application.routes +run MyApp.application.routes ``` The default middlewares shown here (and some others) are each summarized in the [Internal Middlewares](#internal-middleware-stack) section, below. @@ -238,6 +239,14 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol * Makes a unique `X-Request-Id` header available to the response and enables the `ActionDispatch::Request#request_id` method. +**`ActionDispatch::RemoteIp`** + +* Checks for IP spoofing attacks. + +**`Sprockets::Rails::QuietAssets`** + +* Suppresses logger output for asset requests. + **`Rails::Rack::Logger`** * Notifies the logs that the request has began. After request is complete, flushes all the logs. @@ -250,10 +259,6 @@ Much of Action Controller's functionality is implemented as Middlewares. The fol * Responsible for logging exceptions and showing a debugging page in case the request is local. -**`ActionDispatch::RemoteIp`** - -* Checks for IP spoofing attacks. - **`ActionDispatch::Reloader`** * Provides prepare and cleanup callbacks, intended to assist with code reloading during development. diff --git a/guides/source/security.md b/guides/source/security.md index c305350243..f69a0c72b0 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -95,16 +95,23 @@ Rails 2 introduced a new default session storage, CookieStore. CookieStore saves * The client can see everything you store in a session, because it is stored in clear-text (actually Base64-encoded, so not encrypted). So, of course, _you don't want to store any secrets here_. To prevent session hash tampering, a digest is calculated from the session with a server-side secret (`secrets.secret_token`) and inserted into the end of the cookie. -However, since Rails 4, the default store is EncryptedCookieStore. With -EncryptedCookieStore the session is encrypted before being stored in a cookie. -This prevents the user from accessing and tampering the content of the cookie. -Thus the session becomes a more secure place to store data. The encryption is -done using a server-side secret key `secrets.secret_key_base` stored in -`config/secrets.yml`. +In Rails 4, encrypted cookies through AES in CBC mode with HMAC using SHA1 for +verification was introduced. This prevents the user from accessing and tampering +the content of the cookie. Thus the session becomes a more secure place to store +data. The encryption is performed using a server-side `secrets.secret_key_base`. +Two salts are used when deriving keys for encryption and verification. These +salts are set via the `config.action_dispatch.encrypted_cookie_salt` and +`config.action_dispatch.encrypted_signed_cookie_salt` configuration values. -That means the security of this storage depends on this secret (and on the digest algorithm, which defaults to SHA1, for compatibility). So _don't use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters, use `rails secret` instead_. +Rails 5.2 uses AES-GCM for the encryption which couples authentication +and encryption in one faster step and produces shorter ciphertexts. -`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`, e.g.: +Encrypted cookies are automatically upgraded if the +`config.action_dispatch.use_authenticated_cookie_encryption` is enabled. + +_Do not use a trivial secret, i.e. a word from a dictionary, or one which is shorter than 30 characters! Instead use `rails secret` to generate secret keys!_ + +Applications get `secrets.secret_key_base` initialized to a random key present in `config/secrets.yml`, e.g.: development: secret_key_base: a75d... @@ -356,7 +363,7 @@ send_file('/var/www/uploads/' + params[:filename]) Simply pass a file name like "../../../etc/passwd" to download the server's login information. A simple solution against this, is to _check that the requested file is in the expected directory_: ```ruby -basename = File.expand_path(File.join(File.dirname(__FILE__), '../../files')) +basename = File.expand_path('../../files', __dir__) filename = File.expand_path(File.join(basename, @file.public_filename)) raise if basename != File.expand_path(File.join(File.dirname(filename), '../../../')) @@ -796,7 +803,7 @@ In December 2006, 34,000 actual user names and passwords were stolen in a [MySpa INFO: _CSS Injection is actually JavaScript injection, because some browsers (IE, some versions of Safari and others) allow JavaScript in CSS. Think twice about allowing custom CSS in your web application._ -CSS Injection is explained best by the well-known [MySpace Samy worm](http://namb.la/popular/tech.html). This worm automatically sent a friend request to Samy (the attacker) simply by visiting his profile. Within several hours he had over 1 million friend requests, which created so much traffic that MySpace went offline. The following is a technical explanation of that worm. +CSS Injection is explained best by the well-known [MySpace Samy worm](https://samy.pl/popular/tech.html). This worm automatically sent a friend request to Samy (the attacker) simply by visiting his profile. Within several hours he had over 1 million friend requests, which created so much traffic that MySpace went offline. The following is a technical explanation of that worm. MySpace blocked many tags, but allowed CSS. So the worm's author put JavaScript into CSS like this: diff --git a/guides/source/testing.md b/guides/source/testing.md index ced88e888c..c0394f927e 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -610,9 +610,9 @@ For creating Rails system tests, you use the `test/system` directory in your application. Rails provides a generator to create a system test skeleton for you. ```bash -$ bin/rails generate system_test users_create +$ bin/rails generate system_test users invoke test_unit - create test/system/users_creates_test.rb + create test/system/users_test.rb ``` Here's what a freshly-generated system test looks like: @@ -620,11 +620,11 @@ Here's what a freshly-generated system test looks like: ```ruby require "application_system_test_case" -class UsersCreatesTest < ApplicationSystemTestCase +class UsersTest < ApplicationSystemTestCase # test "visiting the index" do - # visit users_creates_url + # visit users_url # - # assert_selector "h1", text: "UsersCreate" + # assert_selector "h1", text: "Users" # end end ``` @@ -658,8 +658,8 @@ end The driver name is a required argument for `driven_by`. The optional arguments that can be passed to `driven_by` are `:using` for the browser (this will only -be used for non-headless drivers like Selenium), and `:screen_size` to change -the size of the screen for screenshots. +be used by Selenium), and `:screen_size` to change the size of the screen for +screenshots. ```ruby require "test_helper" diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index cf08c5dd1d..290f2a509b 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -250,7 +250,7 @@ Since it's just a `<form>`, all of the information on `form_with` also applies. ### Customize remote elements It is possible to customize the behavior of elements with a `data-remote` -attribute without writing a line of JavaScript. Your can specify extra `data-` +attribute without writing a line of JavaScript. You can specify extra `data-` attributes to accomplish this. #### `data-method` |