Console Tricks in Rails 5

You can print the yaml representation of an object using the y method.

$ rails c
p Loading development environment (Rails 5.0.0.beta3)
p = Product.first
  Product Load (0.3ms)  SELECT  "products".* FROM "products" ORDER BY "products"."id" ASC LIMIT ?  [["LIMIT", 1]]
 => #<Product id: 1, name: "Television", price: #<BigDecimal:7fb81444ba50,'0.99E2',9(18)>, created_at: "2016-03-28 21:58:42", updated_at: "2016-03-28 21:58:42"> 
 > y p
--- !ruby/object:Product
raw_attributes:
  id: 1
  name: Television
  price: 99
  created_at: '2016-03-28 21:58:42.799649'
  updated_at: '2016-03-28 21:58:42.799649'
attributes: !ruby/object:ActiveRecord::AttributeSet
  attributes: !ruby/object:ActiveRecord::LazyAttributeHash
    types:
      id: &2 !ruby/object:ActiveModel::Type::Integer
        precision: 
        scale: 
        limit: 
        range: !ruby/range
          begin: -2147483648
          end: 2147483648
          excl: true
      name: &3 !ruby/object:ActiveModel::Type::String
        precision: 
        scale: 
        limit: 
      price: &4 !ruby/object:ActiveModel::Type::Decimal
        precision: 8
        scale: 2
        limit: 
      created_at: &5 !ruby/marshalable:ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
        :__v2__: []
        []: &1 !ruby/object:ActiveRecord::Type::DateTime
          precision: 
          scale: 
          limit: 
      updated_at: &7 !ruby/marshalable:ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter
        :__v2__: []
        []: *1
    values:
      id: 1
      name: Television
      price: 99
      created_at: '2016-03-28 21:58:42.799649'
      updated_at: '2016-03-28 21:58:42.799649'
    additional_types: {}
    materialized: true
    delegate_hash:
      id: !ruby/object:ActiveRecord::Attribute::FromDatabase
        name: id
        value_before_type_cast: 1
        type: *2
        original_attribute: 
        value: 1
      name: !ruby/object:ActiveRecord::Attribute::FromDatabase
        name: name
        value_before_type_cast: Television
        type: *3
        original_attribute: 
        value: Television
      price: !ruby/object:ActiveRecord::Attribute::FromDatabase
        name: price
        value_before_type_cast: 99
        type: *4
        original_attribute: 
        value: !ruby/object:BigDecimal 18:0.99E2
      created_at: !ruby/object:ActiveRecord::Attribute::FromDatabase
        name: created_at
        value_before_type_cast: '2016-03-28 21:58:42.799649'
        type: *5
        original_attribute: 
        value: !ruby/object:ActiveSupport::TimeWithZone
          utc: &6 2016-03-28 21:58:42.799649000 Z
          zone: &8 !ruby/object:ActiveSupport::TimeZone
            name: Etc/UTC
          time: *6
      updated_at: !ruby/object:ActiveRecord::Attribute::FromDatabase
        name: updated_at
        value_before_type_cast: '2016-03-28 21:58:42.799649'
        type: *7
        original_attribute: 
        value: !ruby/object:ActiveSupport::TimeWithZone
          utc: &9 2016-03-28 21:58:42.799649000 Z
          zone: *8
          time: *9
new_record: false
active_record_yaml_version: 1
 => nil 

You can use pretty print pp to give a better output.

require 'pp'
 => false 
 > pp p
#<Product:0x007f70
 id: 1,
 name: "Television",
 price: #<BigDecimal:7fb50,'0.99E2',9(18)>,
 created_at: Mon, 28 Mar 2016 21:58:42 UTC +00:00,
 updated_at: Mon, 28 Mar 2016 21:58:42 UTC +00:00>
 => #<Product id: 1, name: "Television", price: #<BigDecimal:7fb81450,'0.99E2',9(18)>, created_at: "2016-03-28 21:58:42", updated_at: "2016-03-28 21:58:42"> 

This is much more readable than the yaml method. The pp is already required by Rails 5, that is the reason you see the result false.

You can autocomplete strings by typing the first few characters and hitting the tab a few times.

 > Acti

ActionCable       ActionController  ActionDispatch    ActionMailer      ActionPack        ActionView        ActiveJob         ActiveModel       ActiveRecord      ActiveSupport   

Here we see all classes that begins with Acti. You can also check what methods are available on an object by hitting tabs a few times.

 > 'foo'.to_
'foo'.to_blob             'foo'.to_date             'foo'.to_f                'foo'.to_json_raw         'foo'.to_query            'foo'.to_str              'foo'.to_yaml
'foo'.to_c                'foo'.to_datetime         'foo'.to_i                'foo'.to_json_raw_object  'foo'.to_r                'foo'.to_sym              'foo'.to_yaml_properties

What are the classes that begin with Pro?

 > Pro
Proc     Process  Product  

What are the methods that are available in our product object?

 > p.new_record?
p.new_record?
 > p.new_record?
 => false 

What are the methods that begin with the letter n for the product object?

 > p.n
p.name                        p.name_before_type_cast       p.name_changed?               p.name_was                    p.nested_attributes_options?  p.no_touching?
p.name=                       p.name_came_from_user?        p.name_previous_change        p.name_will_change!           p.new_record?                 
p.name?                       p.name_change                 p.name_previously_changed?    p.nested_attributes_options   p.nil?  

We have access to the app instance in the rails console.

 > app.class
 => ActionDispatch::Integration::Session 

We can send a GET request for the home page.

 > app.get '/'
Started GET "/" for 127.0.0.1 at 2016-03-29 20:56:34 -0700
  ActiveRecord::SchemaMigration Load (0.3ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by ProjectsController#index as HTML
  Project Load (0.4ms)  SELECT "projects".* FROM "projects"
  Task Load (0.3ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 1]]
  Task Load (0.1ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 4]]
  Task Load (0.1ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 6]]
  Rendered projects/index.html.erb within layouts/application (85.1ms)
Completed 200 OK in 450ms (Views: 353.3ms | ActiveRecord: 1.6ms)
 => 200 

We see projects and the associated tasks loaded from the database. The http status code is 200. We can check the flash.

 > app.flash
 => #<ActionDispatch::Flash::FlashHash:0x007f18 @discard=#<Set: {}>, @flashes={}, @now=nil> 

However, in Rails 5, you cannot access the variables that you make available in the controller for the view.

 > app.assigns[:tasks]
NoMethodError: assigns has been extracted to a gem. To continue using it,
        add `gem 'rails-controller-testing'` to your Gemfile.

You can view the cookies.

 > app.cookies
 => #<Rack::Test::CookieJar:0x007fb8 @default_host="www.example.com", @cookies=[#<Rack::Test::Cookie:0x007fb @default_host="www.example.com", @name_value_raw="_blog5_session=UGZoa0hWMVFtallIVm1Fb", @name="_blog5_session", @value="DJIT5aee561c9e4f5c771d7406", @options={"path"=>"/", "HttpOnly"=>nil, "domain"=>"www.example.com"}>]> 

You can access the view helpers by using the helper object.

 > helper.text_field_tag :card
 => "<input type=\"text\" name=\"card\" id=\"card\" />" 
 > helper.pluralize(5, 'item')
 => "5 items" 

We can check the available methods in the app object by hitting tabs a few times.

 > app.methods
 => [:main_app, :_main_app, :_routes, :root_path, :rails_mailers_path, :products_path, :new_product_path, ...] 

What are the available methods in the _routes ?

 > app._routes
 => #<ActionDispatch::Routing::RouteSet:0x007fb8135ce360> 
 > app._routes.methods
 => [:empty?, :inspect, :call, :prepend, :append, :request_class, :set, :formatter=, ...] 
 > app.methods.grep(/_path$/).sort
 => [:complete_task_path, :completed_tasks_path, :edit_polymorphic_path, :edit_product_path, ...] 

The underscore is a special global variable that has the value of the last executed command.

 > _.class
 => Array 

It is an array in this case. Can we inspect it?

 > _
 => Array 
 > y _
--- !ruby/class 'Array'
 => nil 

Here is a better example to illustrate the usefulness of underscore global variable.

 > app._routes.methods
 => [:empty?, :inspect, :call, :prepend, :append, :request_class, :set, :formatter=, ...] 
 > y _
---
- :empty?
- :inspect
- :call
- :prepend
- :append
- :request_class
- :set
...

If you change something in the file, you can reload the changes in the rails console by using the reload! method.

> reload!
Reloading...
 => true 

After requesting the home page, we can check the path like this:

 > app.get '/'
Started GET "/" for 127.0.0.1 at 2016-03-29 11:15:30 -0700
  ActiveRecord::SchemaMigration Load (0.2ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by ProjectsController#index as HTML
  Project Load (0.3ms)  SELECT "projects".* FROM "projects"
  Task Load (0.3ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 1]]
  Task Load (0.1ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 4]]
  Task Load (0.1ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 6]]
  Rendered projects/index.html.erb within layouts/application (51.9ms)
Completed 200 OK in 337ms (Views: 281.0ms | ActiveRecord: 1.7ms)
 => 200 
 > app.path
 => "/" 

We can reset the path and request a different page like this:

 > app.reset!
 => nil 
 > app.get '/projects'
Started GET "/projects" for 127.0.0.1 at 2016-03-29 11:20:23 -0700
Processing by ProjectsController#index as HTML
  Project Load (0.5ms)  SELECT "projects".* FROM "projects"
  Task Load (0.3ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 1]]
  Task Load (0.1ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 4]]
  Task Load (0.1ms)  SELECT "tasks".* FROM "tasks" WHERE "tasks"."project_id" = ?  [["project_id", 6]]
  Rendered projects/index.html.erb within layouts/application (39.6ms)
Completed 200 OK in 120ms (Views: 78.1ms | ActiveRecord: 2.1ms)

You can get into a specific object context by providing irb the class name like this:

 > irb Task
 > self
 => Task(id: integer, name: string, complete: boolean, created_at: datetime, updated_at: datetime, project_id: integer, priority: integer, due_date: datetime) 

Now we are in the Task class context, we can call the methods without the receiver.

 > all
  Task Load (0.2ms)  SELECT "tasks".* FROM "tasks"
 => #<ActiveRecord::Relation [#<Task id: 1, name: "Get rich quick", complete: true, created_at: "2016-03-18 21:37:57", updated_at: "2016-03-24 01:12:25", project_id: 1, priority: 4, due_date: "2016-01-18 21:37:57">, #<Task id: 2, name: "Write a book", complete: true, created_at: ...]> 
 > quit
  => #<IRB::Irb: @context=#<IRB::Context:0x007ff0f08>, @signal_status=:IN_EVAL, @scanner=#<RubyLex:0x007b420>> 

You can get out of the Task class context by calling the exit. We can get into a specific task object like this:

 > irb Task.first
  Task Load (0.3ms)  SELECT  "tasks".* FROM "tasks" ORDER BY "tasks"."id" ASC LIMIT ?  [["LIMIT", 1]]
 > name
 => "Get rich quick" 

Here we are printing the name of the task object. We can get out of the task object by typing quit.

 > quit
 => #<IRB::Irb: @context=#<IRB::Context:0x007ff0008>, @signal_status=:IN_EVAL, @scanner=#<RubyLex:0x007b420>> 

We can switch to the app context and check the host like this:

 > irb app
 > host
 => "www.example.com" 

You can customize your IRB by creating an .irbrc in your home folder. Let's open the Object class and define a method.

class Object
  def foo
    'bar'
  end
end

Now you can access the foo method in the rails console like this:

rails c
Loading development environment (Rails 5.0.0.beta3)
 > foo
 => "bar" 

Summary

In this article, you learned some console tricks.


Related Articles