Use irb code fences where applicable [ci-skip]

Using `irb` code fences and the appropriate prompt syntax results in
better syntax highlighting.
This commit is contained in:
Jonathan Hefner 2020-10-31 16:44:05 -05:00
parent 82ab903653
commit 3c9d7a268f
17 changed files with 707 additions and 526 deletions

@ -520,8 +520,7 @@ XmlMini.backend = 'LibXML'
The `Time` and `TimeWithZone` classes include an `xmlschema` method to return the time in an XML-friendly string. As of Rails 2.3, `TimeWithZone` supports the same argument for specifying the number of digits in the fractional second part of the returned string that `Time` does:
```ruby
>> Time.zone.now.xmlschema(6)
=> "2009-01-16T13:00:06.13653Z"
Time.zone.now.xmlschema(6) # => "2009-01-16T13:00:06.13653Z"
```
* Lead Contributor: [Nicholas Dainty](http://www.workingwithrails.com/person/13536-nicholas-dainty)

@ -144,8 +144,7 @@ The `direct` method allows creation of custom URL helpers.
``` ruby
direct(:homepage) { "http://www.rubyonrails.org" }
>> homepage_url
=> "http://www.rubyonrails.org"
homepage_url # => "http://www.rubyonrails.org"
```
The return value of the block must be a valid argument for the `url_for`

@ -49,12 +49,17 @@ class Person
send(attribute) > 100
end
end
```
person = Person.new
person.age = 110
person.age_highest? # => true
person.reset_age # => 0
person.age_highest? # => false
```irb
irb> person = Person.new
irb> person.age = 110
irb> person.age_highest?
=> true
irb> person.reset_age
=> 0
irb> person.age_highest?
=> false
```
### Callbacks
@ -102,11 +107,16 @@ class Person
nil
end
end
```
person = Person.new
person.to_model == person # => true
person.to_key # => nil
person.to_param # => nil
```irb
irb> person = Person.new
irb> person.to_model == person
=> true
irb> person.to_key
=> nil
irb> person.to_param
=> nil
```
### Dirty
@ -149,51 +159,62 @@ end
#### Querying object directly for its list of all changed attributes.
```ruby
person = Person.new
person.changed? # => false
```irb
irb> person = Person.new
irb> person.changed?
=> false
person.first_name = "First Name"
person.first_name # => "First Name"
irb> person.first_name = "First Name"
irb> person.first_name
=> "First Name"
# returns true if any of the attributes have unsaved changes.
person.changed? # => true
# Returns true if any of the attributes have unsaved changes.
irb> person.changed?
=> true
# returns a list of attributes that have changed before saving.
person.changed # => ["first_name"]
# Returns a list of attributes that have changed before saving.
irb> person.changed
=> ["first_name"]
# returns a Hash of the attributes that have changed with their original values.
person.changed_attributes # => {"first_name"=>nil}
# Returns a Hash of the attributes that have changed with their original values.
irb> person.changed_attributes
=> {"first_name"=>nil}
# returns a Hash of changes, with the attribute names as the keys, and the
# values as an array of the old and new values for that field.
person.changes # => {"first_name"=>[nil, "First Name"]}
# Returns a Hash of changes, with the attribute names as the keys, and the values as an array of the old and new values for that field.
irb> person.changes
=> {"first_name"=>[nil, "First Name"]}
```
#### Attribute based accessor methods
Track whether the particular attribute has been changed or not.
```ruby
```irb
irb> person.first_name
=> "First Name"
# attr_name_changed?
person.first_name # => "First Name"
person.first_name_changed? # => true
irb> person.first_name_changed?
=> true
```
Track the previous value of the attribute.
```ruby
```irb
# attr_name_was accessor
person.first_name_was # => nil
irb> person.first_name_was
=> nil
```
Track both previous and current value of the changed attribute. Returns an array
if changed, otherwise returns nil.
```ruby
```irb
# attr_name_change
person.first_name_change # => [nil, "First Name"]
person.last_name_change # => nil
irb> person.first_name_change
=> [nil, "First Name"]
irb> person.last_name_change
=> nil
```
### Validations
@ -211,17 +232,23 @@ class Person
validates_format_of :email, with: /\A([^\s]+)((?:[-a-z0-9]\.)[a-z]{2,})\z/i
validates! :token, presence: true
end
```
person = Person.new
person.token = "2b1f325"
person.valid? # => false
person.name = 'vishnu'
person.email = 'me'
person.valid? # => false
person.email = 'me@vishnuatrai.com'
person.valid? # => true
person.token = nil
person.valid? # => raises ActiveModel::StrictValidationFailed
```irb
irb> person = Person.new
irb> person.token = "2b1f325"
irb> person.valid?
=> false
irb> person.name = 'vishnu'
irb> person.email = 'me'
irb> person.valid?
=> false
irb> person.email = 'me@vishnuatrai.com'
irb> person.valid?
=> true
irb> person.token = nil
irb> person.valid?
ActiveModel::StrictValidationFailed
```
### Naming
@ -277,14 +304,16 @@ When including `ActiveModel::Model` you get some features like:
It also gives you the ability to initialize an object with a hash of attributes,
much like any Active Record object.
```ruby
email_contact = EmailContact.new(name: 'David',
email: 'david@example.com',
message: 'Hello World')
email_contact.name # => 'David'
email_contact.email # => 'david@example.com'
email_contact.valid? # => true
email_contact.persisted? # => false
```irb
irb> email_contact = EmailContact.new(name: 'David', email: 'david@example.com', message: 'Hello World')
irb> email_contact.name
=> "David"
irb> email_contact.email
=> "david@example.com"
irb> email_contact.valid?
=> true
irb> email_contact.persisted?
=> false
```
Any class that includes `ActiveModel::Model` can be used with `form_with`,
@ -311,11 +340,13 @@ end
Now you can access a serialized Hash of your object using the `serializable_hash` method.
```ruby
person = Person.new
person.serializable_hash # => {"name"=>nil}
person.name = "Bob"
person.serializable_hash # => {"name"=>"Bob"}
```irb
irb> person = Person.new
irb> person.serializable_hash
=> {"name"=>nil}
irb> person.name = "Bob"
irb> person.serializable_hash
=> {"name"=>"Bob"}
```
#### ActiveModel::Serializers
@ -344,11 +375,13 @@ end
The `as_json` method, similar to `serializable_hash`, provides a Hash representing
the model.
```ruby
person = Person.new
person.as_json # => {"name"=>nil}
person.name = "Bob"
person.as_json # => {"name"=>"Bob"}
```irb
irb> person = Person.new
irb> person.as_json
=> {"name"=>nil}
irb> person.name = "Bob"
irb> person.as_json
=> {"name"=>"Bob"}
```
You can also define the attributes for a model from a JSON string.
@ -374,11 +407,13 @@ end
Now it is possible to create an instance of `Person` and set attributes using `from_json`.
```ruby
json = { name: 'Bob' }.to_json
person = Person.new
person.from_json(json) # => #<Person:0x00000100c773f0 @name="Bob">
person.name # => "Bob"
```irb
irb> json = { name: 'Bob' }.to_json
irb> person = Person.new
irb> person.from_json(json)
=> #<Person:0x00000100c773f0 @name="Bob">
irb> person.name
=> "Bob"
```
### Translation
@ -483,39 +518,54 @@ class Person
attr_accessor :password_digest, :recovery_password_digest
end
```
person = Person.new
```irb
irb> person = Person.new
# When password is blank.
person.valid? # => false
irb> person.valid?
=> false
# When the confirmation doesn't match the password.
person.password = 'aditya'
person.password_confirmation = 'nomatch'
person.valid? # => false
irb> person.password = 'aditya'
irb> person.password_confirmation = 'nomatch'
irb> person.valid?
=> false
# When the length of password exceeds 72.
person.password = person.password_confirmation = 'a' * 100
person.valid? # => false
irb> person.password = person.password_confirmation = 'a' * 100
irb> person.valid?
=> false
# When only password is supplied with no password_confirmation.
person.password = 'aditya'
person.valid? # => true
irb> person.password = 'aditya'
irb> person.valid?
=> true
# When all validations are passed.
person.password = person.password_confirmation = 'aditya'
person.valid? # => true
irb> person.password = person.password_confirmation = 'aditya'
irb> person.valid?
=> true
person.recovery_password = "42password"
irb> person.recovery_password = "42password"
person.authenticate('aditya') # => person
person.authenticate('notright') # => false
person.authenticate_password('aditya') # => person
person.authenticate_password('notright') # => false
irb> person.authenticate('aditya')
=> #<Person> # == person
irb> person.authenticate('notright')
=> false
irb> person.authenticate_password('aditya')
=> #<Person> # == person
irb> person.authenticate_password('notright')
=> false
person.authenticate_recovery_password('42password') # => person
person.authenticate_recovery_password('notright') # => false
irb> person.authenticate_recovery_password('42password')
=> #<Person> # == person
irb> person.authenticate_recovery_password('notright')
=> false
person.password_digest # => "$2a$04$gF8RfZdoXHvyTjHhiU4ZsO.kQqV9oonYZu31PRE4hLQn3xM2qkpIy"
person.recovery_password_digest # => "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"
irb> person.password_digest
=> "$2a$04$gF8RfZdoXHvyTjHhiU4ZsO.kQqV9oonYZu31PRE4hLQn3xM2qkpIy"
irb> person.recovery_password_digest
=> "$2a$04$iOfhwahFymCs5weB3BNH/uXkTG65HR.qpW.bNhEjFP3ftli3o5DQC"
```

@ -339,10 +339,14 @@ A quick example to illustrate:
class User < ApplicationRecord
validates :name, presence: true
end
```
user = User.new
user.save # => false
user.save! # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
```irb
irb> user = User.new
irb> user.save
=> false
irb> user.save!
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
```
You can learn more about validations in the [Active Record Validations

@ -141,12 +141,14 @@ class User < ApplicationRecord
puts "You have found an object!"
end
end
```
>> User.new
```irb
irb> User.new
You have initialized an object!
=> #<User id: nil>
>> User.first
irb> User.first
You have found an object!
You have initialized an object!
=> #<User id: 1>
@ -162,11 +164,13 @@ class User < ApplicationRecord
puts "You have touched an object"
end
end
```
>> u = User.create(name: 'Kuldeep')
```irb
irb> u = User.create(name: 'Kuldeep')
=> #<User id: 1, name: "Kuldeep", created_at: "2013-11-25 12:17:49", updated_at: "2013-11-25 12:17:49">
>> u.touch
irb> u.touch
You have touched an object
=> true
```
@ -190,12 +194,13 @@ class Company < ApplicationRecord
puts 'Employee/Company was touched'
end
end
```
>> @employee = Employee.last
```irb
irb> @employee = Employee.last
=> #<Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05">
# triggers @employee.company.touch
>> @employee.touch
irb> @employee.touch # triggers @employee.company.touch
An Employee was touched
Employee/Company was touched
=> true
@ -293,12 +298,14 @@ class Article < ApplicationRecord
puts 'Article destroyed'
end
end
```
>> user = User.first
```irb
irb> user = User.first
=> #<User id: 1>
>> user.articles.create!
irb> user.articles.create!
=> #<Article id: 1, user_id: 1>
>> user.destroy
irb> user.destroy
Article destroyed
=> #<User id: 1>
```
@ -475,13 +482,13 @@ class User < ApplicationRecord
puts 'User was saved to database'
end
end
```
# prints nothing
>> @user = User.create
```irb
irb> @user = User.create # prints nothing
# updating @user
>> @user.save
=> User was saved to database
irb> @user.save # updating @user
User was saved to database
```
There is also an alias for using the `after_commit` callback for both create and update together:
@ -497,12 +504,12 @@ class User < ApplicationRecord
puts 'User was saved to database'
end
end
# creating a User
>> @user = User.create
=> User was saved to database
# updating @user
>> @user.save
=> User was saved to database
```
```irb
irb> @user = User.create # creating a User
User was saved to database
irb> @user.save # updating @user
User was saved to database
```

@ -96,22 +96,26 @@ ActiveRecord::Schema.define do
t.hstore 'settings'
end
end
```
```ruby
# app/models/profile.rb
class Profile < ApplicationRecord
end
```
# Usage
Profile.create(settings: { "color" => "blue", "resolution" => "800x600" })
```irb
irb> Profile.create(settings: { "color" => "blue", "resolution" => "800x600" })
profile = Profile.first
profile.settings # => {"color"=>"blue", "resolution"=>"800x600"}
irb> profile = Profile.first
irb> profile.settings
=> {"color"=>"blue", "resolution"=>"800x600"}
profile.settings = {"color" => "yellow", "resolution" => "1280x1024"}
profile.save!
irb> profile.settings = {"color" => "yellow", "resolution" => "1280x1024"}
irb> profile.save!
Profile.where("settings->'color' = ?", "yellow")
# => #<ActiveRecord::Relation [#<Profile id: 1, settings: {"color"=>"yellow", "resolution"=>"1280x1024"}>]>
irb> Profile.where("settings->'color' = ?", "yellow")
=> #<ActiveRecord::Relation [#<Profile id: 1, settings: {"color"=>"yellow", "resolution"=>"1280x1024"}>]>
```
### JSON and JSONB
@ -129,20 +133,24 @@ end
create_table :events do |t|
t.jsonb 'payload'
end
```
```ruby
# app/models/event.rb
class Event < ApplicationRecord
end
```
# Usage
Event.create(payload: { kind: "user_renamed", change: ["jack", "john"]})
```irb
irb> Event.create(payload: { kind: "user_renamed", change: ["jack", "john"]})
event = Event.first
event.payload # => {"kind"=>"user_renamed", "change"=>["jack", "john"]}
irb> event = Event.first
irb> event.payload
=> {"kind"=>"user_renamed", "change"=>["jack", "john"]}
## Query based on JSON document
# The -> operator returns the original JSON type (which might be an object), whereas ->> returns text
Event.where("payload->>'kind' = ?", "user_renamed")
irb> Event.where("payload->>'kind' = ?", "user_renamed")
```
### Range Types
@ -157,27 +165,31 @@ This type is mapped to Ruby [`Range`](https://ruby-doc.org/core-2.5.0/Range.html
create_table :events do |t|
t.daterange 'duration'
end
```
```ruby
# app/models/event.rb
class Event < ApplicationRecord
end
```
# Usage
Event.create(duration: Date.new(2014, 2, 11)..Date.new(2014, 2, 12))
```irb
irb> Event.create(duration: Date.new(2014, 2, 11)..Date.new(2014, 2, 12))
event = Event.first
event.duration # => Tue, 11 Feb 2014...Thu, 13 Feb 2014
irb> event = Event.first
irb> event.duration
=> Tue, 11 Feb 2014...Thu, 13 Feb 2014
## All Events on a given date
Event.where("duration @> ?::date", Date.new(2014, 2, 12))
irb> Event.where("duration @> ?::date", Date.new(2014, 2, 12))
## Working with range bounds
event = Event.
select("lower(duration) AS starts_at").
select("upper(duration) AS ends_at").first
irb> event = Event.select("lower(duration) AS starts_at").select("upper(duration) AS ends_at").first
event.starts_at # => Tue, 11 Feb 2014
event.ends_at # => Thu, 13 Feb 2014
irb> event.starts_at
=> Tue, 11 Feb 2014
irb> event.ends_at
=> Thu, 13 Feb 2014
```
### Composite Types
@ -207,17 +219,21 @@ SQL
create_table :contacts do |t|
t.column :address, :full_address
end
```
```ruby
# app/models/contact.rb
class Contact < ApplicationRecord
end
```
# Usage
Contact.create address: "(Paris,Champs-Élysées)"
contact = Contact.first
contact.address # => "(Paris,Champs-Élysées)"
contact.address = "(Paris,Rue Basse)"
contact.save!
```irb
irb> Contact.create address: "(Paris,Champs-Élysées)"
irb> contact = Contact.first
irb> contact.address
=> "(Paris,Champs-Élysées)"
irb> contact.address = "(Paris,Rue Basse)"
irb> contact.save!
```
### Enumerated Types
@ -246,18 +262,22 @@ def down
DROP TYPE article_status;
SQL
end
```
```ruby
# app/models/article.rb
class Article < ApplicationRecord
end
```
# Usage
Article.create status: "draft"
article = Article.first
article.status # => "draft"
```irb
irb> Article.create status: "draft"
irb> article = Article.first
irb> article.status
=> "draft"
article.status = "published"
article.save!
irb> article.status = "published"
irb> article.save!
```
To add a new value before/after existing one you should use [ALTER TYPE](https://www.postgresql.org/docs/current/static/sql-altertype.html):
@ -301,16 +321,20 @@ extension to use uuid.
create_table :revisions do |t|
t.uuid :identifier
end
```
```ruby
# app/models/revision.rb
class Revision < ApplicationRecord
end
```
# Usage
Revision.create identifier: "A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11"
```irb
irb> Revision.create identifier: "A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11"
revision = Revision.first
revision.identifier # => "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"
irb> revision = Revision.first
irb> revision.identifier
=> "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"
```
You can use `uuid` type to define references in migrations:
@ -348,18 +372,23 @@ See [this section](#uuid-primary-keys) for more details on using UUIDs as primar
create_table :users, force: true do |t|
t.column :settings, "bit(8)"
end
```
```ruby
# app/models/user.rb
class User < ApplicationRecord
end
```
# Usage
User.create settings: "01010011"
user = User.first
user.settings # => "01010011"
user.settings = "0xAF"
user.settings # => 10101111
user.save!
```irb
irb> User.create settings: "01010011"
irb> user = User.first
irb> user.settings
=> "01010011"
irb> user.settings = "0xAF"
irb> user.settings
=> 10101111
irb> user.save!
```
### Network Address Types
@ -377,24 +406,25 @@ create_table(:devices, force: true) do |t|
t.cidr 'network'
t.macaddr 'address'
end
```
```ruby
# app/models/device.rb
class Device < ApplicationRecord
end
```
# Usage
macbook = Device.create(ip: "192.168.1.12",
network: "192.168.2.0/24",
address: "32:01:16:6d:05:ef")
```irb
irb> macbook = Device.create(ip: "192.168.1.12", network: "192.168.2.0/24", address: "32:01:16:6d:05:ef")
macbook.ip
# => #<IPAddr: IPv4:192.168.1.12/255.255.255.255>
irb> macbook.ip
=> #<IPAddr: IPv4:192.168.1.12/255.255.255.255>
macbook.network
# => #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
irb> macbook.network
=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
macbook.address
# => "32:01:16:6d:05:ef"
irb> macbook.address
=> "32:01:16:6d:05:ef"
```
### Geometric Types
@ -416,16 +446,20 @@ This type is mapped to [`ActiveSupport::Duration`](http://api.rubyonrails.org/cl
create_table :events do |t|
t.interval 'duration'
end
```
```ruby
# app/models/event.rb
class Event < ApplicationRecord
end
```
# Usage
Event.create(duration: 2.days)
```irb
irb> Event.create(duration: 2.days)
event = Event.first
event.duration # => 2 days
irb> event = Event.first
irb> event.duration
=> 2 days
```
UUID Primary Keys
@ -440,14 +474,18 @@ enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto')
create_table :devices, id: :uuid do |t|
t.string :kind
end
```
```ruby
# app/models/device.rb
class Device < ApplicationRecord
end
```
# Usage
device = Device.create
device.id # => "814865cd-5a1d-4771-9306-4268f188fe9e"
```ruby
irb> device = Device.create
irb> device.id
=> "814865cd-5a1d-4771-9306-4268f188fe9e"
```
NOTE: `gen_random_uuid()` (from `pgcrypto`) is assumed if no `:default` option was
@ -514,7 +552,9 @@ CREATE VIEW articles AS
FROM "TBL_ART"
WHERE "BL_ARCH" = 'f'
SQL
```
```ruby
# app/models/article.rb
class Article < ApplicationRecord
self.primary_key = "id"
@ -522,18 +562,17 @@ class Article < ApplicationRecord
update_attribute :archived, true
end
end
```
# Usage
first = Article.create! title: "Winter is coming",
status: "published",
published_at: 1.year.ago
second = Article.create! title: "Brace yourself",
status: "draft",
published_at: 1.month.ago
```irb
irb> first = Article.create! title: "Winter is coming", status: "published", published_at: 1.year.ago
irb> second = Article.create! title: "Brace yourself", status: "draft", published_at: 1.month.ago
Article.count # => 2
first.archive!
Article.count # => 1
irb> Article.count
=> 2
irb> first.archive!
irb> Article.count
=> 1
```
NOTE: This application only cares about non-archived `Articles`. A view also

@ -138,10 +138,10 @@ Active Record provides several different ways of retrieving a single object.
Using the `find` method, you can retrieve the object corresponding to the specified _primary key_ that matches any supplied options. For example:
```ruby
```irb
# Find the customer with primary key (id) 10.
customer = Customer.find(10)
# => #<Customer id: 10, first_name: "Ryan">
irb> customer = Customer.find(10)
=> #<Customer id: 10, first_name: "Ryan">
```
The SQL equivalent of the above is:
@ -154,10 +154,10 @@ The `find` method will raise an `ActiveRecord::RecordNotFound` exception if no m
You can also use this method to query for multiple objects. Call the `find` method and pass in an array of primary keys. The return will be an array containing all of the matching records for the supplied _primary keys_. For example:
```ruby
```irb
# Find the customers with primary keys 1 and 10.
customers = Customer.find([1, 10]) # Or even Customer.find(1, 10)
# => [#<Customer id: 1, first_name: "Lifo">, #<Customer id: 10, first_name: "Ryan">]
irb> customers = Customer.find([1, 10]) # OR Customer.find(1, 10)
=> [#<Customer id: 1, first_name: "Lifo">, #<Customer id: 10, first_name: "Ryan">]
```
The SQL equivalent of the above is:
@ -172,9 +172,9 @@ WARNING: The `find` method will raise an `ActiveRecord::RecordNotFound` exceptio
The `take` method retrieves a record without any implicit ordering. For example:
```ruby
customer = Customer.take
# => #<Customer id: 1, first_name: "Lifo">
```irb
irb> customer = Customer.take
=> #<Customer id: 1, first_name: "Lifo">
```
The SQL equivalent of the above is:
@ -187,12 +187,9 @@ The `take` method returns `nil` if no record is found and no exception will be r
You can pass in a numerical argument to the `take` method to return up to that number of results. For example
```ruby
customers = Customer.take(2)
# => [
# #<Customer id: 1, first_name: "Lifo">,
# #<Customer id: 220, first_name: "Sara">
# ]
```irb
irb> customers = Customer.take(2)
=> [#<Customer id: 1, first_name: "Lifo">, #<Customer id: 220, first_name: "Sara">]
```
The SQL equivalent of the above is:
@ -209,9 +206,9 @@ TIP: The retrieved record may vary depending on the database engine.
The `first` method finds the first record ordered by primary key (default). For example:
```ruby
customer = Customer.first
# => #<Customer id: 1, first_name: "Lifo">
```irb
irb> customer = Customer.first
=> #<Customer id: 1, first_name: "Lifo">
```
The SQL equivalent of the above is:
@ -226,13 +223,9 @@ If your [default scope](active_record_querying.html#applying-a-default-scope) co
You can pass in a numerical argument to the `first` method to return up to that number of results. For example
```ruby
customers = Customer.first(3)
# => [
# #<Customer id: 1, first_name: "Lifo">,
# #<Customer id: 2, first_name: "Fifo">,
# #<Customer id: 3, first_name: "Filo">
# ]
```irb
irb> customers = Customer.first(3)
=> [#<Customer id: 1, first_name: "Lifo">, #<Customer id: 2, first_name: "Fifo">, #<Customer id: 3, first_name: "Filo">]
```
The SQL equivalent of the above is:
@ -243,9 +236,9 @@ SELECT * FROM customers ORDER BY customers.id ASC LIMIT 3
On a collection that is ordered using `order`, `first` will return the first record ordered by the specified attribute for `order`.
```ruby
customer = Customer.order(:first_name).first
# => #<Customer id: 2, first_name: "Fifo">
```irb
irb> customer = Customer.order(:first_name).first
=> #<Customer id: 2, first_name: "Fifo">
```
The SQL equivalent of the above is:
@ -260,9 +253,9 @@ The `first!` method behaves exactly like `first`, except that it will raise `Act
The `last` method finds the last record ordered by primary key (default). For example:
```ruby
customer = Customer.last
# => #<Customer id: 221, first_name: "Russel">
```irb
irb> customer = Customer.last
=> #<Customer id: 221, first_name: "Russel">
```
The SQL equivalent of the above is:
@ -277,13 +270,9 @@ If your [default scope](active_record_querying.html#applying-a-default-scope) co
You can pass in a numerical argument to the `last` method to return up to that number of results. For example
```ruby
customers = Customer.last(3)
# => [
# #<Customer id: 219, first_name: "James">,
# #<Customer id: 220, first_name: "Sara">,
# #<Customer id: 221, first_name: "Russel">
# ]
```irb
irb> customers = Customer.last(3)
=> [#<Customer id: 219, first_name: "James">, #<Customer id: 220, first_name: "Sara">, #<Customer id: 221, first_name: "Russel">]
```
The SQL equivalent of the above is:
@ -294,9 +283,9 @@ SELECT * FROM customers ORDER BY customers.id DESC LIMIT 3
On a collection that is ordered using `order`, `last` will return the last record ordered by the specified attribute for `order`.
```ruby
customer = Customer.order(:first_name).last
# => #<Customer id: 220, first_name: "Sara">
```irb
irb> customer = Customer.order(:first_name).last
=> #<Customer id: 220, first_name: "Sara">
```
The SQL equivalent of the above is:
@ -311,12 +300,12 @@ The `last!` method behaves exactly like `last`, except that it will raise `Activ
The `find_by` method finds the first record matching some conditions. For example:
```ruby
Customer.find_by first_name: 'Lifo'
# => #<Customer id: 1, first_name: "Lifo">
```irb
irb> Customer.find_by first_name: 'Lifo'
=> #<Customer id: 1, first_name: "Lifo">
Customer.find_by first_name: 'Jon'
# => nil
irb> Customer.find_by first_name: 'Jon'
=> nil
```
It is equivalent to writing:
@ -333,9 +322,9 @@ SELECT * FROM customers WHERE (customers.first_name = 'Lifo') LIMIT 1
The `find_by!` method behaves exactly like `find_by`, except that it will raise `ActiveRecord::RecordNotFound` if no matching record is found. For example:
```ruby
Customer.find_by! first_name: 'does not exist'
# => ActiveRecord::RecordNotFound
```irb
irb> Customer.find_by! first_name: 'does not exist'
ActiveRecord::RecordNotFound
```
This is equivalent to writing:
@ -681,9 +670,9 @@ Customer.order("orders_count ASC", "created_at DESC")
If you want to call `order` multiple times, subsequent orders will be appended to the first:
```ruby
Customer.order("orders_count ASC").order("created_at DESC")
# SELECT * FROM customers ORDER BY orders_count ASC, created_at DESC
```irb
irb> Customer.order("orders_count ASC").order("created_at DESC")
SELECT * FROM customers ORDER BY orders_count ASC, created_at DESC
```
WARNING: In most database systems, on selecting fields with `distinct` from a result set using methods like `select`, `pluck` and `ids`; the `order` method will raise an `ActiveRecord::StatementInvalid` exception unless the field(s) used in `order` clause are included in the select list. See the next section for selecting fields from the result set.
@ -732,11 +721,11 @@ SELECT DISTINCT last_name FROM customers
You can also remove the uniqueness constraint:
```ruby
# Returns unique last_names
query = Customer.select(:last_name).distinct
# => Returns unique last_names
# Returns all last_names, even if there are duplicates
query.distinct(false)
# => Returns all last_names, even if there are duplicates
```
Limit and Offset
@ -793,9 +782,9 @@ GROUP BY created_at
To get the total of grouped items on a single query, call `count` after the `group`.
```ruby
Order.group(:status).count
# => { 'being_packed' => 7, 'shipped' => 12 }
```irb
irb> Order.group(:status).count
=> {"being_packed"=>7, "shipped"=>12}
```
The SQL that would be executed would be something like this:
@ -1387,15 +1376,17 @@ end
To call this `out_of_print` scope we can call it on either the class:
```ruby
Book.out_of_print # => [all books out of print]
```irb
irb> Book.out_of_print
=> #<ActiveRecord::Relation> # all out of print books
```
Or on an association consisting of `Book` objects:
```ruby
author = Author.first
author.books.out_of_print # => [all out of print books by this author]
```irb
irb> author = Author.first
irb> author.books.out_of_print
=> #<ActiveRecord::Relation> # all out of print books by `author`
```
Scopes are also chainable within scopes:
@ -1419,8 +1410,8 @@ end
Call the scope as if it were a class method:
```ruby
Book.costs_more_than(100.10)
```irb
irb> Book.costs_more_than(100.10)
```
However, this is just duplicating the functionality that would be provided to you by a class method.
@ -1435,8 +1426,8 @@ end
These methods will still be accessible on the association objects:
```ruby
author.books.costs_more_than(100.10)
```irb
irb> author.books.costs_more_than(100.10)
```
### Using conditionals
@ -1498,9 +1489,13 @@ updating a record. E.g.:
class Book < ApplicationRecord
default_scope { where(out_of_print: false) }
end
```
Book.new # => #<Book id: nil, out_of_print: false>
Book.unscoped.new # => #<Book id: nil, out_of_print: nil>
```irb
irb> Book.new
=> #<Book id: nil, out_of_print: false>
irb> Book.unscoped.new
=> #<Book id: nil, out_of_print: nil>
```
Be aware that, when given in the `Array` format, `default_scope` query arguments
@ -1510,8 +1505,11 @@ cannot be converted to a `Hash` for default attribute assignment. E.g.:
class Book < ApplicationRecord
default_scope { where("out_of_print = ?", false) }
end
```
Book.new # => #<Book id: nil, out_of_print: nil>
```irb
irb> Book.new
=> #<Book id: nil, out_of_print: nil>
```
### Merging of scopes
@ -1526,25 +1524,27 @@ class Book < ApplicationRecord
scope :recent, -> { where('year_published >= ?', Date.current.year - 50 )}
scope :old, -> { where('year_published < ?', Date.current.year - 50 )}
end
```
Book.out_of_print.old
# SELECT books.* FROM books WHERE books.out_of_print = 'true' AND books.year_published < 1969
```irb
irb> Book.out_of_print.old
SELECT books.* FROM books WHERE books.out_of_print = 'true' AND books.year_published < 1969
```
We can mix and match `scope` and `where` conditions and the final SQL
will have all conditions joined with `AND`.
```ruby
Book.in_print.where('price < 100')
# SELECT books.* FROM books WHERE books.out_of_print = 'false' AND books.price < 100
```irb
irb> Book.in_print.where('price < 100')
SELECT books.* FROM books WHERE books.out_of_print = 'false' AND books.price < 100
```
If we do want the last `where` clause to win then `Relation#merge` can
be used.
```ruby
Book.in_print.merge(Book.out_of_print)
# SELECT books.* FROM books WHERE books.out_of_print = true
```irb
irb> Book.in_print.merge(Book.out_of_print)
SELECT books.* FROM books WHERE books.out_of_print = true
```
One important caveat is that `default_scope` will be prepended in
@ -1557,15 +1557,17 @@ class Book < ApplicationRecord
scope :in_print, -> { where(out_of_print: false) }
scope :out_of_print, -> { where(out_of_print: true) }
end
```
Book.all
# SELECT books.* FROM books WHERE (year_published >= 1969)
```irb
irb> Book.all
SELECT books.* FROM books WHERE (year_published >= 1969)
Book.in_print
# SELECT books.* FROM books WHERE (year_published >= 1969) AND books.out_of_print = true
irb> Book.in_print
SELECT books.* FROM books WHERE (year_published >= 1969) AND books.out_of_print = true
Book.where('price > 50')
# SELECT books.* FROM books WHERE (year_published >= 1969) AND (price > 50)
irb> Book.where('price > 50')
SELECT books.* FROM books WHERE (year_published >= 1969) AND (price > 50)
```
As you can see above the `default_scope` is being merged in both
@ -1583,21 +1585,19 @@ Book.unscoped.load
This method removes all scoping and will do a normal query on the table.
```ruby
Book.unscoped.all
# SELECT books.* FROM books
```irb
irb> Book.unscoped.all
SELECT books.* FROM books
Book.where(out_of_print: true).unscoped.all
# SELECT books.* FROM books
irb> Book.where(out_of_print: true).unscoped.all
SELECT books.* FROM books
```
`unscoped` can also accept a block:
```ruby
Book.unscoped {
Book.out_of_print
}
# SELECT books.* FROM books WHERE books.out_of_print
```irb
irb> Book.unscoped { Book.out_of_print }
SELECT books.* FROM books WHERE books.out_of_print
```
Dynamic Finders
@ -1637,34 +1637,31 @@ end
These [scopes](#scopes) are created automatically and can be used to find all objects with or wihout a particular value for `status`:
```ruby
Order.shipped
# finds all orders with status == :shipped
Order.not_shipped
# finds all orders with status != :shipped
...
```irb
irb> Order.shipped
=> #<ActiveRecord::Relation> # all orders with status == :shipped
irb> Order.not_shipped
=> #<ActiveRecord::Relation> # all orders with status != :shipped
```
These instace methods are created automatically and query whether the model has that value for the `status` enum:
```ruby
order = Order.first
order.shipped?
# Returns true if status == :shipped
order.complete?
# Returns true if status == :complete
...
```irb
irb> order = Order.shipped.first
irb> order.shipped?
=> true
irb> order.complete?
=> false
```
These instance methods are created automatically and will first update the value of `status` to the named value
and then query whether or not the status has been successfully set to the value:
```ruby
order = Order.first
order.shipped!
# => UPDATE "orders" SET "status" = ?, "updated_at" = ? WHERE "orders"."id" = ? [["status", 0], ["updated_at", "2019-01-24 07:13:08.524320"], ["id", 1]]
# => true
...
```irb
irb> order = Order.first
irb> order.shipped!
UPDATE "orders" SET "status" = ?, "updated_at" = ? WHERE "orders"."id" = ? [["status", 0], ["updated_at", "2019-01-24 07:13:08.524320"], ["id", 1]]
=> true
```
Full documentation about enums can be found [here](https://api.rubyonrails.org/classes/ActiveRecord/Enum.html).
@ -1737,9 +1734,9 @@ The `find_or_create_by` method checks whether a record with the specified attrib
Suppose you want to find a customer named 'Andy', and if there's none, create one. You can do so by running:
```ruby
Customer.find_or_create_by(first_name: 'Andy')
# => #Customer id: 5, first_name: "Andy", last_name: nil, title: nil, visits: 0, orders_count: nil, lock_version: 0, created_at: "2019-01-17 07:06:45", updated_at: "2019-01-17 07:06:45"
```irb
irb> Customer.find_or_create_by(first_name: 'Andy')
=> #<Customer id: 5, first_name: "Andy", last_name: nil, title: nil, visits: 0, orders_count: nil, lock_version: 0, created_at: "2019-01-17 07:06:45", updated_at: "2019-01-17 07:06:45">
```
The SQL generated by this method looks like this:
@ -1787,9 +1784,9 @@ validates :orders_count, presence: true
to your `Customer` model. If you try to create a new `Customer` without passing an `orders_count`, the record will be invalid and an exception will be raised:
```ruby
Customer.find_or_create_by!(first_name: 'Andy')
# => ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
```irb
irb> Customer.find_or_create_by!(first_name: 'Andy')
ActiveRecord::RecordInvalid: Validation failed: Orders count can't be blank
```
### `find_or_initialize_by`
@ -1800,15 +1797,15 @@ means that a new model instance will be created in memory but won't be
saved to the database. Continuing with the `find_or_create_by` example, we
now want the customer named 'Nina':
```ruby
nina = Customer.find_or_initialize_by(first_name: 'Nina')
# => #<Customer id: nil, first_name: "Nina", orders_count: 0, locked: true, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
```irb
irb> nina = Customer.find_or_initialize_by(first_name: 'Nina')
=> #<Customer id: nil, first_name: "Nina", orders_count: 0, locked: true, created_at: "2011-08-30 06:09:27", updated_at: "2011-08-30 06:09:27">
nina.persisted?
# => false
irb> nina.persisted?
=> false
nina.new_record?
# => true
irb> nina.new_record?
=> true
```
Because the object is not yet stored in the database, the SQL generated looks like this:
@ -1819,9 +1816,9 @@ SELECT * FROM customers WHERE (customers.first_name = 'Nina') LIMIT 1
When you want to save it to the database, just call `save`:
```ruby
nina.save
# => true
```irb
irb> nina.save
=> true
```
Finding by SQL
@ -1829,15 +1826,9 @@ Finding by SQL
If you'd like to use your own SQL to find records in a table you can use `find_by_sql`. The `find_by_sql` method will return an array of objects even if the underlying query returns just a single record. For example you could run this query:
```ruby
Customer.find_by_sql("SELECT * FROM customers
INNER JOIN orders ON customers.id = orders.customer_id
ORDER BY customers.created_at desc")
# => [
# #<Customer id: 1, first_name: "Lucas" ...>,
# #<Customer id: 2, first_name: "Jan" ...>,
# ...
# ]
```irb
irb> Customer.find_by_sql("SELECT * FROM customers INNER JOIN orders ON customers.id = orders.customer_id ORDER BY customers.created_at desc")
=> [#<Customer id: 1, first_name: "Lucas" ...>, #<Customer id: 2, first_name: "Jan" ...>, ...]
```
`find_by_sql` provides you with a simple way of making custom calls to the database and retrieving instantiated objects.
@ -1849,30 +1840,27 @@ objects from the database using custom SQL just like `find_by_sql` but will not
This method will return an instance of `ActiveRecord::Result` class and calling `to_a` on this
object would return you an array of hashes where each hash indicates a record.
```ruby
Customer.connection.select_all("SELECT first_name, created_at FROM customers WHERE id = '1'").to_hash
# => [
# {"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"},
# {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}
# ]
```irb
irb> Customer.connection.select_all("SELECT first_name, created_at FROM customers WHERE id = '1'").to_hash
=> [{"first_name"=>"Rafael", "created_at"=>"2012-11-10 23:23:45.281189"}, {"first_name"=>"Eileen", "created_at"=>"2013-12-09 11:22:35.221282"}]
```
### `pluck`
`pluck` can be used to query single or multiple columns from the underlying table of a model. It accepts a list of column names as an argument and returns an array of values of the specified columns with the corresponding data type.
```ruby
Book.where(out_of_print: true).pluck(:id)
# SELECT id FROM books WHERE out_of_print = false
# => [1, 2, 3]
```irb
irb> Book.where(out_of_print: true).pluck(:id)
SELECT id FROM books WHERE out_of_print = false
=> [1, 2, 3]
Order.distinct.pluck(:status)
# SELECT DISTINCT status FROM orders
# => ['shipped', 'being_packed', 'cancelled']
irb> Order.distinct.pluck(:status)
SELECT DISTINCT status FROM orders
=> ["shipped", "being_packed", "cancelled"]
Customer.pluck(:id, :first_name)
# SELECT customers.id, customers.name FROM customers
# => [[1, 'David'], [2, 'Fran'], [3, 'Jose']]
irb> Customer.pluck(:id, :first_name)
SELECT customers.id, customers.name FROM customers
=> [[1, "David"], [2, "Fran"], [3, "Jose"]]
```
`pluck` makes it possible to replace code like:
@ -1904,63 +1892,66 @@ class Customer < ApplicationRecord
"I am #{first_name}"
end
end
```
Customer.select(:first_name).map &:name
# => ["I am David", "I am Jeremy", "I am Jose"]
```irb
irb> Customer.select(:first_name).map &:name
=> ["I am David", "I am Jeremy", "I am Jose"]
Customer.pluck(:first_name)
# => ["David", "Jeremy", "Jose"]
irb> Customer.pluck(:first_name)
=> ["David", "Jeremy", "Jose"]
```
You are not limited to querying fields from a single table, you can query multiple tables as well.
```
Order.joins(:customer, :books).pluck("orders.created_at, customers.email, books.title")
```irb
irb> Order.joins(:customer, :books).pluck("orders.created_at, customers.email, books.title")
```
Furthermore, unlike `select` and other `Relation` scopes, `pluck` triggers an immediate
query, and thus cannot be chained with any further scopes, although it can work with
scopes already constructed earlier:
```ruby
Customer.pluck(:first_name).limit(1)
# => NoMethodError: undefined method `limit' for #<Array:0x007ff34d3ad6d8>
```irb
irb> Customer.pluck(:first_name).limit(1)
NoMethodError: undefined method `limit' for #<Array:0x007ff34d3ad6d8>
Customer.limit(1).pluck(:first_name)
# => ["David"]
irb> Customer.limit(1).pluck(:first_name)
=> ["David"]
```
NOTE: You should also know that using `pluck` will trigger eager loading if the relation object contains include values, even if the eager loading is not necessary for the query. For example:
```ruby
# store association for reusing it
assoc = Customer.includes(:reviews)
assoc.pluck(:id)
# SELECT "customers"."id" FROM "customers" LEFT OUTER JOIN "reviews" ON "reviews"."id" = "customers"."review_id"
```irb
irb> assoc = Customer.includes(:reviews)
irb> assoc.pluck(:id)
SELECT "customers"."id" FROM "customers" LEFT OUTER JOIN "reviews" ON "reviews"."id" = "customers"."review_id"
```
One way to avoid this is to `unscope` the includes:
```ruby
assoc.unscope(:includes).pluck(:id)
```irb
irb> assoc.unscope(:includes).pluck(:id)
```
### `ids`
`ids` can be used to pluck all the IDs for the relation using the table's primary key.
```ruby
Customer.ids
# SELECT id FROM customers
```irb
irb> Customer.ids
SELECT id FROM customers
```
```ruby
class Customer < ApplicationRecord
self.primary_key = "customer_id"
end
```
Customer.ids
# SELECT customer_id FROM customers
```irb
irb> Customer.ids
SELECT customer_id FROM customers
```
Existence of Objects
@ -2025,22 +2016,22 @@ This section uses `count` as an example method in this preamble, but the options
All calculation methods work directly on a model:
```ruby
Customer.count
# SELECT COUNT(*) FROM customers
```irb
irb> Customer.count
SELECT COUNT(*) FROM customers
```
Or on a relation:
```ruby
Customer.where(first_name: 'Ryan').count
# SELECT COUNT(*) FROM customers WHERE (first_name = 'Ryan')
```irb
irb> Customer.where(first_name: 'Ryan').count
SELECT COUNT(*) FROM customers WHERE (first_name = 'Ryan')
```
You can also use various finder methods on a relation for performing complex calculations:
```ruby
Customer.includes("orders").where(first_name: 'Ryan', orders: { status: 'shipped' }).count
```irb
irb> Customer.includes("orders").where(first_name: 'Ryan', orders: { status: 'shipped' }).count
```
Which will execute:

@ -23,9 +23,13 @@ Here's an example of a very simple validation:
class Person < ApplicationRecord
validates :name, presence: true
end
```
Person.create(name: "John Doe").valid? # => true
Person.create(name: nil).valid? # => false
```irb
irb> Person.create(name: "John Doe").valid?
=> true
irb> Person.create(name: nil).valid?
=> false
```
As you can see, our validation lets us know that our `Person` is not valid
@ -85,17 +89,17 @@ end
We can see how it works by looking at some `bin/rails console` output:
```ruby
>> p = Person.new(name: "John Doe")
```irb
irb> p = Person.new(name: "John Doe")
=> #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil>
>> p.new_record?
irb> p.new_record?
=> true
>> p.save
irb> p.save
=> true
>> p.new_record?
irb> p.new_record?
=> false
```
@ -168,9 +172,13 @@ As you saw above:
class Person < ApplicationRecord
validates :name, presence: true
end
```
Person.create(name: "John Doe").valid? # => true
Person.create(name: nil).valid? # => false
```irb
irb> Person.create(name: "John Doe").valid?
=> true
irb> Person.create(name: nil).valid?
=> false
```
After Active Record has performed validations, any errors found can be accessed
@ -182,34 +190,36 @@ Note that an object instantiated with `new` will not report errors
even if it's technically invalid, because validations are automatically run
only when the object is saved, such as with the `create` or `save` methods.
```ruby
```
class Person < ApplicationRecord
validates :name, presence: true
end
```
>> p = Person.new
# => #<Person id: nil, name: nil>
>> p.errors.size
# => 0
```irb
irb> p = Person.new
=> #<Person id: nil, name: nil>
irb> p.errors.size
=> 0
>> p.valid?
# => false
>> p.errors.objects.first.full_message
# => "Name can't be blank"
irb> p.valid?
=> false
irb> p.errors.objects.first.full_message
=> "Name can't be blank"
>> p = Person.create
# => #<Person id: nil, name: nil>
>> p.errors.objects.first.full_message
# => "Name can't be blank"
irb> p = Person.create
=> #<Person id: nil, name: nil>
irb> p.errors.objects.first.full_message
=> "Name can't be blank"
>> p.save
# => false
irb> p.save
=> false
>> p.save!
# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
irb> p.save!
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
>> Person.create!
# => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
irb> Person.create!
ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
```
`invalid?` is the inverse of `valid?`. It triggers your validations,
@ -232,9 +242,13 @@ whether there are errors found on an individual attribute of the object.
class Person < ApplicationRecord
validates :name, presence: true
end
```
>> Person.new.errors[:name].any? # => false
>> Person.create.errors[:name].any? # => true
```irb
irb> Person.new.errors[:name].any?
=> false
irb> Person.create.errors[:name].any?
=> true
```
We'll cover validation errors in greater depth in the [Working with Validation
@ -774,9 +788,13 @@ empty string for example.
class Topic < ApplicationRecord
validates :title, length: { is: 5 }, allow_blank: true
end
```
Topic.create(title: "").valid? # => true
Topic.create(title: nil).valid? # => true
```irb
irb> Topic.create(title: "").valid?
=> true
irb> Topic.create(title: nil).valid?
=> true
```
### `:message`
@ -847,12 +865,16 @@ class Person < ApplicationRecord
validates :email, uniqueness: true, on: :account_setup
validates :age, numericality: true, on: :account_setup
end
```
person = Person.new(age: 'thirty-three')
person.valid? # => true
person.valid?(:account_setup) # => false
person.errors.messages
# => {:email=>["has already been taken"], :age=>["is not a number"]}
```irb
irb> person = Person.new(age: 'thirty-three')
irb> person.valid?
=> true
irb> person.valid?(:account_setup)
=> false
irb> person.errors.messages
=> {:email=>["has already been taken"], :age=>["is not a number"]}
```
`person.valid?(:account_setup)` executes both the validations without saving
@ -868,11 +890,14 @@ class Person < ApplicationRecord
validates :age, numericality: true, on: :account_setup
validates :name, presence: true
end
```
person = Person.new
person.valid?(:account_setup) # => false
person.errors.messages
# => {:email=>["has already been taken"], :age=>["is not a number"], :name=>["can't be blank"]}
```irb
irb> person = Person.new
irb> person.valid?(:account_setup)
=> false
irb> person.errors.messages
=> {:email=>["has already been taken"], :age=>["is not a number"], :name=>["can't be blank"]}
```
Strict Validations
@ -885,8 +910,11 @@ You can also specify validations to be strict and raise
class Person < ApplicationRecord
validates :name, presence: { strict: true }
end
```
Person.new.valid? # => ActiveModel::StrictValidationFailed: Name can't be blank
```irb
irb> Person.new.valid?
ActiveModel::StrictValidationFailed: Name can't be blank
```
There is also the ability to pass a custom exception to the `:strict` option.
@ -895,8 +923,11 @@ There is also the ability to pass a custom exception to the `:strict` option.
class Person < ApplicationRecord
validates :token, presence: true, uniqueness: true, strict: TokenGenerationException
end
```
Person.new.valid? # => TokenGenerationException: Token can't be blank
```irb
irb> Person.new.valid?
TokenGenerationException: Token can't be blank
```
Conditional Validation
@ -1099,15 +1130,20 @@ each error is represented by an `ActiveModel::Error` object.
class Person < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
end
```
person = Person.new
person.valid? # => false
person.errors.full_messages
# => ["Name can't be blank", "Name is too short (minimum is 3 characters)"]
```irb
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.full_messages
=> ["Name can't be blank", "Name is too short (minimum is 3 characters)"]
person = Person.new(name: "John Doe")
person.valid? # => true
person.errors.full_messages # => []
irb> person = Person.new(name: "John Doe")
irb> person.valid?
=> true
irb> person.errors.full_messages
=> []
```
### `errors[]`
@ -1118,19 +1154,26 @@ person.errors.full_messages # => []
class Person < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
end
```
person = Person.new(name: "John Doe")
person.valid? # => true
person.errors[:name] # => []
```irb>
irb> person = Person.new(name: "John Doe")
irb> person.valid?
=> true
irb> person.errors[:name]
=> []
person = Person.new(name: "JD")
person.valid? # => false
person.errors[:name] # => ["is too short (minimum is 3 characters)"]
irb> person = Person.new(name: "JD")
irb> person.valid?
=> false
irb> person.errors[:name]
=> ["is too short (minimum is 3 characters)"]
person = Person.new
person.valid? # => false
person.errors[:name]
# => ["can't be blank", "is too short (minimum is 3 characters)"]
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors[:name]
=> ["can't be blank", "is too short (minimum is 3 characters)"]
```
### `errors.where` and error object
@ -1143,27 +1186,41 @@ Sometimes we may need more information about each error beside its message. Each
class Person < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
end
```
person = Person.new
person.valid? # => false
```irb
irb> person = Person.new
irb> person.valid?
=> false
>> person.errors.where(:name) # errors linked to :name attribute
>> person.errors.where(:name, :too_short) # further filtered to only :too_short type error
irb> person.errors.where(:name)
=> [ ... ] # all errors for :name attribute
irb> person.errors.where(:name, :too_short)
=> [ ... ] # :too_short errors for :name attribute
```
You can read various information from these error objects:
```ruby
>> error = person.errors.where(:name).last
>> error.attribute # => :name
>> error.type # => :too_short
>> error.options[:count] # => 3
```irb
irb> error = person.errors.where(:name).last
irb> error.attribute
=> :name
irb> error.type
=> :too_short
irb> error.options[:count]
=> 3
```
You can also generate the error message:
>> error.message # => "is too short (minimum is 3 characters)"
>> error.full_message # => "Name is too short (minimum is 3 characters)"
```irb
irb> error.message
=> "is too short (minimum is 3 characters)"
irb> error.full_message
=> "Name is too short (minimum is 3 characters)"
```
The `full_message` method generates a more user-friendly message, with the capitalized attribute name prepended.
@ -1177,10 +1234,14 @@ class Person < ApplicationRecord
errors.add :name, :too_plain, message: "is not cool enough"
end
end
```
person = Person.create
person.errors.where(:name).first.type # => :too_plain
person.errors.where(:name).first.full_message # => "Name is not cool enough"
```irb
irb> person = Person.create
irb> person.errors.where(:name).first.type
=> :too_plain
irb> person.errors.where(:name).first.full_message
=> "Name is not cool enough"
```
### `errors[:base]`
@ -1193,9 +1254,12 @@ class Person < ApplicationRecord
errors.add :base, :invalid, message: "This person is invalid because ..."
end
end
```
person = Person.create
person.errors.where(:base).first.full_message # => "This person is invalid because ..."
```irb
irb> person = Person.create
irb> person.errors.where(:base).first.full_message
=> "This person is invalid because ..."
```
### `errors.clear`
@ -1206,17 +1270,24 @@ The `clear` method is used when you intentionally want to clear the `errors` col
class Person < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
end
```
person = Person.new
person.valid? # => false
person.errors.empty? # => false
```irb
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.empty?
=> false
person.errors.clear
person.errors.empty? # => true
irb> person.errors.clear
irb> person.errors.empty?
=> true
person.save # => false
irb> person.save
=> false
person.errors.empty? # => false
irb> person.errors.empty?
=> false
```
### `errors.size`
@ -1227,14 +1298,20 @@ The `size` method returns the total number of errors for the object.
class Person < ApplicationRecord
validates :name, presence: true, length: { minimum: 3 }
end
```
person = Person.new
person.valid? # => false
person.errors.size # => 2
```irb
irb> person = Person.new
irb> person.valid?
=> false
irb> person.errors.size
=> 2
person = Person.new(name: "Andrea", email: "andrea@example.com")
person.valid? # => true
person.errors.size # => 0
irb> person = Person.new(name: "Andrea", email: "andrea@example.com")
irb> person.valid?
=> true
irb> person.errors.size
=> 0
```
Displaying Validation Errors in Views

@ -414,9 +414,8 @@ more information regarding this).
Other plugins may add additional modules. You can get a list of all modules
included into `ActionController::API` in the rails console:
```bash
$ bin/rails c
>> ActionController::API.ancestors - ActionController::Metal.ancestors
```irb
irb> ActionController::API.ancestors - ActionController::Metal.ancestors
=> [ActionController::API,
ActiveRecord::Railties::ControllerRuntime,
ActionDispatch::Routing::RouteSet::MountedHelpers,

@ -749,12 +749,14 @@ end
Active Record will attempt to automatically identify that these two models share a bi-directional association based on the association name. In this way, Active Record will only load one copy of the `Author` object, making your application more efficient and preventing inconsistent data:
```ruby
a = Author.first
b = a.books.first
a.first_name == b.author.first_name # => true
a.first_name = 'David'
a.first_name == b.author.first_name # => true
```irb
irb> a = Author.first
irb> b = a.books.first
irb> a.first_name == b.author.first_name
=> true
irb> a.first_name = 'David'
irb> a.first_name == b.author.first_name
=> true
```
Active Record supports automatic identification for most associations with standard names. However, Active Record will not automatically identify bi-directional associations that contain a scope or any of the following options:
@ -776,12 +778,14 @@ end
Active Record will no longer automatically recognize the bi-directional association:
```ruby
a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => false
```irb
irb> a = Author.first
irb> b = a.books.first
irb> a.first_name == b.writer.first_name
=> true
irb> a.first_name = 'David'
irb> a.first_name == b.writer.first_name
=> false
```
Active Record provides the `:inverse_of` option so you can explicitly declare bi-directional associations:
@ -798,12 +802,14 @@ end
By including the `:inverse_of` option in the `has_many` association declaration, Active Record will now recognize the bi-directional association:
```ruby
a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => true
```irb
irb> a = Author.first
irb> b = a.books.first
irb> a.first_name == b.writer.first_name
=> true
irb> a.first_name = 'David'
irb> a.first_name == b.writer.first_name
=> true
```
Detailed Association Reference
@ -1952,13 +1958,17 @@ class Person < ApplicationRecord
has_many :readings
has_many :articles, through: :readings
end
```
person = Person.create(name: 'John')
article = Article.create(name: 'a1')
person.articles << article
person.articles << article
person.articles.inspect # => [#<Article id: 5, name: "a1">, #<Article id: 5, name: "a1">]
Reading.all.inspect # => [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>]
```irb
irb> person = Person.create(name: 'John')
irb> article = Article.create(name: 'a1')
irb> person.articles << article
irb> person.articles << article
irb> person.articles.to_a
=> [#<Article id: 5, name: "a1">, #<Article id: 5, name: "a1">]
irb> Reading.all.to_a
=> [#<Reading id: 12, person_id: 5, article_id: 5>, #<Reading id: 13, person_id: 5, article_id: 5>]
```
In the above case there are two readings and `person.articles` brings out both of
@ -1971,13 +1981,17 @@ class Person
has_many :readings
has_many :articles, -> { distinct }, through: :readings
end
```
person = Person.create(name: 'Honda')
article = Article.create(name: 'a1')
person.articles << article
person.articles << article
person.articles.inspect # => [#<Article id: 7, name: "a1">]
Reading.all.inspect # => [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>]
```irb
irb> person = Person.create(name: 'Honda')
irb> article = Article.create(name: 'a1')
irb> person.articles << article
irb> person.articles << article
irb> person.articles.to_a
=> [#<Article id: 7, name: "a1">]
irb> Reading.all.to_a
=> [#<Reading id: 16, person_id: 7, article_id: 7>, #<Reading id: 17, person_id: 7, article_id: 7>]
```
In the above case there are still two readings. However `person.articles` shows
@ -1997,11 +2011,12 @@ add_index :readings, [:person_id, :article_id], unique: true
Once you have this unique index, attempting to add the article to a person twice
will raise an `ActiveRecord::RecordNotUnique` error:
```ruby
person = Person.create(name: 'Honda')
article = Article.create(name: 'a1')
person.articles << article
person.articles << article # => ActiveRecord::RecordNotUnique
```irb
irb> person = Person.create(name: 'Honda')
irb> article = Article.create(name: 'a1')
irb> person.articles << article
irb> person.articles << article
ActiveRecord::RecordNotUnique
```
Note that checking for uniqueness using something like `include?` is subject

@ -133,9 +133,7 @@ In a Rails console there is no file watcher active regardless of the value of `c
However, you can force a reload in the console by executing `reload!`:
```bash
$ bin/rails c
Loading development environment (Rails 6.0.0)
```irb
irb(main):001:0> User.object_id
=> 70136277390120
irb(main):002:0> reload!
@ -172,12 +170,12 @@ Let's see other situations that involve stale class or module objects.
Check this Rails console session:
```ruby
> joe = User.new
> reload!
> alice = User.new
> joe.class == alice.class
false
```irb
irb> joe = User.new
irb> reload!
irb> alice = User.new
irb> joe.class == alice.class
=> false
```
`joe` is an instance of the original `User` class. When there is a reload, the `User` constant evaluates to a different, reloaded class. `alice` is an instance of the current one, but `joe` is not, his class is stale. You may define `joe` again, start an IRB subsession, or just launch a new console instead of calling `reload!`.

@ -822,8 +822,8 @@ constants.
For example, if you're in a console session and edit some file behind the
scenes, the code can be reloaded with the `reload!` command:
```
> reload!
```irb
irb> reload!
```
When the application runs, code is reloaded when something relevant to this
@ -1248,10 +1248,10 @@ warning: toplevel constant Image referenced by Hotel::Image
This surprising constant resolution can be observed with any qualifying class:
```
2.1.5 :001 > String::Array
```irb
irb(main):001:0> String::Array
(irb):1: warning: toplevel constant Array referenced by String::Array
=> Array
=> Array
```
WARNING. To find this gotcha the qualifying namespace has to be a class,

@ -368,22 +368,22 @@ Inside the `bin/rails console` you have access to the `app` and `helper` instanc
With the `app` method you can access named route helpers, as well as do requests.
```ruby
>> app.root_path
```irb
irb> app.root_path
=> "/"
>> app.get _
irb> app.get _
Started GET "/" for 127.0.0.1 at 2014-06-19 10:41:57 -0300
...
```
With the `helper` method it is possible to access Rails and your application's helpers.
```ruby
>> helper.time_ago_in_words 30.days.ago
```irb
irb> helper.time_ago_in_words 30.days.ago
=> "about 1 month"
>> helper.my_custom_helper
irb> helper.my_custom_helper
=> "my custom helper"
```

@ -1077,8 +1077,7 @@ development:
This will connect to the database named `blog_development` using the `postgresql` adapter. This same information can be stored in a URL and provided via an environment variable like this:
```ruby
> puts ENV['DATABASE_URL']
postgresql://localhost/blog_development?pool=5
ENV['DATABASE_URL'] # => "postgresql://localhost/blog_development?pool=5"
```
The `config/database.yml` file contains sections for three different environments in which Rails can run by default:

@ -439,8 +439,8 @@ If you'd rather play around in the console, `bin/rails console` will also work j
like a Rails application. Remember: the `Article` model is namespaced, so to
reference it you must call it as `Blorgh::Article`.
```ruby
>> Blorgh::Article.find(1)
```irb
irb> Blorgh::Article.find(1)
=> #<Blorgh::Article id: 1 ...>
```

@ -137,8 +137,8 @@ To test that your method does what it says it does, run the unit tests with `bin
To see this in action, change to the `test/dummy` directory, start `bin/rails console`, and commence squawking:
```ruby
>> "Hello World".to_squawk
```irb
irb> "Hello World".to_squawk
=> "squawk! Hello World"
```

@ -1357,9 +1357,13 @@ class FooBar
{ foo: 'bar' }
end
end
```
>> FooBar.new.to_json # => "{\"foo\":\"bar\"}"
>> JSON.generate(FooBar.new, quirks_mode: true) # => "\"#<FooBar:0x007fa80a481610>\""
```irb
irb> FooBar.new.to_json
=> "{\"foo\":\"bar\"}"
irb> JSON.generate(FooBar.new, quirks_mode: true)
=> "\"#<FooBar:0x007fa80a481610>\""
```
#### New JSON encoder