diff options
author | Vijay Dev <vijaydev.cse@gmail.com> | 2015-08-24 06:05:07 +0000 |
---|---|---|
committer | Vijay Dev <vijaydev.cse@gmail.com> | 2015-08-24 06:05:07 +0000 |
commit | 4f252cddc1ee4e28c633a2250335b2fac4d31108 (patch) | |
tree | 776177555c7039204e23c9c1b7d33b700d366ca3 /guides | |
parent | bc36ffeec05692777f4ece09978a321feed2d818 (diff) | |
parent | 06818cb9a8cee8c95eaebdd1418e6fcb0da9382e (diff) | |
download | rails-4f252cddc1ee4e28c633a2250335b2fac4d31108.tar.gz rails-4f252cddc1ee4e28c633a2250335b2fac4d31108.tar.bz2 rails-4f252cddc1ee4e28c633a2250335b2fac4d31108.zip |
Merge branch 'master' of github.com:rails/rails
Conflicts:
guides/source/security.md
Diffstat (limited to 'guides')
35 files changed, 699 insertions, 559 deletions
diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md index fd177b4238..09fb7b1a0e 100644 --- a/guides/CHANGELOG.md +++ b/guides/CHANGELOG.md @@ -1,3 +1,7 @@ +* Add code of conduct to contributing guide + + *Jon Moss* + * New section in Configuring: Configuring Active Job *Eliot Sykes* diff --git a/guides/Rakefile b/guides/Rakefile index 3c2099ac02..00577377d7 100644 --- a/guides/Rakefile +++ b/guides/Rakefile @@ -7,7 +7,7 @@ namespace :guides do desc "Generate HTML guides" task :html do - ENV["WARN_BROKEN_LINKS"] = "1" # authors can't disable this + ENV["WARNINGS"] = "1" # authors can't disable this ruby "rails_guides.rb" end diff --git a/guides/bug_report_templates/action_controller_gem.rb b/guides/bug_report_templates/action_controller_gem.rb index 11561c55f9..58ba708a39 100644 --- a/guides/bug_report_templates/action_controller_gem.rb +++ b/guides/bug_report_templates/action_controller_gem.rb @@ -32,7 +32,7 @@ class TestController < ActionController::Base include Rails.application.routes.url_helpers def index - render text: 'Home' + render plain: 'Home' end end diff --git a/guides/bug_report_templates/action_controller_master.rb b/guides/bug_report_templates/action_controller_master.rb index 66887398b9..31a3f6c650 100644 --- a/guides/bug_report_templates/action_controller_master.rb +++ b/guides/bug_report_templates/action_controller_master.rb @@ -9,6 +9,7 @@ gemfile(true) do source 'https://rubygems.org' gem 'rails', github: 'rails/rails' gem 'arel', github: 'rails/arel' + gem 'rack', github: 'rack/rack' end require 'action_controller/railtie' @@ -31,7 +32,7 @@ class TestController < ActionController::Base include Rails.application.routes.url_helpers def index - render text: 'Home' + render plain: 'Home' end end diff --git a/guides/bug_report_templates/active_record_master.rb b/guides/bug_report_templates/active_record_master.rb index 270dbe7df7..6ae50b2460 100644 --- a/guides/bug_report_templates/active_record_master.rb +++ b/guides/bug_report_templates/active_record_master.rb @@ -9,6 +9,7 @@ gemfile(true) do source 'https://rubygems.org' gem 'rails', github: 'rails/rails' gem 'arel', github: 'rails/arel' + gem 'rack', github: 'rack/rack' gem 'sqlite3' end diff --git a/guides/bug_report_templates/generic_master.rb b/guides/bug_report_templates/generic_master.rb index b6b4562751..f6dce64280 100644 --- a/guides/bug_report_templates/generic_master.rb +++ b/guides/bug_report_templates/generic_master.rb @@ -9,6 +9,7 @@ gemfile(true) do source 'https://rubygems.org' gem 'rails', github: 'rails/rails' gem 'arel', github: 'rails/arel' + gem 'rack', github: 'rack/rack' end require 'active_support' diff --git a/guides/source/4_2_release_notes.md b/guides/source/4_2_release_notes.md index 684bd286bc..8a59007420 100644 --- a/guides/source/4_2_release_notes.md +++ b/guides/source/4_2_release_notes.md @@ -227,6 +227,17 @@ restore the old behavior. If you do this, be sure to configure your firewall properly such that only trusted machines on your network can access your development server. +### Changed status option symbols for `render` + +Due to a [change in Rack](https://github.com/rack/rack/commit/be28c6a2ac152fe4adfbef71f3db9f4200df89e8), the symbols that the `render` method accepts for the `:status` option have changed: + +- 306: `:reserved` has been removed. +- 413: `:request_entity_too_large` has been renamed to `:payload_too_large`. +- 414: `:request_uri_too_long` has been renamed to `:uri_too_long`. +- 416: `:requested_range_not_satisfiable` has been renamed to `:range_not_satisfiable`. + +Keep in mind that if calling `render` with an unknown symbol, the response status will default to 500. + ### HTML Sanitizer The HTML sanitizer has been replaced with a new, more robust, implementation diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md index 09fbdc0d32..d2173c39f6 100644 --- a/guides/source/action_controller_overview.md +++ b/guides/source/action_controller_overview.md @@ -1174,7 +1174,7 @@ end WARNING: You shouldn't do `rescue_from Exception` or `rescue_from StandardError` unless you have a particular reason as it will cause serious side-effects (e.g. you won't be able to see exception details and tracebacks during development). -NOTE: Certain exceptions are only rescuable from the `ApplicationController` class, as they are raised before the controller gets initialized and the action gets executed. See Pratik Naik's [article](http://m.onkey.org/2008/7/20/rescue-from-dispatching) on the subject for more information. +NOTE: Certain exceptions are only rescuable from the `ApplicationController` class, as they are raised before the controller gets initialized and the action gets executed. Force HTTPS protocol -------------------- diff --git a/guides/source/action_mailer_basics.md b/guides/source/action_mailer_basics.md index c31b50fcfc..c39cd34e9a 100644 --- a/guides/source/action_mailer_basics.md +++ b/guides/source/action_mailer_basics.md @@ -326,7 +326,7 @@ key. The list of emails can be an array of email addresses or a single string with the addresses separated by commas. ```ruby -class AdminMailer < ActionMailer::Base +class AdminMailer < ApplicationMailer default to: Proc.new { Admin.pluck(:email) }, from: 'notification@example.com' @@ -759,6 +759,9 @@ config.action_mailer.smtp_settings = { authentication: 'plain', 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 +use another ESP to send email by replacing 'smpt.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 98c6cbd540..00c41a480e 100644 --- a/guides/source/action_view_overview.md +++ b/guides/source/action_view_overview.md @@ -15,7 +15,7 @@ After reading this guide, you will know: What is Action View? -------------------- -Action View and Action Controller are the two major components of Action Pack. In Rails, web requests are handled by Action Pack, which splits the work into a controller part (performing the logic) and a view part (rendering a template). Typically, Action Controller will be concerned with communicating with the database and performing CRUD actions where necessary. Action View is then responsible for compiling the response. +In Rails, web requests are handled by [Action Controller](action_controller_overview.html) and Action View. Typically, Action Controller will be concerned with communicating with the database and performing CRUD actions where necessary. Action View is then responsible for compiling the response. Action View templates are written using embedded Ruby in tags mingled with HTML. To avoid cluttering the templates with boilerplate code, a number of helper classes provide common behavior for forms, dates, and strings. It's also easy to add new helpers to your application as it evolves. @@ -1443,12 +1443,12 @@ Sanitizes a block of CSS code. Strips all link tags from text leaving just the link text. ```ruby -strip_links("<a href="http://rubyonrails.org">Ruby on Rails</a>") +strip_links('<a href="http://rubyonrails.org">Ruby on Rails</a>') # => Ruby on Rails ``` ```ruby -strip_links("emails to <a href="mailto:me@email.com">me@email.com</a>.") +strip_links('emails to <a href="mailto:me@email.com">me@email.com</a>.') # => emails to me@email.com. ``` diff --git a/guides/source/active_job_basics.md b/guides/source/active_job_basics.md index dd545b56f5..e3502d7363 100644 --- a/guides/source/active_job_basics.md +++ b/guides/source/active_job_basics.md @@ -70,12 +70,14 @@ Here's what a job looks like: class GuestsCleanupJob < ActiveJob::Base queue_as :default - def perform(*args) + def perform(*guests) # Do something later end end ``` +Note that you can define `perform` with as many arguments as you want. + ### Enqueue the Job Enqueue a job like so: @@ -83,21 +85,26 @@ Enqueue a job like so: ```ruby # Enqueue a job to be performed as soon the queuing system is # free. -MyJob.perform_later record +GuestsCleanupJob.perform_later guest ``` ```ruby # Enqueue a job to be performed tomorrow at noon. -MyJob.set(wait_until: Date.tomorrow.noon).perform_later(record) +GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later(guest) ``` ```ruby # Enqueue a job to be performed 1 week from now. -MyJob.set(wait: 1.week).perform_later(record) +GuestsCleanupJob.set(wait: 1.week).perform_later(guest) ``` -That's it! +```ruby +# `perform_now` and `perform_later` will call `perform` under the hood so +# you can pass as many arguments as defined in the latter. +GuestsCleanupJob.perform_later(guest1, guest2, filter: 'some_filter') +``` +That's it! Job Execution ------------- @@ -280,6 +287,19 @@ UserMailer.welcome(@user).deliver_later ``` +Internationalization +-------------------- + +Each job uses the `I18n.locale` set when the job was created. Useful if you send +emails asynchronously: + +```ruby +I18n.locale = :eo + +UserMailer.welcome(@user).deliver_later # Email will be localized to Esparanto. +``` + + GlobalID -------- diff --git a/guides/source/active_model_basics.md b/guides/source/active_model_basics.md index 4b2bfaee2f..81e2a69504 100644 --- a/guides/source/active_model_basics.md +++ b/guides/source/active_model_basics.md @@ -8,12 +8,12 @@ classes. Active Model allows for Action Pack helpers to interact with plain Ruby objects. Active Model also helps build custom ORMs for use outside of the Rails framework. -After reading this guide, you will be able to add to plain Ruby objects: +After reading this guide, you will know: -* The ability to behave like an Active Record model. -* Callbacks and validations like Active Record. -* Serializers. -* Integration with the Rails internationalization (i18n) framework. +* How an Active Record model behaves. +* How Callbacks and validations work. +* How serializers work. +* The Rails internationalization (i18n) framework. -------------------------------------------------------------------------------- @@ -319,9 +319,8 @@ person.serializable_hash # => {"name"=>"Bob"} #### ActiveModel::Serializers -Rails provides two serializers `ActiveModel::Serializers::JSON` and -`ActiveModel::Serializers::Xml`. Both of these modules automatically include -the `ActiveModel::Serialization`. +Rails provides a `ActiveModel::Serializers::JSON` serializer. +This module automatically include the `ActiveModel::Serialization`. ##### ActiveModel::Serializers::JSON @@ -379,62 +378,6 @@ person.from_json(json) # => #<Person:0x00000100c773f0 @name="Bob"> person.name # => "Bob" ``` -##### ActiveModel::Serializers::Xml - -To use the `ActiveModel::Serializers::Xml` you only need to change from -`ActiveModel::Serialization` to `ActiveModel::Serializers::Xml`. - -```ruby -class Person - include ActiveModel::Serializers::Xml - - attr_accessor :name - - def attributes - {'name' => nil} - end -end -``` - -With the `to_xml` you have an XML representing the model. - -```ruby -person = Person.new -person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<person>\n <name nil=\"true\"/>\n</person>\n" -person.name = "Bob" -person.to_xml # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<person>\n <name>Bob</name>\n</person>\n" -``` - -From an XML string you define the attributes of the model. -You need to have the `attributes=` method defined on your class: - -```ruby -class Person - include ActiveModel::Serializers::Xml - - attr_accessor :name - - def attributes=(hash) - hash.each do |key, value| - send("#{key}=", value) - end - end - - def attributes - {'name' => nil} - end -end -``` - -Now it is possible to create an instance of person and set the attributes using `from_xml`. - -```ruby -xml = { name: 'Bob' }.to_xml -person = Person.new -person.from_xml(xml) # => #<Person:0x00000100c773f0 @name="Bob"> -person.name # => "Bob" -``` - ### Translation `ActiveModel::Translation` provides integration between your object and the Rails diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index a227b54040..dafbe17bbd 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -142,7 +142,7 @@ end This will create a `Product` model, mapped to a `products` table at the database. By doing this you'll also have the ability to map the columns of each row in that table with the attributes of the instances of your model. Suppose -that the `products` table was created using an SQL sentence like: +that the `products` table was created using an SQL statement like: ```sql CREATE TABLE products ( @@ -260,7 +260,7 @@ david = User.find_by(name: 'David') ```ruby # find all users named David who are Code Artists and sort by created_at in reverse chronological order -users = User.where(name: 'David', occupation: 'Code Artist').order('created_at DESC') +users = User.where(name: 'David', occupation: 'Code Artist').order(created_at: :desc) ``` You can learn more about querying an Active Record model in the [Active Record diff --git a/guides/source/active_record_migrations.md b/guides/source/active_record_migrations.md index ce605c912e..4e5902fb3d 100644 --- a/guides/source/active_record_migrations.md +++ b/guides/source/active_record_migrations.md @@ -357,8 +357,8 @@ will append `ENGINE=BLACKHOLE` to the SQL statement used to create the table ### Creating a Join Table -Migration method `create_join_table` creates an HABTM join table. A typical use -would be: +The migration method `create_join_table` creates an HABTM (has and belongs to +many) join table. A typical use would be: ```ruby create_join_table :products, :categories @@ -367,23 +367,21 @@ create_join_table :products, :categories which creates a `categories_products` table with two columns called `category_id` and `product_id`. These columns have the option `:null` set to `false` by default. This can be overridden by specifying the `:column_options` -option. +option: ```ruby -create_join_table :products, :categories, column_options: {null: true} +create_join_table :products, :categories, column_options: { null: true } ``` -will create the `product_id` and `category_id` with the `:null` option as -`true`. - -You can pass the option `:table_name` when you want to customize the table -name. For example: +By default, the name of the join table comes from the union of the first two +arguments provided to create_join_table, in alphabetical order. +To customize the name of the table, provide a `:table_name` option: ```ruby create_join_table :products, :categories, table_name: :categorization ``` -will create a `categorization` table. +creates a `categorization` table. `create_join_table` also accepts a block, which you can use to add indices (which are not created by default) or additional columns: @@ -1006,7 +1004,10 @@ such features, the `execute` method can be used to execute arbitrary SQL. Migrations and Seed Data ------------------------ -Some people use migrations to add data to the database: +The main purpose of Rails' migration feature is to issue commands that modify the +schema using a consistent process. Migrations can also be used +to add or modify data. This is useful in an existing database that can't be destroyed +and recreated, such as a production database. ```ruby class AddInitialProducts < ActiveRecord::Migration @@ -1022,9 +1023,11 @@ class AddInitialProducts < ActiveRecord::Migration end ``` -However, Rails has a 'seeds' feature that should be used for seeding a database -with initial data. It's a really simple feature: just fill up `db/seeds.rb` -with some Ruby code, and run `rake db:seed`: +To add initial data after a database is created, Rails has a built-in +'seeds' feature that makes the process quick and easy. This is especially +useful when reloading the database frequently in development and test environments. +It's easy to get started with this feature: just fill up `db/seeds.rb` with some +Ruby code, and run `rake db:seed`: ```ruby 5.times do |i| diff --git a/guides/source/active_record_postgresql.md b/guides/source/active_record_postgresql.md index fe112a4708..9d495dfacb 100644 --- a/guides/source/active_record_postgresql.md +++ b/guides/source/active_record_postgresql.md @@ -252,7 +252,7 @@ extension to use uuid. ```ruby # db/migrate/20131220144913_create_revisions.rb create_table :revisions do |t| - t.column :identifier, :uuid + t.uuid :identifier end # app/models/revision.rb diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index e3cfabb327..4b4d70d3ce 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -1266,6 +1266,18 @@ class Client < ActiveRecord::Base end ``` +NOTE: The `default_scope` is also applied while creating/building a record. +It is not applied while updating a record. E.g.: + +```ruby +class Client < ActiveRecord::Base + default_scope { where(active: true) } +end + +Client.new # => #<Client id: nil, active: true> +Client.unscoped.new # => #<Client id: nil, active: nil> +``` + ### Merging of scopes Just like `where` clauses scopes are merged using `AND` conditions. diff --git a/guides/source/active_support_instrumentation.md b/guides/source/active_support_instrumentation.md index e49abc41f4..cd44c685ba 100644 --- a/guides/source/active_support_instrumentation.md +++ b/guides/source/active_support_instrumentation.md @@ -244,14 +244,6 @@ INFO. The adapters will add their own data as well. } ``` -### identity.active_record - -| Key | Value | -| ---------------- | ----------------------------------------- | -| `:line` | Primary Key of object in the identity map | -| `:name` | Record's class | -| `:connection_id` | `self.object_id` | - ### instantiation.active_record | Key | Value | diff --git a/guides/source/api_documentation_guidelines.md b/guides/source/api_documentation_guidelines.md index 46c9013087..a4feff798d 100644 --- a/guides/source/api_documentation_guidelines.md +++ b/guides/source/api_documentation_guidelines.md @@ -84,6 +84,11 @@ English Please use American English (*color*, *center*, *modularize*, etc). See [a list of American and British English spelling differences here](http://en.wikipedia.org/wiki/American_and_British_English_spelling_differences). +Comma +------- + +Please use the Oxford comma (*red, white, and blue* style). See [the detail of Oxford comma](http://en.wikipedia.org/wiki/Serial_comma). + Example Code ------------ diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 4a610e8458..7b8d2d3aef 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -403,13 +403,13 @@ When using the asset pipeline, paths to assets must be re-written and underscored in Ruby) for the following asset classes: image, font, video, audio, JavaScript and stylesheet. -* `image-url("rails.png")` becomes `url(/assets/rails.png)` -* `image-path("rails.png")` becomes `"/assets/rails.png"`. +* `image-url("rails.png")` returns `url(/assets/rails.png)` +* `image-path("rails.png")` returns `"/assets/rails.png"` The more generic form can also be used: -* `asset-url("rails.png")` becomes `url(/assets/rails.png)` -* `asset-path("rails.png")` becomes `"/assets/rails.png"` +* `asset-url("rails.png")` returns `url(/assets/rails.png)` +* `asset-path("rails.png")` returns `"/assets/rails.png"` #### JavaScript/CoffeeScript and ERB diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index c0fa3cfd04..1191f5edfe 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -622,6 +622,19 @@ end We pass `id: false` to `create_table` because that table does not represent a model. That's required for the association to work properly. If you observe any strange behavior in a `has_and_belongs_to_many` association like mangled model IDs, or exceptions about conflicting IDs, chances are you forgot that bit. +You can also use the method `create_join_table` + +```ruby +class CreateAssembliesPartsJoinTable < ActiveRecord::Migration + def change + create_join_table :assemblies, :parts do |t| + t.index :assembly_id + t.index :part_id + end + end +end +``` + ### Controlling Association Scope By default, associations look for objects only within the current module's scope. This can be important when you declare Active Record models within a module. For example: diff --git a/guides/source/caching_with_rails.md b/guides/source/caching_with_rails.md index b0103c9af4..9a56233e4a 100644 --- a/guides/source/caching_with_rails.md +++ b/guides/source/caching_with_rails.md @@ -3,12 +3,24 @@ Caching with Rails: An Overview =============================== -This guide is an introduction to speeding up your Rails app with caching. +This guide is an introduction to speeding up your Rails application with caching. + +Caching means to store content generated during the request-response cycle and +to reuse it when responding to similar requests. + +Caching is often the most effective way to boost an application's performance. +Through caching, web sites running on a single server with a single database +can sustain a load of thousands of concurrent users. + +Rails provides a set of caching features out of the box. This guide will teach +you the scope and purpose of each one of them. Master these techniques and your +Rails applications can serve millions of views without exorbitant response times +or server bills. After reading this guide, you will know: -* Page and action caching. * Fragment and Russian doll caching. +* How to manage the caching dependencies. * Alternative cache stores. * Conditional GET support. @@ -31,6 +43,11 @@ the relevant `config/environments/*.rb` file: config.action_controller.perform_caching = true ``` +NOTE: Changing the value of `config.action_controller.perform_caching` will +only have an effect on the caching provided by the Action Controller component. +For instance, it will not impact low-level caching, that we address +[below](#low-level-caching). + ### Page Caching Page caching is a Rails mechanism which allows the request for a generated page @@ -98,6 +115,30 @@ If you want to cache a fragment under certain conditions, you can use <% end %> ``` +#### Collection caching + +The `render` helper can also cache individual templates rendered for a collection. +It can even one up the previous example with `each` by reading all cache +templates at once instead of one by one. This is done automatically if the template +rendered by the collection includes a `cache` call. Take a collection that renders +a `products/_product.html.erb` partial for each element: + +```ruby +render products +``` + +If `products/_product.html.erb` starts with a `cache` call like so: + +```html+erb +<% cache product do %> + <%= product.name %> +<% end %> +``` + +All the cached templates from previous renders will be fetched at once with much +greater speed. There's more info on how to make your templates [eligible for +collection caching](http://api.rubyonrails.org/classes/ActionView/Template/Handlers/ERB.html#method-i-resource_cache_call_pattern). + ### Russian Doll Caching You may want to nest cached fragments inside other cached fragments. This is @@ -122,7 +163,7 @@ For example, take the following view: Which in turn renders this view: ```erb -<% cache game %> +<% cache game do %> <%= render game %> <% end %> ``` @@ -147,6 +188,93 @@ With `touch` set to true, any action which changes `updated_at` for a game record will also change it for the associated product, thereby expiring the cache. +### Managing dependencies + +In order to correctly invalidate the cache, you need to properly define the +caching dependencies. Rails is clever enough to handle common cases so you don't +have to specify anything. However, sometimes, when you're dealing with custom +helpers for instance, you need to explicitly define them. + +#### Implicit dependencies + +Most template dependencies can be derived from calls to `render` in the template +itself. Here are some examples of render calls that `ActionView::Digestor` knows +how to decode: + +```ruby +render partial: "comments/comment", collection: commentable.comments +render "comments/comments" +render 'comments/comments' +render('comments/comments') + +render "header" => render("comments/header") + +render(@topic) => render("topics/topic") +render(topics) => render("topics/topic") +render(message.topics) => render("topics/topic") +``` + +On the other hand, some calls need to be changed to make caching work properly. +For instance, if you're passing a custom collection, you'll need to change: + +```ruby +render @project.documents.where(published: true) +``` + +to: + +```ruby +render partial: "documents/document", collection: @project.documents.where(published: true) +``` + +#### Explicit dependencies + +Sometimes you'll have template dependencies that can't be derived at all. This +is typically the case when rendering happens in helpers. Here's an example: + +```html+erb +<%= render_sortable_todolists @project.todolists %> +``` + +You'll need to use a special comment format to call those out: + +```html+erb +<%# Template Dependency: todolists/todolist %> +<%= render_sortable_todolists @project.todolists %> +``` + +In some cases, like a single table inheritance setup, you might have a bunch of +explicit dependencies. Instead of writing every template out, you can use a +wildcard to match any template in a directory: + +```html+erb +<%# Template Dependency: events/* %> +<%= render_categorizable_events @person.events %> +``` + +As for collection caching, if the partial template doesn't start with a clean +cache call, you can still benefit from collection caching by adding a special +comment format anywhere in the template, like: + +```html+erb +<%# Template Collection: notification %> +<% my_helper_that_calls_cache(some_arg, notification) do %> + <%= notification.name %> +<% end %> +``` + +#### External dependencies + +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 +simply be explicit in a comment, like: + +```html+erb +<%# Helper Dependency Updated: Jul 28, 2015 at 7pm %> +<%= some_helper_method(person) %> +``` + ### Low-Level Caching Sometimes you need to cache a particular value or query result instead of caching view fragments. Rails' caching mechanism works great for storing __any__ kind of information. @@ -202,16 +330,17 @@ persistent fashion, you can with low level caching. Cache Stores ------------ -Rails provides different stores for the cached data created by **action** and **fragment** caches. - -TIP: Page caches are always stored on disk. +Rails provides different stores for the cached data (apart from SQL and page +caching). ### Configuration -You can set up your application's default cache store by calling `config.cache_store=` in the Application definition inside your `config/application.rb` file or in an Application.configure block in an environment specific configuration file (i.e. `config/environments/*.rb`). The first argument will be the cache store to use and the rest of the argument will be passed as arguments to the cache store constructor. +You can set up your application's default cache store by setting the +`config.cache_store` configuration option. Other parameters can be passed as +arguments to the cache store's constructor: ```ruby -config.cache_store = :memory_store +config.cache_store = :memory_store, { size: 64.megabytes } ``` NOTE: Alternatively, you can call `ActionController::Base.cache_store` outside of a configuration block. @@ -236,6 +365,19 @@ There are some common options used by all cache implementations. These can be pa * `:race_condition_ttl` - This option is used in conjunction with the `:expires_in` option. It will prevent race conditions when cache entries expire by preventing multiple processes from simultaneously regenerating the same entry (also known as the dog pile effect). This option sets the number of seconds that an expired entry can be reused while a new value is being regenerated. It's a good practice to set this value if you use the `:expires_in` option. +#### Custom Cache Stores + +You can create your own custom cache store by simply extending +`ActiveSupport::Cache::Store` and implementing the appropriate methods. This way, +you can swap in any number of caching technologies into your Rails application. + +To use a custom cache store, simply set the cache store to a new instance of your +custom class. + +```ruby +config.cache_store = MyCacheStore.new +``` + ### ActiveSupport::Cache::MemoryStore This cache store keeps entries in memory in the same Ruby process. The cache @@ -287,36 +429,6 @@ The `write` and `fetch` methods on this cache accept two additional options that config.cache_store = :mem_cache_store, "cache-1.example.com", "cache-2.example.com" ``` -### ActiveSupport::Cache::EhcacheStore - -If you are using JRuby you can use Terracotta's Ehcache as the cache store for your application. Ehcache is an open source Java cache that also offers an enterprise version with increased scalability, management, and commercial support. You must first install the jruby-ehcache-rails3 gem (version 1.1.0 or later) to use this cache store. - -```ruby -config.cache_store = :ehcache_store -``` - -When initializing the cache, you may use the `:ehcache_config` option to specify the Ehcache config file to use (where the default is "ehcache.xml" in your Rails config directory), and the :cache_name option to provide a custom name for your cache (the default is rails_cache). - -In addition to the standard `:expires_in` option, the `write` method on this cache can also accept the additional `:unless_exist` option, which will cause the cache store to use Ehcache's `putIfAbsent` method instead of `put`, and therefore will not overwrite an existing entry. Additionally, the `write` method supports all of the properties exposed by the [Ehcache Element class](http://ehcache.org/apidocs/net/sf/ehcache/Element.html) , including: - -| Property | Argument Type | Description | -| --------------------------- | ------------------- | ----------------------------------------------------------- | -| elementEvictionData | ElementEvictionData | Sets this element's eviction data instance. | -| eternal | boolean | Sets whether the element is eternal. | -| timeToIdle, tti | int | Sets time to idle | -| timeToLive, ttl, expires_in | int | Sets time to Live | -| version | long | Sets the version attribute of the ElementAttributes object. | - -These options are passed to the `write` method as Hash options using either camelCase or underscore notation, as in the following examples: - -```ruby -Rails.cache.write('key', 'value', time_to_idle: 60.seconds, timeToLive: 600.seconds) -caches_action :index, expires_in: 60.seconds, unless_exist: true -``` - -For more information about Ehcache, see [http://ehcache.org/](http://ehcache.org/) . -For more information about Ehcache for JRuby and Rails, see [http://ehcache.org/documentation/jruby.html](http://ehcache.org/documentation/jruby.html) - ### ActiveSupport::Cache::NullStore This cache store implementation is meant to be used only in development or test environments and it never stores anything. This can be very useful in development when you have code that interacts directly with `Rails.cache` but caching may interfere with being able to see the results of code changes. With this cache store, all `fetch` and `read` operations will result in a miss. @@ -325,19 +437,13 @@ This cache store implementation is meant to be used only in development or test config.cache_store = :null_store ``` -### Custom Cache Stores - -You can create your own custom cache store by simply extending `ActiveSupport::Cache::Store` and implementing the appropriate methods. In this way, you can swap in any number of caching technologies into your Rails application. - -To use a custom cache store, simply set the cache store to a new instance of the class. - -```ruby -config.cache_store = MyCacheStore.new -``` - -### Cache Keys +Cache Keys +---------- -The keys used in a cache can be any object that responds to either `:cache_key` or `:to_param`. You can implement the `:cache_key` method on your classes if you need to generate custom keys. Active Record will generate keys based on the class name and record id. +The keys used in a cache can be any object that responds to either `cache_key` or +`to_param`. You can implement the `cache_key` method on your classes if you need +to generate custom keys. Active Record will generate keys based on the class name +and record id. You can use Hashes and Arrays of values as cache keys. @@ -346,7 +452,12 @@ You can use Hashes and Arrays of values as cache keys. Rails.cache.read(site: "mysite", owners: [owner_1, owner_2]) ``` -The keys you use on `Rails.cache` will not be the same as those actually used with the storage engine. They may be modified with a namespace or altered to fit technology backend constraints. This means, for instance, that you can't save values with `Rails.cache` and then try to pull them out with the `memcache-client` gem. However, you also don't need to worry about exceeding the memcached size limit or violating syntax rules. +The keys you use on `Rails.cache` will not be the same as those actually used with +the storage engine. They may be modified with a namespace or altered to fit +technology backend constraints. This means, for instance, that you can't save +values with `Rails.cache` and then try to pull them out with the `dalli` gem. +However, you also don't need to worry about exceeding the memcached size limit or +violating syntax rules. Conditional GET support ----------------------- diff --git a/guides/source/command_line.md b/guides/source/command_line.md index 0f5a9e4e39..cd265331d6 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -260,7 +260,13 @@ $ bin/rake db:migrate == CreateHighScores: migrated (0.0019s) ====================================== ``` -INFO: Let's talk about unit tests. Unit tests are code that tests and makes assertions about code. In unit testing, we take a little part of code, say a method of a model, and test its inputs and outputs. Unit tests are your friend. The sooner you make peace with the fact that your quality of life will drastically increase when you unit test your code, the better. Seriously. We'll make one in a moment. +INFO: Let's talk about unit tests. Unit tests are code that tests and makes assertions +about code. In unit testing, we take a little part of code, say a method of a model, +and test its inputs and outputs. Unit tests are your friend. The sooner you make +peace with the fact that your quality of life will drastically increase when you unit +test your code, the better. Seriously. Please visit +[the testing guide](http://guides.rubyonrails.org/testing.html) for an in-depth +look at unit testing. Let's see the interface Rails created for us. diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 79a80de3cc..df9704830e 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -326,7 +326,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 caching 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`. @@ -414,7 +414,7 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. `config.action_view` includes a small number of configuration settings: -* `config.action_view.field_error_proc` provides an HTML generator for displaying errors that come from Active Record. The default is +* `config.action_view.field_error_proc` provides an HTML generator for displaying errors that come from Active Model. The default is ```ruby Proc.new do |html_tag, instance| @@ -451,6 +451,9 @@ encrypted cookies salt value. Defaults to `'signed encrypted cookie'`. * `config.action_view.raise_on_missing_translations` determines whether an 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. + ### Configuring Action Mailer There are a number of settings available on `config.action_mailer`: @@ -1084,22 +1087,22 @@ development: timeout: 5000 ``` -Since the connection pooling is handled inside of Active Record by default, all application servers (Thin, mongrel, Unicorn etc.) should behave the same. Initially, the database connection pool is empty and it will create additional connections as the demand for them increases, until it reaches the connection pool limit. +Since the connection pooling is handled inside of Active Record by default, all application servers (Thin, mongrel, Unicorn etc.) should behave the same. The database connection pool is initially empty. As demand for connections increases it will create them until it reaches the connection pool limit. -Any one request will check out a connection the first time it requires access to the database, after which it will check the connection back in, at the end of the request, meaning that the additional connection slot will be available again for the next request in the queue. +Any one request will check out a connection the first time it requires access to the database. At the end of the request it will check the connection back in. This means that the additional connection slot will be available again for the next request in the queue. If you try to use more connections than are available, Active Record will block -and wait for a connection from the pool. When it cannot get connection, a timeout -error similar to given below will be thrown. +you and wait for a connection from the pool. If it cannot get a connection, a +timeout error similar to that given below will be thrown. ```ruby ActiveRecord::ConnectionTimeoutError - could not obtain a database connection within 5 seconds. The max pool size is currently 5; consider increasing it: ``` -If you get the above error, you might want to increase the size of connection -pool by incrementing the `pool` option in `database.yml` +If you get the above error, you might want to increase the size of the +connection pool by incrementing the `pool` option in `database.yml` -NOTE. If you are running in a multi-threaded environment, there could be a chance that several threads may be accessing multiple connections simultaneously. So depending on your current request load, you could very well have multiple threads contending for a limited amount of connections. +NOTE. If you are running in a multi-threaded environment, there could be a chance that several threads may be accessing multiple connections simultaneously. So depending on your current request load, you could very well have multiple threads contending for a limited number of connections. Custom configuration diff --git a/guides/source/contributing_to_ruby_on_rails.md b/guides/source/contributing_to_ruby_on_rails.md index 2e86eee587..ba82713266 100644 --- a/guides/source/contributing_to_ruby_on_rails.md +++ b/guides/source/contributing_to_ruby_on_rails.md @@ -15,6 +15,9 @@ After reading this guide, you will know: Ruby on Rails is not "someone else's framework." Over the years, hundreds of people have contributed to Ruby on Rails ranging from a single character to massive architectural changes or significant documentation - all with the goal of making Ruby on Rails better for everyone. Even if you don't feel up to writing code or documentation yet, there are a variety of other ways that you can contribute, from reporting issues to testing patches. +As mentioned in [Rails +README](https://github.com/rails/rails/blob/master/README.md), everyone interacting in Rails and its sub-project’s codebases, issue trackers, chat rooms, and mailing lists is expected to follow the Rails [code of conduct](https://github.com/rails/rails/blob/master/CODE_OF_CONDUCT.md). + -------------------------------------------------------------------------------- Reporting an Issue @@ -334,7 +337,7 @@ will now run the four of them in turn. You can also run any single test separately: ```bash -$ ARCONN=sqlite3 ruby -Itest test/cases/associations/has_many_associations_test.rb +$ ARCONN=sqlite3 bundle exec ruby -Itest test/cases/associations/has_many_associations_test.rb ``` To run a single test against all adapters, use: diff --git a/guides/source/credits.html.erb b/guides/source/credits.html.erb index 61ea0b44ef..1d995581fa 100644 --- a/guides/source/credits.html.erb +++ b/guides/source/credits.html.erb @@ -28,7 +28,7 @@ Ruby on Rails Guides: Credits <h3 class="section">Rails Guides Authors</h3> <%= author('Ryan Bigg', 'radar', 'radar.png') do %> - Ryan Bigg works as the Community Manager at <a href="http://spreecommerce.com">Spree Commerce</a> and has been working with Rails since 2006. He's the author of <a href="https://leanpub.com/multi-tenancy-rails">Multi Tenancy With Rails</a> and co-author of <a href="http://manning.com/bigg2">Rails 4 in Action</a>. He's written many gems which can be seen on <a href="https://github.com/radar">his GitHub page</a> and he also tweets prolifically as <a href="http://twitter.com/ryanbigg">@ryanbigg</a>. + Ryan Bigg works as a Rails developer at <a href="http://marketplacer.com">Marketplacer</a> and has been working with Rails since 2006. He's the author of <a href="https://leanpub.com/multi-tenancy-rails">Multi Tenancy With Rails</a> and co-author of <a href="http://manning.com/bigg2">Rails 4 in Action</a>. He's written many gems which can be seen on <a href="https://github.com/radar">his GitHub page</a> and he also tweets prolifically as <a href="http://twitter.com/ryanbigg">@ryanbigg</a>. <% end %> <%= author('Oscar Del Ben', 'oscardelben', 'oscardelben.jpg') do %> diff --git a/guides/source/debugging_rails_applications.md b/guides/source/debugging_rails_applications.md index dc1df8f229..40d5bd2012 100644 --- a/guides/source/debugging_rails_applications.md +++ b/guides/source/debugging_rails_applications.md @@ -346,22 +346,11 @@ by asking the debugger for help. Type: `help` ``` (byebug) help -byebug 2.7.0 + h[elp][ <cmd>[ <subcmd>]] -Type 'help <command-name>' for help on a specific command - -Available commands: -backtrace delete enable help list pry next restart source up -break disable eval info method ps save step var -catch display exit interrupt next putl set thread -condition down finish irb p quit show trace -continue edit frame kill pp reload skip undisplay -``` - -TIP: To view the help menu for any command use `help <command-name>` at the -debugger prompt. For example: _`help list`_. You can abbreviate any debugging -command by supplying just enough letters to distinguish them from other -commands. For example, you can use `l` for the `list` command. + help -- prints this help. + help <cmd> -- prints help on command <cmd>. + help <cmd> <subcmd> -- prints help on <cmd>'s subcommand <subcmd>. To see the previous ten lines you should type `list-` (or `l-`). @@ -502,7 +491,7 @@ current context: (byebug) instance_variables [:@_action_has_layout, :@_routes, :@_headers, :@_status, :@_request, - :@_response, :@_env, :@_prefixes, :@_lookup_context, :@_action_name, + :@_response, :@_prefixes, :@_lookup_context, :@_action_name, :@_response_body, :@marked_for_same_origin_verification, :@_config] ``` @@ -533,7 +522,7 @@ And then ask again for the instance_variables: ``` (byebug) instance_variables [:@_action_has_layout, :@_routes, :@_headers, :@_status, :@_request, - :@_response, :@_env, :@_prefixes, :@_lookup_context, :@_action_name, + :@_response, :@_prefixes, :@_lookup_context, :@_action_name, :@_response_body, :@marked_for_same_origin_verification, :@_config, :@articles] ``` @@ -630,13 +619,15 @@ Processing by ArticlesController#index as HTML (byebug) ``` -If we use `next`, we want go deep inside method calls. Instead, byebug will go -to the next line within the same context. In this case, this is the last line of -the method, so `byebug` will jump to next next line of the previous frame. - +If we use `next`, we won't go deep inside method calls. Instead, `byebug` will +go to the next line within the same context. In this case, it is the last line +of the current method, so `byebug` will return to the next line of the caller ++method. ``` (byebug) next -Next went up a frame because previous frame finished + +Next advances to the next line (line 6: `end`), which returns to the next line +of the caller method: [4, 13] in /PathTo/project/test_app/app/controllers/articles_controller.rb 4: # GET /articles @@ -653,8 +644,8 @@ Next went up a frame because previous frame finished (byebug) ``` -If we use `step` in the same situation, we will literally go to the next Ruby -instruction to be executed. In this case, Active Support's `week` method. +If we use `step` in the same situation, `byebug` will literally go to the next +Ruby instruction to be executed -- in this case, Active Support's `week` method. ``` (byebug) step @@ -773,8 +764,8 @@ environment variable. A specific _line_ can also be given. ### Quitting -To exit the debugger, use the `quit` command (abbreviated `q`), or its alias -`exit`. +To exit the debugger, use the `quit` command (abbreviated to `q`). Or, type `q!` +to bypass the `Really quit? (y/n)` prompt and exit unconditionally. A simple quit tries to terminate all threads in effect. Therefore your server will be stopped and you will have to start it again. diff --git a/guides/source/documents.yaml b/guides/source/documents.yaml index 9145aee009..4473eba478 100644 --- a/guides/source/documents.yaml +++ b/guides/source/documents.yaml @@ -122,6 +122,10 @@ url: autoloading_and_reloading_constants.html description: This guide documents how autoloading and reloading constants work. - + name: "Caching with Rails: An Overview" + url: caching_with_rails.html + description: This guide is an introduction to speeding up your Rails application with caching. + - name: Active Support Instrumentation work_in_progress: true url: active_support_instrumentation.html diff --git a/guides/source/form_helpers.md b/guides/source/form_helpers.md index 8f7d97844e..84a8d695cb 100644 --- a/guides/source/form_helpers.md +++ b/guides/source/form_helpers.md @@ -211,9 +211,8 @@ IMPORTANT: The search, telephone, date, time, color, datetime, datetime-local, month, week, URL, email, number and range inputs are HTML5 controls. If you require your app to have a consistent experience in older browsers, you will need an HTML5 polyfill (provided by CSS and/or JavaScript). -There is definitely [no shortage of solutions for this](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills), although a couple of popular tools at the moment are -[Modernizr](http://www.modernizr.com/) and [yepnope](http://yepnopejs.com/), -which provide a simple way to add functionality based on the presence of +There is definitely [no shortage of solutions for this](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills), although a popular tool at the moment is +[Modernizr](http://www.modernizr.com/), which provides a simple way to add functionality based on the presence of detected HTML5 features. TIP: If you're using password input fields (for any purpose), you might want to configure your application to prevent those parameters from being logged. You can learn about this in the [Security Guide](security.html#logging). diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index 400383cfb5..ef66b75ec1 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -23,10 +23,12 @@ 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 - versions 1.9 and later. To learn more about RubyGems, please read the [RubyGems Guides](http://guides.rubygems.org). +* 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). Rails is a web application framework running on the Ruby programming language. @@ -35,7 +37,6 @@ curve diving straight into Rails. There are several curated lists of online reso for learning Ruby: * [Official Ruby Programming Language website](https://www.ruby-lang.org/en/documentation/) -* [reSRC's List of Free Programming Books](http://resrc.io/list/10/list-of-free-programming-books/#ruby) Be aware that some resources, while still excellent, cover versions of Ruby as old as 1.6, and commonly 1.8, and will not include some syntax that you will see in day-to-day @@ -90,17 +91,17 @@ Open up a command line prompt. On Mac OS X open Terminal.app, on Windows choose dollar sign `$` should be run in the command line. Verify that you have a current version of Ruby installed: +```bash +$ ruby -v +ruby 2.2.2p95 +``` + 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 Mac OS X 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/). -```bash -$ ruby -v -ruby 2.2.2p95 -``` - 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 @@ -164,7 +165,7 @@ of the files and folders that Rails created by default: | File/Folder | Purpose | | ----------- | ------- | |app/|Contains the controllers, models, views, helpers, mailers and assets for your application. You'll focus on this folder for the remainder of this guide.| -|bin/|Contains the rails script that starts your app and can contain other scripts you use to setup, deploy or run your application.| +|bin/|Contains the rails script that starts your app and can contain other scripts you use to setup, update, deploy or run your application.| |config/|Configure your application's routes, database, and more. This is covered in more detail in [Configuring Rails Applications](configuring.html).| |config.ru|Rack configuration for Rack based servers used to start the application.| |db/|Contains your current database schema, as well as the database migrations.| diff --git a/guides/source/layouts_and_rendering.md b/guides/source/layouts_and_rendering.md index 94cd7297e2..b425eb126a 100644 --- a/guides/source/layouts_and_rendering.md +++ b/guides/source/layouts_and_rendering.md @@ -360,7 +360,6 @@ Rails understands both numeric status codes and the corresponding symbols shown | | 303 | :see_other | | | 304 | :not_modified | | | 305 | :use_proxy | -| | 306 | :reserved | | | 307 | :temporary_redirect | | | 308 | :permanent_redirect | | **Client Error** | 400 | :bad_request | @@ -376,10 +375,10 @@ Rails understands both numeric status codes and the corresponding symbols shown | | 410 | :gone | | | 411 | :length_required | | | 412 | :precondition_failed | -| | 413 | :request_entity_too_large | -| | 414 | :request_uri_too_long | +| | 413 | :payload_too_large | +| | 414 | :uri_too_long | | | 415 | :unsupported_media_type | -| | 416 | :requested_range_not_satisfiable | +| | 416 | :range_not_satisfiable | | | 417 | :expectation_failed | | | 422 | :unprocessable_entity | | | 423 | :locked | diff --git a/guides/source/routing.md b/guides/source/routing.md index 52f11f92bd..e4799d93fa 100644 --- a/guides/source/routing.md +++ b/guides/source/routing.md @@ -83,7 +83,9 @@ Rails would dispatch that request to the `destroy` method on the `photos` contro ### CRUD, Verbs, and Actions -In Rails, a resourceful route provides a mapping between HTTP verbs and URLs to controller actions. By convention, each action also maps to particular CRUD operations in a database. A single entry in the routing file, such as: +In Rails, a resourceful route provides a mapping between HTTP verbs and URLs to +controller actions. By convention, each action also maps to a specific CRUD +operation in a database. A single entry in the routing file, such as: ```ruby resources :photos @@ -615,6 +617,8 @@ get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' } Rails would match `photos/12` to the `show` action of `PhotosController`, and set `params[:format]` to `"jpg"`. +NOTE: You cannot override defaults via query parameters - this is for security reasons. The only defaults that can be overridden are dynamic segments via substitution in the URL path. + ### Naming Routes You can specify a name for any route using the `:as` option: @@ -793,7 +797,11 @@ get '/stories/:name', to: redirect { |path_params, req| "/articles/#{path_params get '/stories', to: redirect { |path_params, req| "/articles/#{req.subdomain}" } ``` -Please note that this redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible. +Please note that default redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible. You can use the `:status` option to change the response status: + +```ruby +get '/stories/:name', to: redirect('/articles/%{name}', status: 302) +``` In all of these cases, if you don't provide the leading host (`http://www.example.com`), Rails will take those details from the current request. @@ -1087,6 +1095,20 @@ edit_videos GET /videos/:identifier/edit(.:format) videos#edit Video.find_by(identifier: params[:identifier]) ``` +You can override `ActiveRecord::Base#to_param` of a related model to construct +an URL: + +```ruby +class Video < ActiveRecord::Base + def to_param + identifier + end +end + +video = Video.find_by(identifier: "Roman-Holiday") +edit_videos_path(video) # => "/videos/Roman-Holiday" +``` + Inspecting and Testing Routes ----------------------------- diff --git a/guides/source/security.md b/guides/source/security.md index fa168643ed..93c270064a 100644 --- a/guides/source/security.md +++ b/guides/source/security.md @@ -93,9 +93,16 @@ Rails 2 introduced a new default session storage, CookieStore. CookieStore saves * 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_. -* 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 and inserted into the end of the cookie. +* 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. -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_. +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`. + +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 `rake secret` instead_. `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.: @@ -191,11 +198,10 @@ This attack method works by including malicious code or a link in a page that ac 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 it will also send the cookie, if the request comes from a site of a different domain. 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. -* 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 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. +* 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. It is important to notice that the actual crafted image or link doesn't necessarily have to be situated in the web application's domain, it can be anywhere - in a forum, blog post or email. @@ -220,7 +226,7 @@ The HTTP protocol basically provides two main types of requests - GET and POST ( If your web application is RESTful, you might be used to additional HTTP verbs, such as PATCH, PUT or DELETE. Most of today's web browsers, however do not support them - only GET and POST. Rails uses a hidden `_method` field to handle this barrier. -_POST requests can be sent automatically, too_. Here is an example for a link which displays www.harmless.com as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request. +_POST requests can be sent automatically, too_. Here is an example for a link which displays `www.harmless.com` as destination in the browser's status bar. In fact it dynamically creates a new form that sends a POST request. ```html <a href="http://www.harmless.com/" onclick=" @@ -1008,18 +1014,12 @@ config.action_dispatch.default_headers.clear Here is a list of common headers: -* X-Frame-Options -_'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website. -* X-XSS-Protection -_'1; mode=block' in Rails by default_ - use XSS Auditor and block page if XSS attack is detected. Set it to '0;' if you want to switch XSS Auditor off (useful if response contents scripts from request parameters). -* X-Content-Type-Options -_'nosniff' in Rails by default_ - stops the browser from guessing the MIME type of a file. -* X-Content-Security-Policy -[A powerful mechanism for controlling which sites certain content types can be loaded from](http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html) -* Access-Control-Allow-Origin -Used to control which sites are allowed to bypass same origin policies and send cross-origin requests. -* Strict-Transport-Security -[Used to control if the browser is allowed to only access a site over a secure connection](http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) +* **X-Frame-Options:** _'SAMEORIGIN' in Rails by default_ - allow framing on same domain. Set it to 'DENY' to deny framing at all or 'ALLOWALL' if you want to allow framing for all website. +* **X-XSS-Protection:** _'1; mode=block' in Rails by default_ - use XSS Auditor and block page if XSS attack is detected. Set it to '0;' if you want to switch XSS Auditor off(useful if response contents scripts from request parameters) +* **X-Content-Type-Options:** _'nosniff' in Rails by default_ - stops the browser from guessing the MIME type of a file. +* **X-Content-Security-Policy:** [A powerful mechanism for controlling which sites certain content types can be loaded from](http://w3c.github.io/webappsec/specs/content-security-policy/csp-specification.dev.html) +* **Access-Control-Allow-Origin:** Used to control which sites are allowed to bypass same origin policies and send cross-origin requests. +* **Strict-Transport-Security:** [Used to control if the browser is allowed to only access a site over a secure connection](http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) Environmental Security ---------------------- diff --git a/guides/source/testing.md b/guides/source/testing.md index 2fd54a48fc..3a691220cf 100644 --- a/guides/source/testing.md +++ b/guides/source/testing.md @@ -25,15 +25,7 @@ Rails tests can also simulate browser requests and thus you can test your applic Introduction to Testing ----------------------- -Testing support was woven into the Rails fabric from the beginning. It wasn't an "oh! let's bolt on support for running tests because they're new and cool" epiphany. Just about every Rails application interacts heavily with a database and, as a result, your tests will need a database to interact with as well. To write efficient tests, you'll need to understand how to set up this database and populate it with sample data. - -### The Test Environment - -By default, every Rails application has three environments: development, test, and production. The database for each one of them is configured in `config/database.yml`. - -A dedicated test database allows you to set up and interact with test data in isolation. This way your tests can mangle test data with confidence, without worrying about the data in the development or production databases. - -Also, each environment's configuration can be modified similarly. In this case, we can modify our test environment by changing the options found in `config/environments/test.rb`. +Testing support was woven into the Rails fabric from the beginning. It wasn't an "oh! let's bolt on support for running tests because they're new and cool" epiphany. ### Rails Sets up for Testing from the Word Go @@ -51,123 +43,18 @@ Fixtures are a way of organizing test data; they reside in the `fixtures` direct The `test_helper.rb` file holds the default configuration for your tests. -### The Low-Down on Fixtures - -For good tests, you'll need to give some thought to setting up test data. -In Rails, you can handle this by defining and customizing fixtures. -You can find comprehensive documentation in the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html). - -#### What Are Fixtures? - -_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and written in YAML. There is one file per model. - -You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model, Rails automatically creates fixture stubs in this directory. - -#### YAML - -YAML-formatted fixtures are a human-friendly way to describe your sample data. These types of fixtures have the **.yml** file extension (as in `users.yml`). - -Here's a sample YAML fixture file: - -```yaml -# lo & behold! I am a YAML comment! -david: - name: David Heinemeier Hansson - birthday: 1979-10-15 - profession: Systems development - -steve: - name: Steve Ross Kellock - birthday: 1974-09-27 - profession: guy with keyboard -``` - -Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are typically separated by a blank line. You can place comments in a fixture file by using the # character in the first column. - -If you are working with [associations](/association_basics.html), you can simply -define a reference node between two different fixtures. Here's an example with -a `belongs_to`/`has_many` association: - -```yaml -# In fixtures/categories.yml -about: - name: About -# In fixtures/articles.yml -one: - title: Welcome to Rails! - body: Hello world! - category: about -``` - -Notice the `category` key of the `one` article found in `fixtures/articles.yml` has a value of `about`. This tells Rails to load the category `about` found in `fixtures/categories.yml`. - -NOTE: For associations to reference one another by name, you cannot specify the `id:` attribute on the associated fixtures. Rails will auto assign a primary key to be consistent between runs. For more information on this association behavior please read the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html). - -#### ERB'in It Up - -ERB allows you to embed Ruby code within templates. The YAML fixture format is pre-processed with ERB when Rails loads fixtures. This allows you to use Ruby to help you generate some sample data. For example, the following code generates a thousand users: - -```erb -<% 1000.times do |n| %> -user_<%= n %>: - username: <%= "user#{n}" %> - email: <%= "user#{n}@example.com" %> -<% end %> -``` - -#### Fixtures in Action - -Rails by default automatically loads all fixtures from the `test/fixtures` directory for your models and controllers test. Loading involves three steps: - -1. Remove any existing data from the table corresponding to the fixture -2. Load the fixture data into the table -3. Dump the fixture data into a method in case you want to access it directly - -TIP: In order to remove existing data from the database, Rails tries to disable referential integrity triggers (like foreign keys and check constraints). If you are getting annoying permission errors on running tests, make sure the database user has privilege to disable these triggers in testing environment. (In PostgreSQL, only superusers can disable all triggers. Read more about PostgreSQL permissions [here](http://blog.endpoint.com/2012/10/postgres-system-triggers-error.html)) - -#### Fixtures are Active Record objects - -Fixtures are instances of Active Record. As mentioned in point #3 above, you can access the object directly because it is automatically available as a method whose scope is local of the test case. For example: - -```ruby -# this will return the User object for the fixture named david -users(:david) +### The Test Environment -# this will return the property for david called id -users(:david).id +By default, every Rails application has three environments: development, test, and production. -# one can also access methods available on the User class -email(david.partner.email, david.location_tonight) -``` +Each environment's configuration can be modified similarly. In this case, we can modify our test environment by changing the options found in `config/environments/test.rb`. -To get multiple fixtures at once, you can pass in a list of fixture names. For example: +NOTE: Your test are run under RAILS_ENV=test. -```ruby -# this will return an array containing the fixtures david and steve -users(:david, :steve) -``` +### Rails meets Minitest -### Console Tasks for Running your Tests - -Rails comes with a CLI command to run tests. -Here are some examples of how to use it: - -```bash -$ bin/rails test # run all tests in the `test` directory -$ bin/rails test test/controllers # run all tests from specific directory -$ bin/rails test test/models/post_test.rb # run specific test -$ bin/rails test test/models/post_test.rb:44 # run specific test and line -``` - -We will cover each of types Rails tests listed above in this guide. - -Model Testing ------------------------- - -For this guide we will be using the application we built in the [Getting Started with Rails](getting_started.html) guide. - -If you remember when you used the `rails generate scaffold` command from earlier. We created our first resource among other things it created a test stub in the `test/models` directory: +If you remember when you used the `rails generate scaffold` command from the [Getting Started with Rails](getting_started.html) guide. We created our first resource among other things it created test stubs in the `test` directory: ```bash $ bin/rails generate scaffold article title:string body:text @@ -242,47 +129,6 @@ An assertion is a line of code that evaluates an object (or expression) for expe Every test must contain at least one assertion, with no restriction as to how many assertions are allowed. Only when all the assertions are successful will the test pass. -### Maintaining the test database schema - -In order to run your tests, your test database will need to have the current -structure. The test helper checks whether your test database has any pending -migrations. If so, it will try to load your `db/schema.rb` or `db/structure.sql` -into the test database. If migrations are still pending, an error will be -raised. Usually this indicates that your schema is not fully migrated. Running -the migrations against the development database (`bin/rake db:migrate`) will -bring the schema up to date. - -NOTE: If existing migrations required modifications, the test database needs to -be rebuilt. This can be done by executing `bin/rake db:test:prepare`. - -### Running Tests - -Running a test is as simple as invoking the file containing the test cases through `rails test` command. - -```bash -$ bin/rails test test/models/article_test.rb -. - -Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s. - -1 tests, 1 assertions, 0 failures, 0 errors, 0 skips -``` - -This will run all test methods from the test case. - -You can also run a particular test method from the test case by running the test and providing the `test method name`. - -```bash -$ bin/rails test test/models/article_test.rb test_the_truth -. - -Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s. - -1 tests, 1 assertions, 0 failures, 0 errors, 0 skips -``` - -The `.` (dot) above indicates a passing test. When a test fails you see an `F`; when a test throws an error you see an `E` in its place. The last line of the output is the summary. - #### Your first failing test To see how a test failure is reported, you can add a failing test to the `article_test.rb` test case. @@ -435,8 +281,8 @@ specify to make your test failure messages clearer. It's not required. | `assert_no_match( regexp, string, [msg] )` | Ensures that a string doesn't match the regular expression.| | `assert_includes( collection, obj, [msg] )` | Ensures that `obj` is in `collection`.| | `assert_not_includes( collection, obj, [msg] )` | Ensures that `obj` is not in `collection`.| -| `assert_in_delta( expecting, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are within `delta` of each other.| -| `assert_not_in_delta( expecting, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are not within `delta` of each other.| +| `assert_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are within `delta` of each other.| +| `assert_not_in_delta( expected, actual, [delta], [msg] )` | Ensures that the numbers `expected` and `actual` are not within `delta` of each other.| | `assert_throws( symbol, [msg] ) { block }` | Ensures that the given block throws the symbol.| | `assert_raises( exception1, exception2, ... ) { block }` | Ensures that the given block raises one of the given exceptions.| | `assert_nothing_raised( exception1, exception2, ... ) { block }` | Ensures that the given block doesn't raise one of the given exceptions.| @@ -477,7 +323,7 @@ Rails adds some custom assertions of its own to the `minitest` framework: You'll see the usage of some of these assertions in the next chapter. -### A Brief Note About Minitest +### A Brief Note About Test Cases All the basic assertions such as `assert_equal` defined in `Minitest::Assertions` are also available in the classes we use in our own test cases. In fact, Rails provides the following classes for you to inherit from: @@ -492,6 +338,297 @@ Each of these classes include `Minitest::Assertions`, allowing us to use all of NOTE: For more information on `Minitest`, refer to [Minitest](http://docs.seattlerb.org/minitest) +### The Rails Test Runner + +We can run all of our tests at once by using the `rails test` command. + +Or we can run a single test by passing the `rails test` command the filename containing the test cases. + +```bash +$ bin/rails test test/models/article_test.rb +. + +Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s. + +1 tests, 1 assertions, 0 failures, 0 errors, 0 skips +``` + +This will run all test methods from the test case. + +You can also run a particular test method from the test case by providing the `-n` or `--name` flag and the `test method name`. + +```bash +$ bin/rails test test/models/article_test.rb -n test_the_truth +. + +Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s. + +1 tests, 1 assertions, 0 failures, 0 errors, 0 skips +``` + +You can also run a test at a specific line by providing the line number. + +```bash +$ bin/rails test test/models/post_test.rb:44 # run specific test and line +``` + +You can also run an entire directory of tests by providing the path to the directory. + +```bash +$ bin/rails test test/controllers # run all tests from specific directory +``` + + +The Test Database +----------------- + +Just about every Rails application interacts heavily with a database and, as a result, your tests will need a database to interact with as well. To write efficient tests, you'll need to understand how to set up this database and populate it with sample data. + +By default, every Rails application has three environments: development, test, and production. The database for each one of them is configured in `config/database.yml`. + +A dedicated test database allows you to set up and interact with test data in isolation. This way your tests can mangle test data with confidence, without worrying about the data in the development or production databases. + + +### Maintaining the test database schema + +In order to run your tests, your test database will need to have the current +structure. The test helper checks whether your test database has any pending +migrations. If so, it will try to load your `db/schema.rb` or `db/structure.sql` +into the test database. If migrations are still pending, an error will be +raised. Usually this indicates that your schema is not fully migrated. Running +the migrations against the development database (`bin/rake db:migrate`) will +bring the schema up to date. + +NOTE: If existing migrations required modifications, the test database needs to +be rebuilt. This can be done by executing `bin/rake db:test:prepare`. + +### The Low-Down on Fixtures + +For good tests, you'll need to give some thought to setting up test data. +In Rails, you can handle this by defining and customizing fixtures. +You can find comprehensive documentation in the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html). + +#### What Are Fixtures? + +_Fixtures_ is a fancy word for sample data. Fixtures allow you to populate your testing database with predefined data before your tests run. Fixtures are database independent and written in YAML. There is one file per model. + +You'll find fixtures under your `test/fixtures` directory. When you run `rails generate model` to create a new model, Rails automatically creates fixture stubs in this directory. + +#### YAML + +YAML-formatted fixtures are a human-friendly way to describe your sample data. These types of fixtures have the **.yml** file extension (as in `users.yml`). + +Here's a sample YAML fixture file: + +```yaml +# lo & behold! I am a YAML comment! +david: + name: David Heinemeier Hansson + birthday: 1979-10-15 + profession: Systems development + +steve: + name: Steve Ross Kellock + birthday: 1974-09-27 + profession: guy with keyboard +``` + +Each fixture is given a name followed by an indented list of colon-separated key/value pairs. Records are typically separated by a blank line. You can place comments in a fixture file by using the # character in the first column. + +If you are working with [associations](/association_basics.html), you can simply +define a reference node between two different fixtures. Here's an example with +a `belongs_to`/`has_many` association: + +```yaml +# In fixtures/categories.yml +about: + name: About + +# In fixtures/articles.yml +one: + title: Welcome to Rails! + body: Hello world! + category: about +``` + +Notice the `category` key of the `one` article found in `fixtures/articles.yml` has a value of `about`. This tells Rails to load the category `about` found in `fixtures/categories.yml`. + +NOTE: For associations to reference one another by name, you cannot specify the `id:` attribute on the associated fixtures. Rails will auto assign a primary key to be consistent between runs. For more information on this association behavior please read the [Fixtures API documentation](http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html). + +#### ERB'in It Up + +ERB allows you to embed Ruby code within templates. The YAML fixture format is pre-processed with ERB when Rails loads fixtures. This allows you to use Ruby to help you generate some sample data. For example, the following code generates a thousand users: + +```erb +<% 1000.times do |n| %> +user_<%= n %>: + username: <%= "user#{n}" %> + email: <%= "user#{n}@example.com" %> +<% end %> +``` + +#### Fixtures in Action + +Rails by default automatically loads all fixtures from the `test/fixtures` directory for your models and controllers test. Loading involves three steps: + +1. Remove any existing data from the table corresponding to the fixture +2. Load the fixture data into the table +3. Dump the fixture data into a method in case you want to access it directly + +TIP: In order to remove existing data from the database, Rails tries to disable referential integrity triggers (like foreign keys and check constraints). If you are getting annoying permission errors on running tests, make sure the database user has privilege to disable these triggers in testing environment. (In PostgreSQL, only superusers can disable all triggers. Read more about PostgreSQL permissions [here](http://blog.endpoint.com/2012/10/postgres-system-triggers-error.html)) + +#### Fixtures are Active Record objects + +Fixtures are instances of Active Record. As mentioned in point #3 above, you can access the object directly because it is automatically available as a method whose scope is local of the test case. For example: + +```ruby +# this will return the User object for the fixture named david +users(:david) + +# this will return the property for david called id +users(:david).id + +# one can also access methods available on the User class +email(david.partner.email, david.location_tonight) +``` + +To get multiple fixtures at once, you can pass in a list of fixture names. For example: + +```ruby +# this will return an array containing the fixtures david and steve +users(:david, :steve) +``` + + +Model Testing +------------- + +Model tests are used to test the various models of your application. + +For creating Rails model tests, we use the 'test/model' directory for your application. Rails provides a generator to create an model test skeleton for you. + +```bash +$ bin/rails generate test_unit:model article title:string body:text +create test/models/article_test.rb +create test/fixtures/articles.yml +``` + +Model tests don't have their own superclass like `ActionMailer::TestCase` instead they inherit from `ActiveSupport::TestCase`. + + +Integration Testing +------------------- + +Integration tests are used to test how various parts of your application interact. They are generally used to test important work flows within your application. + +For creating Rails integration tests, we use the 'test/integration' directory for your application. Rails provides a generator to create an integration test skeleton for you. + +```bash +$ bin/rails generate integration_test user_flows + exists test/integration/ + create test/integration/user_flows_test.rb +``` + +Here's what a freshly-generated integration test looks like: + +```ruby +require 'test_helper' + +class UserFlowsTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end +``` + +Inheriting from `ActionDispatch::IntegrationTest` comes with some advantages. This makes available some additional helpers to use in your integration tests. + +### Helpers Available for Integration Tests + +In addition to the standard testing helpers, inheriting `ActionDispatch::IntegrationTest` comes with some additional helpers available when writing integration tests. Let's briefly introduce you to the three categories of helpers you get to choose from. + +For dealing with the integration test runner, see [`ActionDispatch::Integration::Runner`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Runner.html). + +When performing requests, you will have [`ActionDispatch::Integration::RequestHelpers`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html) available for your use. + +If you'd like to modify the session, or state of your integration test you should look for [`ActionDispatch::Integration::Session`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Session.html) to help. + +### Implementing an integration test + +Let's add an integration test to our blog application. We'll start with a basic workflow of creating a new blog article, to verify that everything is working properly. + +We'll start by generating our integration test skeleton: + +```bash +$ bin/rails generate integration_test blog_flow +``` + +It should have created a test file placeholder for us, with the output of the previous command you should see: + +```bash + invoke test_unit + create test/integration/blog_flow_test.rb +``` + +Now let's open that file and write our first assertion: + +```ruby +require 'test_helper' + +class BlogFlowTest < ActionDispatch::IntegrationTest + test "can see the welcome page" do + get "/" + assert_select "h1", "Welcome#index" + end +end +``` + +If you remember from earlier in the "Testing Views" section we covered `assert_select` to query the resulting HTML of a request. + +When visit our root path, we should see `welcome/index.html.erb` rendered for the view. So this assertion should pass. + +#### Creating articles integration + +How about testing our ability to create a new article in our blog and see the resulting article. + +```ruby +test "can create an article" do + get "/articles/new" + assert_response :success + + post "/articles", + params: { article: { title: "can create", body: "article successfully." } } + assert_response :redirect + follow_redirect! + assert_response :success + assert_select "p", "Title:\n can create" +end +``` + +Let's break this test down so we can understand it. + +We start by calling the `:new` action on our Articles controller. This response should be successful. + +After this we make a post request to the `:create` action of our Articles controller: + +```ruby +post "/articles", + params: { article: { title: "can create", body: "article successfully." } } +assert_response :redirect +follow_redirect! +``` + +The two lines following the request are to handle the redirect we setup when creating a new article. + +NOTE: Don't forget to call `follow_redirect!` if you plan to make subsequent requests after a redirect is made. + +Finally we can assert that our response was successful and our new article is readable on the page. + +#### Taking it further + +We were able to successfully test a very small workflow for visiting our blog and creating a new article. If we wanted to take this further we could add tests for commenting, removing articles, or editing comments. Integration tests are a great place to experiment with all kinds of use-cases for our applications. + + Functional Tests for Your Controllers ------------------------------------- @@ -509,6 +646,14 @@ You should test for things such as: Now that we have used Rails scaffold generator for our `Article` resource, it has already created the controller code and tests. You can take look at the file `articles_controller_test.rb` in the `test/controllers` directory. +The following command will generate a controller test case with a filled up +test for each of the seven default actions. + +```bash +$ bin/rails generate test_unit:scaffold article +create test/controllers/articles_controller_test.rb +``` + Let me take you through one such test, `test_should_get_index` from the file `articles_controller_test.rb`. ```ruby @@ -596,9 +741,9 @@ test "ajax request" do end ``` -### The Four Hashes of the Apocalypse +### The Three Hashes of the Apocalypse -After a request has been made and processed, you will have 4 Hash objects ready for use: +After a request has been made and processed, you will have 3 Hash objects ready for use: * `cookies` - Any cookies that are set. * `flash` - Any objects living in the flash. @@ -639,7 +784,7 @@ post :create # simulate the request with custom env variable ### Testing `flash` notices -If you remember from earlier one of the Four Hashes of the Apocalypse was `flash`. +If you remember from earlier one of the Three Hashes of the Apocalypse was `flash`. We want to add a `flash` message to our blog application whenever someone successfully creates a new Article. @@ -828,33 +973,7 @@ end Testing Routes -------------- -Like everything else in your Rails application, it is recommended that you test your routes. Below are example tests for the routes of default `show` and `create` action of `Articles` controller above and it should look like: - -```ruby -class ArticleRoutesTest < ActionController::TestCase - test "should route to article" do - assert_routing '/articles/1', { controller: "articles", action: "show", id: "1" } - end - - test "should route to create article" do - assert_routing({ method: 'post', path: '/articles' }, { controller: "articles", action: "create" }) - end -end -``` - -I've added this file here `test/controllers/articles_routes_test.rb` and if we run the test we should see: - -```bash -$ bin/rails test test/controllers/articles_routes_test.rb - -# Running: - -.. - -Finished in 0.069381s, 28.8263 runs/s, 86.4790 assertions/s. - -2 runs, 6 assertions, 0 failures, 0 errors, 0 skips -``` +Like everything else in your Rails application, you can test your routes. For more information on routing assertions available in Rails, see the API documentation for [`ActionDispatch::Assertions::RoutingAssertions`](http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html). @@ -944,8 +1063,6 @@ have to use a mixin like this: ```ruby class UserHelperTest < ActionView::TestCase - include UserHelper - test "should return the user name" do # ... end @@ -955,118 +1072,6 @@ end Moreover, since the test class extends from `ActionView::TestCase`, you have access to Rails' helper methods such as `link_to` or `pluralize`. -Integration Testing -------------------- - -Integration tests are used to test how various parts of your application interact. They are generally used to test important work flows within your application. - -For creating Rails integration tests, we use the 'test/integration' directory for your application. Rails provides a generator to create an integration test skeleton for you. - -```bash -$ bin/rails generate integration_test user_flows - exists test/integration/ - create test/integration/user_flows_test.rb -``` - -Here's what a freshly-generated integration test looks like: - -```ruby -require 'test_helper' - -class UserFlowsTest < ActionDispatch::IntegrationTest - # test "the truth" do - # assert true - # end -end -``` - -Inheriting from `ActionDispatch::IntegrationTest` comes with some advantages. This makes available some additional helpers to use in your integration tests. - -### Helpers Available for Integration Tests - -In addition to the standard testing helpers, inheriting `ActionDispatch::IntegrationTest` comes with some additional helpers available when writing integration tests. Let's briefly introduce you to the three categories of helpers you get to choose from. - -For dealing with the integration test runner, see [`ActionDispatch::Integration::Runner`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Runner.html). - -When performing requests, you will have [`ActionDispatch::Integration::RequestHelpers`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html) available for your use. - -If you'd like to modify the session, or state of your integration test you should look for [`ActionDispatch::Integration::Session`](http://api.rubyonrails.org/classes/ActionDispatch/Integration/Session.html) to help. - -### Implementing an integration test - -Let's add an integration test to our blog application. We'll start with a basic workflow of creating a new blog article, to verify that everything is working properly. - -We'll start by generating our integration test skeleton: - -```bash -$ bin/rails generate integration_test blog_flow -``` - -It should have created a test file placeholder for us, with the output of the previous command you should see: - -```bash - invoke test_unit - create test/integration/blog_flow_test.rb -``` - -Now let's open that file and write our first assertion: - -```ruby -require 'test_helper' - -class BlogFlowTest < ActionDispatch::IntegrationTest - test "can see the welcome page" do - get "/" - assert_select "h1", "Welcome#index" - end -end -``` - -If you remember from earlier in the "Testing Views" section we covered `assert_select` to query the resulting HTML of a request. - -When visit our root path, we should see `welcome/index.html.erb` rendered for the view. So this assertion should pass. - -#### Creating articles integration - -How about testing our ability to create a new article in our blog and see the resulting article. - -```ruby -test "can create an article" do - get "/articles/new" - assert_response :success - - post "/articles", - params: { article: { title: "can create", body: "article successfully." } } - assert_response :redirect - follow_redirect! - assert_response :success - assert_select "p", "Title:\n can create" -end -``` - -Let's break this test down so we can understand it. - -We start by calling the `:new` action on our Articles controller. This response should be successful, and we can verify the correct template is rendered including the form partial. - -After this we make a post request to the `:create` action of our Articles controller: - -```ruby -post "/articles", - params: { article: { title: "can create", body: "article successfully." } } -assert_response :redirect -follow_redirect! -``` - -The two lines following the request are to handle the redirect we setup when creating a new article. - -NOTE: Don't forget to call `follow_redirect!` if you plan to make subsequent requests after a redirect is made. - -Finally we can assert that our response was successful, template was rendered, and our new article is readable on the page. - -#### Taking it further - -We were able to successfully test a very small workflow for visiting our blog and creating a new article. If we wanted to take this further we could add tests for commenting, removing articles, or editting comments. Integration tests are a great place to experiment with all kinds of use-cases for our applications. - Testing Your Mailers -------------------- @@ -1219,16 +1224,3 @@ class ProductTest < ActiveJob::TestCase end end ``` - -Other Testing Approaches ------------------------- - -The built-in `minitest` based testing is not the only way to test Rails applications. Rails developers have come up with a wide variety of other approaches and aids for testing, including: - -* [NullDB](http://avdi.org/projects/nulldb/), a way to speed up testing by avoiding database use. -* [Factory Girl](https://github.com/thoughtbot/factory_girl/tree/master), a replacement for fixtures. -* [Fixture Builder](https://github.com/rdy/fixture_builder), a tool that compiles Ruby factories into fixtures before a test run. -* [MiniTest::Spec Rails](https://github.com/metaskills/minitest-spec-rails), use the MiniTest::Spec DSL within your rails tests. -* [Shoulda](http://www.thoughtbot.com/projects/shoulda), an extension to `test/unit` with additional helpers, macros, and assertions. -* [RSpec](http://relishapp.com/rspec), a behavior-driven development framework -* [Capybara](http://jnicklas.github.com/capybara/), Acceptance test framework for web applications diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index 17309d4b47..743241d7a0 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -75,7 +75,7 @@ warning by adding the following configuration to your `config/application.rb`: See [#17227](https://github.com/rails/rails/pull/17227) for more details. -### ActiveJob jobs now inherent from ApplicationJob by default +### ActiveJob jobs now inherit from ApplicationJob by default In Rails 4.2 an ActiveJob inherits from `ActiveJob::Base`. In Rails 5.0 this behavior has changed to now inherit from `ApplicationJob`. diff --git a/guides/source/working_with_javascript_in_rails.md b/guides/source/working_with_javascript_in_rails.md index f3d3a83afc..1c42ff2914 100644 --- a/guides/source/working_with_javascript_in_rails.md +++ b/guides/source/working_with_javascript_in_rails.md @@ -258,7 +258,7 @@ this generates ```html <form action="/articles/1" class="button_to" data-remote="true" method="post"> - <div><input type="submit" value="An article"></div> + <input type="submit" value="An article" /> </form> ``` @@ -357,7 +357,7 @@ This gem uses Ajax to speed up page rendering in most applications. Turbolinks attaches a click handler to all `<a>` on the page. If your browser supports -[PushState](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history#The_pushState()_method), +[PushState](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history#The_pushState%28%29_method), Turbolinks will make an Ajax request for the page, parse the response, and replace the entire `<body>` of the page with the `<body>` of the response. It will then use PushState to change the URL to the correct one, preserving |