From 3c9d7a268f325f5cc6ab1ab49aed6f52e4c4f631 Mon Sep 17 00:00:00 2001 From: Jonathan Hefner Date: Sat, 31 Oct 2020 16:44:05 -0500 Subject: [PATCH] Use irb code fences where applicable [ci-skip] Using `irb` code fences and the appropriate prompt syntax results in better syntax highlighting. --- guides/source/2_3_release_notes.md | 3 +- guides/source/5_1_release_notes.md | 3 +- guides/source/active_model_basics.md | 218 +++++++---- guides/source/active_record_basics.md | 10 +- guides/source/active_record_callbacks.md | 53 +-- guides/source/active_record_postgresql.md | 185 +++++---- guides/source/active_record_querying.md | 359 +++++++++--------- guides/source/active_record_validations.md | 255 ++++++++----- guides/source/api_app.md | 5 +- guides/source/association_basics.md | 85 +++-- .../autoloading_and_reloading_constants.md | 16 +- ...ng_and_reloading_constants_classic_mode.md | 10 +- guides/source/command_line.md | 12 +- guides/source/configuring.md | 3 +- guides/source/engines.md | 4 +- guides/source/plugins.md | 4 +- guides/source/upgrading_ruby_on_rails.md | 8 +- 17 files changed, 707 insertions(+), 526 deletions(-) diff --git a/guides/source/2_3_release_notes.md b/guides/source/2_3_release_notes.md index 11c929c429..0bf82db53c 100644 --- a/guides/source/2_3_release_notes.md +++ b/guides/source/2_3_release_notes.md @@ -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) diff --git a/guides/source/5_1_release_notes.md b/guides/source/5_1_release_notes.md index 6a63e8bd52..81298efd53 100644 --- a/guides/source/5_1_release_notes.md +++ b/guides/source/5_1_release_notes.md @@ -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` diff --git a/guides/source/active_model_basics.md b/guides/source/active_model_basics.md index 619126c111..f306867570 100644 --- a/guides/source/active_model_basics.md +++ b/guides/source/active_model_basics.md @@ -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.name # => "Bob" +```irb +irb> json = { name: 'Bob' }.to_json +irb> person = Person.new +irb> person.from_json(json) +=> # +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 +irb> person.authenticate('notright') +=> false +irb> person.authenticate_password('aditya') +=> # # == 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 +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" ``` diff --git a/guides/source/active_record_basics.md b/guides/source/active_record_basics.md index e5c27ea90d..49e67bd80c 100644 --- a/guides/source/active_record_basics.md +++ b/guides/source/active_record_basics.md @@ -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 diff --git a/guides/source/active_record_callbacks.md b/guides/source/active_record_callbacks.md index 3cc2c5dc1a..4adc24c17c 100644 --- a/guides/source/active_record_callbacks.md +++ b/guides/source/active_record_callbacks.md @@ -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.first +irb> User.first You have found an object! You have initialized an object! => # @@ -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') => # ->> 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 => # -# 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.articles.create! +irb> user.articles.create! => #
->> user.destroy +irb> user.destroy Article destroyed => # ``` @@ -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 ``` diff --git a/guides/source/active_record_postgresql.md b/guides/source/active_record_postgresql.md index 6df8d311ad..ddec796e3d 100644 --- a/guides/source/active_record_postgresql.md +++ b/guides/source/active_record_postgresql.md @@ -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") -# => #"yellow", "resolution"=>"1280x1024"}>]> +irb> Profile.where("settings->'color' = ?", "yellow") +=> #"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 -# => # +irb> macbook.ip +=> # -macbook.network -# => # +irb> macbook.network +=> # -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 diff --git a/guides/source/active_record_querying.md b/guides/source/active_record_querying.md index 8aa0e5b602..49f5d0068b 100644 --- a/guides/source/active_record_querying.md +++ b/guides/source/active_record_querying.md @@ -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) -# => # +irb> customer = Customer.find(10) +=> # ``` 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) -# => [#, #] +irb> customers = Customer.find([1, 10]) # OR Customer.find(1, 10) +=> [#, #] ``` 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 -# => # +```irb +irb> customer = Customer.take +=> # ``` 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) -# => [ -# #, -# # -# ] +```irb +irb> customers = Customer.take(2) +=> [#, #] ``` 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 -# => # +```irb +irb> customer = Customer.first +=> # ``` 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) -# => [ -# #, -# #, -# # -# ] +```irb +irb> customers = Customer.first(3) +=> [#, #, #] ``` 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 -# => # +```irb +irb> customer = Customer.order(:first_name).first +=> # ``` 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 -# => # +```irb +irb> customer = Customer.last +=> # ``` 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) -# => [ -# #, -# #, -# # -# ] +```irb +irb> customers = Customer.last(3) +=> [#, #, #] ``` 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 -# => # +```irb +irb> customer = Customer.order(:first_name).last +=> # ``` 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' -# => # +```irb +irb> Customer.find_by 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 +=> # # 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 +=> # # 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.unscoped.new # => # +```irb +irb> Book.new +=> # +irb> Book.unscoped.new +=> # ``` 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 # => # +```irb +irb> Book.new +=> # ``` ### 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 +=> # # all orders with status == :shipped +irb> Order.not_shipped +=> # # 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') +=> # ``` 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') -# => # +```irb +irb> nina = Customer.find_or_initialize_by(first_name: 'Nina') +=> # -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") -# => [ -# #, -# #, -# ... -# ] +```irb +irb> Customer.find_by_sql("SELECT * FROM customers INNER JOIN orders ON customers.id = orders.customer_id ORDER BY customers.created_at desc") +=> [#, #, ...] ``` `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 # +```irb +irb> Customer.pluck(:first_name).limit(1) +NoMethodError: undefined method `limit' for # -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: diff --git a/guides/source/active_record_validations.md b/guides/source/active_record_validations.md index 54c2093f69..43766b1284 100644 --- a/guides/source/active_record_validations.md +++ b/guides/source/active_record_validations.md @@ -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") => # ->> 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 -# => # ->> p.errors.size -# => 0 +```irb +irb> p = Person.new +=> # +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 -# => # ->> p.errors.objects.first.full_message -# => "Name can't be blank" +irb> p = Person.create +=> # +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 diff --git a/guides/source/api_app.md b/guides/source/api_app.md index 10573b64c2..bcf6ca2fad 100644 --- a/guides/source/api_app.md +++ b/guides/source/api_app.md @@ -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, diff --git a/guides/source/association_basics.md b/guides/source/association_basics.md index 8b50ebc0fd..da5fc8a97a 100644 --- a/guides/source/association_basics.md +++ b/guides/source/association_basics.md @@ -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 # => [#
, #
] -Reading.all.inspect # => [#, #] +```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 +=> [#
, #
] +irb> Reading.all.to_a +=> [#, #] ``` 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 # => [#
] -Reading.all.inspect # => [#, #] +```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 +=> [#
] +irb> Reading.all.to_a +=> [#, #] ``` 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 diff --git a/guides/source/autoloading_and_reloading_constants.md b/guides/source/autoloading_and_reloading_constants.md index 0b327bd2b7..567e7746ef 100644 --- a/guides/source/autoloading_and_reloading_constants.md +++ b/guides/source/autoloading_and_reloading_constants.md @@ -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!`. diff --git a/guides/source/autoloading_and_reloading_constants_classic_mode.md b/guides/source/autoloading_and_reloading_constants_classic_mode.md index 77c32edc13..688a82114a 100644 --- a/guides/source/autoloading_and_reloading_constants_classic_mode.md +++ b/guides/source/autoloading_and_reloading_constants_classic_mode.md @@ -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, diff --git a/guides/source/command_line.md b/guides/source/command_line.md index 3b3e2a2cec..a3942be7fb 100644 --- a/guides/source/command_line.md +++ b/guides/source/command_line.md @@ -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" ``` diff --git a/guides/source/configuring.md b/guides/source/configuring.md index 9852abbac8..62b7f62553 100644 --- a/guides/source/configuring.md +++ b/guides/source/configuring.md @@ -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: diff --git a/guides/source/engines.md b/guides/source/engines.md index d13b247361..37987bc746 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -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) => # ``` diff --git a/guides/source/plugins.md b/guides/source/plugins.md index 1291805552..022d82d2d5 100644 --- a/guides/source/plugins.md +++ b/guides/source/plugins.md @@ -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" ``` diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md index ac30767ed3..03748af39c 100644 --- a/guides/source/upgrading_ruby_on_rails.md +++ b/guides/source/upgrading_ruby_on_rails.md @@ -1357,9 +1357,13 @@ class FooBar { foo: 'bar' } end end +``` ->> FooBar.new.to_json # => "{\"foo\":\"bar\"}" ->> JSON.generate(FooBar.new, quirks_mode: true) # => "\"#\"" +```irb +irb> FooBar.new.to_json +=> "{\"foo\":\"bar\"}" +irb> JSON.generate(FooBar.new, quirks_mode: true) +=> "\"#\"" ``` #### New JSON encoder