aboutsummaryrefslogtreecommitdiffstats
path: root/guides
diff options
context:
space:
mode:
Diffstat (limited to 'guides')
-rw-r--r--guides/CHANGELOG.md4
-rw-r--r--guides/source/action_controller_overview.md4
-rw-r--r--guides/source/active_record_querying.md37
-rw-r--r--guides/source/constant_autoloading_and_reloading.md210
-rw-r--r--guides/source/security.md8
5 files changed, 140 insertions, 123 deletions
diff --git a/guides/CHANGELOG.md b/guides/CHANGELOG.md
index afaa404ac1..5a65f1355e 100644
--- a/guides/CHANGELOG.md
+++ b/guides/CHANGELOG.md
@@ -1 +1,5 @@
+* New section in Active Record Querying: Understanding The Method Chaining
+
+ *andreynering*
+
Please check [4-2-stable](https://github.com/rails/rails/blob/4-2-stable/guides/CHANGELOG.md) for previous changes.
diff --git a/guides/source/action_controller_overview.md b/guides/source/action_controller_overview.md
index 4e36a62583..57546da389 100644
--- a/guides/source/action_controller_overview.md
+++ b/guides/source/action_controller_overview.md
@@ -112,8 +112,8 @@ NOTE: The actual URL in this example will be encoded as "/clients?ids%5b%5d=1&id
The value of `params[:ids]` will now be `["1", "2", "3"]`. Note that parameter values are always strings; Rails makes no attempt to guess or cast the type.
-NOTE: Values such as `[]`, `[nil]` or `[nil, nil, ...]` in `params` are replaced
-with `nil` for security reasons by default. See [Security Guide](security.html#unsafe-query-generation)
+NOTE: Values such as `[nil]` or `[nil, nil, ...]` in `params` are replaced
+with `[]` for security reasons by default. See [Security Guide](security.html#unsafe-query-generation)
for more information.
To send a hash you include the key name inside the brackets:
diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md
index e1a465c64f..f6fbc29707 100644
--- a/guides/source/active_record_querying.md
+++ b/guides/source/active_record_querying.md
@@ -9,6 +9,7 @@ After reading this guide, you will know:
* How to specify the order, retrieved attributes, grouping, and other properties of the found records.
* How to use eager loading to reduce the number of database queries needed for data retrieval.
* How to use dynamic finders methods.
+* How to use method chaining to use multiple ActiveRecord methods together.
* How to check for the existence of particular records.
* How to perform various calculations on Active Record models.
* How to run EXPLAIN on relations.
@@ -1327,10 +1328,44 @@ You can specify an exclamation point (`!`) on the end of the dynamic finders to
If you want to find both by name and locked, you can chain these finders together by simply typing "`and`" between the fields. For example, `Client.find_by_first_name_and_locked("Ryan", true)`.
+Understanding The Method Chaining
+---------------------------------
+
+The ActiveRecord pattern implements [Method Chaining](http://en.wikipedia.org/wiki/Method_chaining).
+This allow us to use multiple ActiveRecord methods in a simple and straightforward way.
+
+You can chain a method in a sentence when the previous method called returns `ActiveRecord::Relation`,
+like `all`, `where`, and `joins`. Methods that returns a instance of a single object
+(see [Retrieving a Single Object Section](#retrieving-a-single-object)) have to be be the last
+in the sentence.
+
+This guide won't cover all the possibilities, just a few as example.
+
+### Retrieving filtered data from multiple tables
+
+```ruby
+Person
+ .select('people.id, people.name, comments.text')
+ .joins(:comments)
+ .where('comments.create_at > ?', 1.week.ago)
+```
+
+### Retrieving specific data from multiple tables
+
+```ruby
+Person
+ .select('people.id, people.name, companies.name')
+ .joins(:company)
+ .find_by('people.name' => 'John') # this should be the last
+```
+
+NOTE: Remember that, if `find_by` return more than one registry, it will take just the first
+and ignore the others.
+
Find or Build a New Object
--------------------------
-NOTE: Some dynamic finders have been deprecated in Rails 4.0 and will be
+NOTE: Some dynamic finders were deprecated in Rails 4.0 and
removed in Rails 4.1. The best practice is to use Active Record scopes
instead. You can find the deprecation gem at
https://github.com/rails/activerecord-deprecated_finders
diff --git a/guides/source/constant_autoloading_and_reloading.md b/guides/source/constant_autoloading_and_reloading.md
index 9c0f9f58fc..a6b270e06d 100644
--- a/guides/source/constant_autoloading_and_reloading.md
+++ b/guides/source/constant_autoloading_and_reloading.md
@@ -15,8 +15,6 @@ After reading this guide, you will know:
* How constant reloading works
-* That autoloading is not based on `Module#autoload`
-
* Solutions to common autoloading gotchas
--------------------------------------------------------------------------------
@@ -259,7 +257,9 @@ Put special attention in the previous paragraphs to the distinction between
class and module objects, constant names, and value objects associated to them
in constant tables.
-### Resolution Algorithm for Relative Constants
+### Resolution Algorithms
+
+#### Resolution Algorithm for Relative Constants
At any given place in the code, let's define *cref* to be the first element of
the nesting if it is not empty, or `Object` otherwise.
@@ -279,7 +279,7 @@ Rails autoloading **does not emulate this algorithm**, but its starting point is
the name of the constant to be autoloaded, and the cref. See more in [Relative
References](#relative-references).
-### Resolution Algorithm for Qualified Constants
+#### Resolution Algorithm for Qualified Constants
Qualified constants look like this:
@@ -341,7 +341,7 @@ still be "A::B".
The idea of a parent namespace is at the core of the autoloading algorithms
and helps explain and understand their motivation intuitively, but as you see
that metaphor leaks easily. Given an edge case to reason about, take always into
-account the by "parent namespace" the guide means exactly that specific string
+account that by "parent namespace" the guide means exactly that specific string
derivation.
### Loading Mechanism
@@ -397,19 +397,18 @@ require 'erb'
```
Ruby looks for the file in the directories listed in `$LOAD_PATH`. That is, Ruby
-iterates over all its directories and for each one of them checks whether they
-have a file called "erb.rb", or "erb.so", or "erb.o", or "erb.dll". If it finds
-any of them, the interpreter loads it and ends the search. Otherwise, it tries
-again in the next directory of the list. If the list gets exhausted, `LoadError`
-is raised.
+iterates over all its directories and for each one of them checks whether it
+has a file called "erb.rb", "erb.so", "erb.o" or "erb.dll". If it finds one,
+the interpreter loads it and ends the search. Otherwise, it tries again in the
+next directory of the list. If the list gets exhausted, `LoadError` is raised.
We are going to cover how constant autoloading works in more detail later, but
-the idea is that when a constant like `Post` is hit and missing, if there's a
-*post.rb* file for example in *app/models* Rails is going to find it, evaluate
-it, and have `Post` defined as a side-effect.
+the idea is that when a constant like `Post` is hit and missing, if there is a
+*post.rb* file, for example in *app/models*, Rails will find it, evaluate it
+and allocate the class `Post` as a side-effect.
-Alright, Rails has a collection of directories similar to `$LOAD_PATH` in which
-to lookup that *post.rb*. That collection is called `autoload_paths` and by
+At this point, Rails has a collection of directories similar to `$LOAD_PATH` in
+which to look up *post.rb*. That collection is called `autoload_paths` and by
default it contains:
* All subdirectories of `app` in the application and engines. For example,
@@ -542,7 +541,7 @@ modulus some additional directory lookups we are going to cover soon.
INFO. `'Constant::Name'.underscore` gives the relative path without extension of
the file name where `Constant::Name` is expected to be defined.
-Let's see how does Rails autoload the `Post` constant in the `PostsController`
+Let's see how Rails autoloads the `Post` constant in the `PostsController`
above assuming the application has a `Post` model defined in
`app/models/post.rb`.
@@ -585,7 +584,7 @@ file is loaded. If the file actually defines `Post` all is fine, otherwise
### Qualified References
When a qualified constant is missing Rails does not look for it in the parent
-namespaces. But there's a caveat: Unfortunately, when a constant is missing
+namespaces. But there's a caveat: unfortunately, when a constant is missing
Rails is not able to say if the trigger was a relative or qualified reference.
For example, consider
@@ -640,7 +639,7 @@ But since autoloading happens on demand, if the top-level `User` by chance was
not yet loaded then Rails has no way to know whether `Admin::User` should load it
or raise `NameError`.
-These kind of name conflicts are rare in practice, but in case there's one
+These kind of name conflicts are rare in practice but, in case there's one,
`require_dependency` provides a solution by making sure the constant needed to
trigger the heuristic is defined in the conflicting place.
@@ -843,13 +842,13 @@ class Admin::UsersController < ApplicationController
end
```
-If Ruby resolves `User` in the former case it checks whether there's a `User`
-constant in the `Admin` module. It does not in the latter case, because `Admin`
-does not belong to the nesting.
+To resolve `User` Ruby checks `Admin` in the former case, but it does not in
+the latter because it does not belong to the nesting. (See [Nesting](#nesting)
+and [Resolution Algorithms](#resolution- algorithms).)
Unfortunately Rails autoloading does not know the nesting in the spot where the
constant was missing and so it is not able to act as Ruby would. In particular,
-if `Admin::User` is autoloadable, it will get autoloaded in either case.
+`Admin::User` will get autoloaded in either case.
Albeit qualified constants with `class` and `module` keywords may technically
work with autoloading in some cases, it is preferable to use relative constants
@@ -867,10 +866,10 @@ end
### Autoloading and STI
-STI (Single Table Inheritance) is a feature of Active Record that easies storing
-records that belong to a hierarchy of classes in one single table. The API of
-such models is aware of the hierarchy and encapsulates some common needs. For
-example, given these classes:
+Single Table Inheritance (STI) is a feature of Active Record that easies
+storing a hierarchy of models in one single table. The API of such models is
+aware of the hierarchy and encapsulates some common needs. For example, given
+these classes:
```ruby
# app/models/polygon.rb
@@ -887,37 +886,35 @@ end
```
`Triangle.create` creates a row that represents a triangle, and
-`Rectangle.create` creates a row that represents a rectangle. If `id` is the ID
-of an existing record, `Polygon.find(id)` returns an object of the correct type.
+`Rectangle.create` creates a row that represents a rectangle. If `id` is the
+ID of an existing record, `Polygon.find(id)` returns an object of the correct
+type.
-Methods that perform operations on collections are also aware of the hierarchy.
-For example, `Polygon.all` returns all the records of the table, because all
+Methods that operate on collections are also aware of the hierarchy. For
+example, `Polygon.all` returns all the records of the table, because all
rectangles and triangles are polygons. Active Record takes care of returning
instances of their corresponding class in the result set.
-When Active Record does this, it autoloads constants as needed. For example, if
-the class of `Polygon.first` is `Rectangle` and it has not yet been loaded,
-Active Record autoloads it and the record is fetched and correctly instantiated,
-transparently.
+Types are autoloaded as needed. For example, if `Polygon.first` is a rectangle
+and `Rectangle` has not yet been loaded, Active Record autoloads it and the
+record is correctly instantiated.
All good, but if instead of performing queries based on the root class we need
-to work on some subclass, then things get interesting.
+to work on some subclass, things get interesting.
While working with `Polygon` you do not need to be aware of all its descendants,
because anything in the table is by definition a polygon, but when working with
subclasses Active Record needs to be able to enumerate the types it is looking
for. Let’s see an example.
-`Rectangle.all` should return all the rectangles in the "polygons" table. In
-particular, no triangle should be fetched. To accomplish this, Active Record
-constraints the query to rows whose type column is “Rectangle”:
+`Rectangle.all` only loads rectangles by adding a type constraint to the query:
```sql
SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle")
```
-That works, but let’s introduce now a child of `Rectangle`:
+Let’s introduce now a subclass of `Rectangle`:
```ruby
# app/models/square.rb
@@ -925,16 +922,15 @@ class Square < Rectangle
end
```
-`Rectangle.all` should return rectangles **and** squares, the query should
-become
+`Rectangle.all` should now return rectangles **and** squares:
```sql
SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle", "Square")
```
-But there’s a subtle caveat here: How does Active Record know that the class
-`Square` exists at all?
+But there’s a caveat here: How does Active Record know that the class `Square`
+exists at all?
Even if the file `app/models/square.rb` exists and defines the `Square` class,
if no code yet used that class, `Rectangle.all` issues the query
@@ -944,8 +940,7 @@ SELECT "polygons".* FROM "polygons"
WHERE "polygons"."type" IN ("Rectangle")
```
-That is not a bug in Active Record, as we saw above the query does include all
-*known* descendants of `Rectangle`.
+That is not a bug, the query includes all *known* descendants of `Rectangle`.
A way to ensure this works correctly regardless of the order of execution is to
load the leaves of the tree by hand at the bottom of the file that defines the
@@ -958,15 +953,14 @@ end
require_dependency ‘square’
```
-Only the leaves that are **at least grandchildren** have to be loaded that way.
-Direct subclasses do not need to be preloaded, and if the hierarchy is deeper
-intermediate superclasses will be autoloaded recursively from the bottom because
-their constant will appear in the definitions.
+Only the leaves that are **at least grandchildren** have to be loaded that
+way. Direct subclasses do not need to be preloaded and, if the hierarchy is
+deeper, intermediate classes will be autoloaded recursively from the bottom
+because their constant will appear in the class definitions as superclass.
### Autoloading and `require`
-Files defining constants that should be autoloaded should never be loaded with
-`require`:
+Files defining constants to be autoloaded should never be `require`d:
```ruby
require 'user' # DO NOT DO THIS
@@ -976,25 +970,21 @@ class UsersController < ApplicationController
end
```
-If some part of the application autoloads the `User` constant before, then the
-application will interpret `app/models/user.rb` twice in development mode.
+There are two possible gotchas here in development mode:
-As we saw before, in development mode autoloading uses `Kernel#load` by default.
-Since `load` does not store the name of the interpreted file in
-`$LOADED_FEATURES` (`$"`) `require` executes, again, `app/models/user.rb`.
+1. If `User` is autoloaded before reaching the `require`, `app/models/user.rb`
+runs again because `load` does not update `$LOADED_FEATURES`.
-On the other hand, if `app/controllers/users_controllers.rb` happens to be
-evaluated before `User` is autoloaded then dependencies won’t mark `User` as an
-autoloaded constant, and therefore changes to `app/models/user.rb` won’t be
-updated in development mode.
+2. If the `require` runs first Rails does not mark `User` as an autoloaded
+constant and changes to `app/models/user.rb` aren't reloaded.
-Just follow the flow and use constant autoloading always, never mix autoloading
-and `require`. As a last resort, if some file absolutely needs to load a certain
-file by hand use `require_dependency` to play nice with constant autoloading.
-This option is rarely needed in practice, though.
+Just follow the flow and use constant autoloading always, never mix
+autoloading and `require`. As a last resort, if some file absolutely needs to
+load a certain file use `require_dependency` to play nice with constant
+autoloading. This option is rarely needed in practice, though.
Of course, using `require` in autoloaded files to load ordinary 3rd party
-libraries is fine, and Rails is able to distinguish their constants, so they are
+libraries is fine, and Rails is able to distinguish their constants, they are
not marked as autoloaded.
### Autoloading and Initializers
@@ -1002,24 +992,22 @@ not marked as autoloaded.
Consider this assignment in `config/initializers/set_auth_service.rb`:
```ruby
-AUTH_SERVICE = Rails.env.production? ? RealAuthService : MockedAuthService
+AUTH_SERVICE = if Rails.env.production?
+ RealAuthService
+else
+ MockedAuthService
+end
```
-The purpose of this setup would be that the application code uses always
-`AUTH_SERVICE` and that constant holds the proper class for the runtime
-environment. In development mode `MockedAuthService` gets autoloaded when the
-initializer is run. Let’s suppose we do some requests, change the implementation
-of `MockedAuthService`, and hit the application again. To our surprise the
-changes are not reflected. Why?
+The purpose of this setup would be that the application uses the class that
+corresponds to the environment via `AUTH_SERVICE`. In development mode
+`MockedAuthService` gets autoloaded when the initializer runs. Let’s suppose
+we do some requests, change its implementation, and hit the application again.
+To our surprise the changes are not reflected. Why?
-As we saw earlier, Rails wipes autoloaded constants by removing them from their
-containers using `remove_const`. But the object the constant holds may remain
-stored somewhere else. Constant removal can’t do anything about that.
-
-That is precisely the case in this example. `AUTH_SERVICE` stores the original
-class object which is perfectly functional regardless of the fact that there is
-no longer a constant in `Object` that matches its class name. The class object
-is independent of the constants it may or may not be stored in.
+As [we saw earlier](#constant-reloading), Rails removes autoloaded constants,
+but `AUTH_SERVICE` stores the original class object. Stale, non-reachable
+using the original constant, but perfectly functional.
The following code summarizes the situation:
@@ -1040,10 +1028,10 @@ C # => uninitialized constant C (NameError)
Because of that, it is not a good idea to autoload constants on application
initialization.
-In the case above we could for instance implement a dynamic access point that
-returns something that depends on the environment:
+In the case above we could implement a dynamic access point:
```ruby
+# app/models/auth_service.rb
class AuthService
if Rails.env.production?
def self.instance
@@ -1057,32 +1045,28 @@ class AuthService
end
```
-and have the application use `AuthService.instance` instead of `AUTH_SERVICE`.
-The code in that `AuthService` would be loaded on demand and be
-autoload-friendly.
+and have the application use `AuthService.instance` instead. `AuthService`
+would be loaded on demand and be autoload-friendly.
### `require_dependency` and Initializers
-As we saw before, `require_dependency` loads files in a autoloading-friendly
+As we saw before, `require_dependency` loads files in an autoloading-friendly
way. Normally, though, such a call does not make sense in an initializer.
-`require_dependency` provides a way to ensure a certain constant is defined at
-some point regardless of the execution path, and one could think about doing
-some calls in an initializer to make sure certain constants are loaded upfront,
-for example as an attempt to address the gotcha with STIs.
+One could think about doing some [`require_dependency`](#require-dependency)
+calls in an initializer to make sure certain constants are loaded upfront, for
+example as an attempt to address the [gotcha with STIs](#autoloading-and-sti).
-Problem is, in development mode all autoloaded constants are wiped on a
-subsequent request as soon as there is some relevant change in the file system.
-When that happens the application is in the very same situation the initializer
-wanted to avoid!
+Problem is, in development mode [autoloaded constants are wiped](#constant-reloading)
+if there is any relevant change in the file system. If that happens then
+we are in the very same situation the initializer wanted to avoid!
Calls to `require_dependency` have to be strategically written in autoloaded
spots.
### When Constants aren't Missed
-Let’s imagine that a Rails application has an `Image` model, and a subclass
-`Hotel::Image`:
+Let's consider an `Image` model, superclass of `Hotel::Image`:
```ruby
# app/models/image.rb
@@ -1110,8 +1094,7 @@ end
```
The intention is to subclass `Hotel::Image`, but which is actually the
-superclass of `Hotel::Poster`? Well, it depends on the order of execution of the
-files:
+superclass of `Hotel::Poster`? Well, it depends on the order of execution:
1. If neither `app/models/image.rb` nor `app/models/hotel/image.rb` have been
loaded at that point, the superclass is `Hotel::Image` because Rails is told
@@ -1125,10 +1108,8 @@ is `Hotel::Image` because Ruby is able to resolve the constant. Good.
is `Image`. Gotcha!
The last scenario (3) may be surprising. Why isn't `Hotel::Image` autoloaded?
-
-Constant autoloading cannot happen at that point because Ruby is able to
-resolve `Image` as a top-level constant, in consequence autoloading is not
-triggered.
+Because Ruby is able to resolve `Image` as a top-level constant, so
+autoloading does not even get a chance.
Most of the time, these kind of ambiguities can be resolved using qualified
constants. In this case we would write
@@ -1140,11 +1121,9 @@ module Hotel
end
```
-That class definition now is robust. No matter which files have been
-previously loaded, we know for certain that the superclass is unambiguously
-set.
+That class definition now is robust.
-It is interesting to note here that fix works because `Hotel` is a module, and
+It is interesting to note here that the fix works because `Hotel` is a module, and
`Hotel::Image` won’t look for `Image` in `Object` as it would if `Hotel` was a
class with `Object` in its ancestors. If `Hotel` was a class we would resort to
loading `Hotel::Image` with `require_dependency`. Furthermore, with that
@@ -1152,7 +1131,7 @@ solution the qualified name would no longer be necessary.
### Autoloading within Singleton Classes
-Let’s suppose we have these class definitions:
+Let's suppose we have these class definitions:
```ruby
# app/models/hotel/services.rb
@@ -1171,17 +1150,15 @@ module Hotel
end
```
-1. If `Hotel::Services` is known by the time `Hotel::GeoLocation` is being loaded,
-everything works because `Hotel` belongs to the nesting when the singleton class
-of `Hotel::GeoLocation` is opened, and thus Ruby itself is able to resolve the
-constant.
+If `Hotel::Services` is known by the time `app/models/hotel/geo_location.rb`
+is being loaded, `Services` is resolved by Ruby because `Hotel` belongs to the
+nesting when the singleton class of `Hotel::GeoLocation` is opened.
-2. But if `Hotel::Services` is not known and we rely on autoloading for the
-`Services` constant in `Hotel::GeoLocation`, Rails is not able to find
-`Hotel::Services`. The application raises `NameError`.
+But if `Hotel::Services` is not known, Rails is not able to autoload it, the
+application raises `NameError`.
The reason is that autoloading is triggered for the singleton class, which is
-anonymous, and as we [saw before](#generic-procedure), Rails only checks the
+anonymous, and as [we saw before](#generic-procedure), Rails only checks the
top-level namespace in that edge case.
An easy solution to this caveat is to qualify the constant:
@@ -1228,7 +1205,8 @@ c.user # surprisingly fine, User
c.user # NameError: uninitialized constant C::User
```
-because it detects a parent namespace already has the constant.
+because it detects a parent namespace already has the constant (see [Qualified
+References](#qualified-references).)
As with pure Ruby, within the body of a direct descendant of `BasicObject` use
always absolute constant paths:
diff --git a/guides/source/security.md b/guides/source/security.md
index b1c5b22338..b3869b1ba5 100644
--- a/guides/source/security.md
+++ b/guides/source/security.md
@@ -942,7 +942,7 @@ unless params[:token].nil?
end
```
-When `params[:token]` is one of: `[]`, `[nil]`, `[nil, nil, ...]` or
+When `params[:token]` is one of: `[nil]`, `[nil, nil, ...]` or
`['foo', nil]` it will bypass the test for `nil`, but `IS NULL` or
`IN ('foo', NULL)` where clauses still will be added to the SQL query.
@@ -953,9 +953,9 @@ request:
| JSON | Parameters |
|-----------------------------------|--------------------------|
| `{ "person": null }` | `{ :person => nil }` |
-| `{ "person": [] }` | `{ :person => nil }` |
-| `{ "person": [null] }` | `{ :person => nil }` |
-| `{ "person": [null, null, ...] }` | `{ :person => nil }` |
+| `{ "person": [] }` | `{ :person => [] }` |
+| `{ "person": [null] }` | `{ :person => [] }` |
+| `{ "person": [null, null, ...] }` | `{ :person => [] }` |
| `{ "person": ["foo", null] }` | `{ :person => ["foo"] }` |
It is possible to return to old behaviour and disable `deep_munge` configuring