471

When I load script/console, sometimes I want to play with the output of a controller or a view helper method.

Are there ways to:

  • simulate a request?
  • call methods from a controller instance on said request?
  • test helper methods, either via said controller instance or another way?
iconoclast
  • 21,213
  • 15
  • 102
  • 138
kch
  • 77,385
  • 46
  • 136
  • 148

14 Answers14

497

To call helpers, use the helper object:

$ ./script/console
>> helper.number_to_currency('123.45')
=> "R$ 123,45"

If you want to use a helper that's not included by default (say, because you removed helper :all from ApplicationController), just include the helper.

>> include BogusHelper
>> helper.bogus
=> "bogus output"

As for dealing with controllers, I quote Nick's answer:

> app.get '/posts/1'
> response = app.response
# you now have a rails response object much like the integration tests

> response.body            # get you the HTML
> response.cookies         # hash of the cookies

# etc, etc
Community
  • 1
  • 1
kch
  • 77,385
  • 46
  • 136
  • 148
  • 4
    I observe that I can't execute more than one `app.get` (a thread error ensues). Is there a way I can flush the system and execute more gets? – JellicleCat May 22 '12 at 17:53
  • 2
    Note in Rails 3.2 this does not work. I needed to call `url_for` from the console. To do this I did `app.url_for(...)` – Raphael Jul 05 '13 at 16:18
  • 1
    For `NoMethodError: undefined method \`protect_against_forgery?' for nil:NilClass` define a function called `protect_against_forgery?` within the console that returns `false` – Sida Zhou Sep 15 '15 at 22:21
  • how do I set the currently logged in user? –  May 17 '16 at 19:28
  • 2
    @RudolfOlah It seems that if you are using device (or warden) you can do it with `ActionDispatch::Integration::Session.include(Warden::Test::Helpers); Warden.test_mode! ; app.login_as(User.find(1), scope: :user)`. – eloyesp Apr 05 '19 at 18:24
157

An easy way to call a controller action from a script/console and view/manipulate the response object is:

> app.get '/posts/1'
> response = app.response
# You now have a Ruby on Rails response object much like the integration tests

> response.body            # Get you the HTML
> response.cookies         # Hash of the cookies

# etc., etc.

The app object is an instance of ActionController::Integration::Session

This works for me using Ruby on Rails 2.1 and 2.3, and I did not try earlier versions.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nick B
  • 7,639
  • 2
  • 32
  • 28
  • 2
    A link to official documentation on app object would be good. – RajaRaviVarma Aug 29 '12 at 11:52
  • It is an instance of the ActionController::Integration::Session class. I have updated the answer to include that. – Nick B Aug 29 '12 at 18:02
  • 5
    How can I authenticate the console, so I can check controllers that require authentication? – Mild Fuzz Mar 07 '13 at 10:58
  • 8
    You should be able to post to your log in page, something like: app.post '/session/new', { :username => "foo", :password => "pass" }. And then continue to use the same "app" variable to get pages after that. – Nick B Mar 07 '13 at 18:15
  • That link is broken (as it's Rails 2.x). `app` is now an `ActionDispatch::Integration::Session `: http://api.rubyonrails.org/classes/ActionDispatch/Integration/Session.html. The `get`, `post`, `patch` methods are defined in http://api.rubyonrails.org/classes/ActionDispatch/Integration/RequestHelpers.html – jwadsack Oct 01 '15 at 17:02
  • Been working with Rails for two years now, first time I heard of this awesome way to hit controllers! – Epigene Mar 23 '16 at 13:47
117

If you need to test from the console (tested on Ruby on Rails 3.1 and 4.1):

Call Controller Actions:

app.get '/'
   app.response
   app.response.headers  # => { "Content-Type"=>"text/html", ... }
   app.response.body     # => "<!DOCTYPE html>\n<html>\n\n<head>\n..."

ApplicationController methods:

foo = ActionController::Base::ApplicationController.new
foo.public_methods(true||false).sort
foo.some_method

Route Helpers:

app.myresource_path     # => "/myresource"
app.myresource_url      # => "http://www.example.com/myresource"

View Helpers:

foo = ActionView::Base.new

foo.javascript_include_tag 'myscript' #=> "<script src=\"/javascripts/myscript.js\"></script>"

helper.link_to "foo", "bar" #=> "<a href=\"bar\">foo</a>"

ActionController::Base.helpers.image_tag('logo.png')  #=> "<img alt=\"Logo\" src=\"/images/logo.png\" />"

Render:

views = Rails::Application::Configuration.new(Rails.root).paths["app/views"]
views_helper = ActionView::Base.new views
views_helper.render 'myview/mytemplate'
views_helper.render file: 'myview/_mypartial', locals: {my_var: "display:block;"}
views_helper.assets_prefix  #=> '/assets'

ActiveSupport methods:

require 'active_support/all'
1.week.ago
=> 2013-08-31 10:07:26 -0300
a = {'a'=>123}
a.symbolize_keys
=> {:a=>123}

Lib modules:

> require 'my_utils'
 => true
> include MyUtils
 => Object
> MyUtils.say "hi"
evaluate: hi
 => true
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fernando Fabreti
  • 4,277
  • 3
  • 32
  • 33
  • 1
    This helps when you are writing independent ruby scripts that will be run using rails runner and they need to call methods in application controller. Thanks – CodeExpress Mar 15 '15 at 14:30
  • @CodeExpress That should never happen. Instead, put the methods in a service object, and call the service from both ApplicationController and your script. – Marnen Laibow-Koser May 01 '19 at 12:16
79

Here's one way to do this through the console:

>> foo = ActionView::Base.new
=> #<ActionView::Base:0x2aaab0ac2af8 @assigns_added=nil, @assigns={}, @helpers=#<ActionView::Base::ProxyModule:0x2aaab0ac2a58>, @controller=nil, @view_paths=[]>

>> foo.extend YourHelperModule
=> #<ActionView::Base:0x2aaab0ac2af8 @assigns_added=nil, @assigns={}, @helpers=#<ActionView::Base::ProxyModule:0x2aaab0ac2a58>, @controller=nil, @view_paths=[]>

>> foo.your_helper_method(args)
=> "<html>created by your helper</html>"

Creating a new instance of ActionView::Base gives you access to the normal view methods that your helper likely uses. Then extending YourHelperModule mixes its methods into your object letting you view their return values.

Gordon Wilson
  • 26,244
  • 11
  • 57
  • 60
18

If the method is the POST method then:

app.post 'controller/action?parameter1=value1&parameter2=value2'

(Here parameters will be as per your applicability.)

Else if it is the GET method then:

app.get 'controller/action'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Swapnil Chincholkar
  • 2,869
  • 3
  • 22
  • 22
16

Here is how to make an authenticated POST request, using Refinery as an example:

# Start Rails console
rails console
# Get the login form
app.get '/community_members/sign_in'
# View the session
app.session.to_hash
# Copy the CSRF token "_csrf_token" and place it in the login request.
# Log in from the console to create a session
app.post '/community_members/login', {"authenticity_token"=>"gT7G17RNFaWUDLC6PJGapwHk/OEyYfI1V8yrlg0lHpM=",  "refinery_user[login]"=>'chloe', 'refinery_user[password]'=>'test'}
# View the session to verify CSRF token is the same
app.session.to_hash
# Copy the CSRF token "_csrf_token" and place it in the request. It's best to edit this in Notepad++
app.post '/refinery/blog/posts', {"authenticity_token"=>"gT7G17RNFaWUDLC6PJGapwHk/OEyYfI1V8yrlg0lHpM=", "switch_locale"=>"en", "post"=>{"title"=>"Test", "homepage"=>"0", "featured"=>"0", "magazine"=>"0", "refinery_category_ids"=>["1282"], "body"=>"Tests do a body good.", "custom_teaser"=>"", "draft"=>"0", "tag_list"=>"", "published_at(1i)"=>"2014", "published_at(2i)"=>"5", "published_at(3i)"=>"27", "published_at(4i)"=>"21", "published_at(5i)"=>"20", "custom_url"=>"", "source_url_title"=>"", "source_url"=>"", "user_id"=>"56", "browser_title"=>"", "meta_description"=>""}, "continue_editing"=>"false", "locale"=>:en}

You might find these useful too if you get an error:

app.cookies.to_hash
app.flash.to_hash
app.response # long, raw, HTML
Chloe
  • 25,162
  • 40
  • 190
  • 357
15

You can access your methods in the Ruby on Rails console like the following:

controller.method_name
helper.method_name
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jyothu
  • 3,104
  • 17
  • 26
15

Another way to do this is to use the Ruby on Rails debugger. There's a Ruby on Rails guide about debugging at http://guides.rubyonrails.org/debugging_rails_applications.html

Basically, start the server with the -u option:

./script/server -u

And then insert a breakpoint into your script where you would like to have access to the controllers, helpers, etc.

class EventsController < ApplicationController
  def index
    debugger
  end
end

And when you make a request and hit that part in the code, the server console will return a prompt where you can then make requests, view objects, etc. from a command prompt. When finished, just type 'cont' to continue execution. There are also options for extended debugging, but this should at least get you started.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dan McNevin
  • 22,278
  • 5
  • 35
  • 28
9

In Ruby on Rails 3, try this:

session = ActionDispatch::Integration::Session.new(Rails.application)
session.get(url)
body = session.response.body

The body will contain the HTML of the URL.

How to route and render (dispatch) from a model in Ruby on Rails 3

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tbabs
  • 445
  • 2
  • 5
  • 8
8

The earlier answers are calling helpers, but the following will help for calling controller methods. I have used this on Ruby on Rails 2.3.2.

First add the following code to your .irbrc file (which can be in your home directory)

class Object
   def request(options = {})
     url=app.url_for(options)
     app.get(url)
     puts app.html_document.root.to_s
  end
end

Then in the Ruby on Rails console you can type something like...

request(:controller => :show, :action => :show_frontpage)

...and the HTML will be dumped to the console.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
David Knight
  • 81
  • 1
  • 2
5

For controllers, you can instantiate a controller object in the Ruby on Rails console.

For example,

class CustomPagesController < ApplicationController

  def index
    @customs = CustomPage.all
  end

  def get_number
    puts "Got the Number"
  end

  protected

  def get_private_number
    puts 'Got private Number'
  end

end

custom = CustomPagesController.new
2.1.5 :011 > custom = CustomPagesController.new
 => #<CustomPagesController:0xb594f77c @_action_has_layout=true, @_routes=nil, @_headers={"Content-Type"=>"text/html"}, @_status=200, @_request=nil, @_response=nil>
2.1.5 :014 > custom.get_number
Got the Number
 => nil

# For calling private or protected methods,
2.1.5 :048 > custom.send(:get_private_number)
Got private Number
 => nil
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dyaniyal Wilson
  • 1,012
  • 10
  • 14
  • 1
    It works! But how can I update action variables. Ex: `def show response = @user.contributions end ` How do I override the `@user` variable? – Fábio Araújo Mar 21 '19 at 15:05
4

Inside any controller action or view, you can invoke the console by calling the console method.

For example, in a controller:

class PostsController < ApplicationController
  def new
    console
    @post = Post.new
  end
end

Or in a view:

<% console %>

<h2>New Post</h2>

This will render a console inside your view. You don't need to care about the location of the console call; it won't be rendered on the spot of its invocation but next to your HTML content.

See: http://guides.rubyonrails.org/debugging_rails_applications.html

Gayan Weerakutti
  • 11,904
  • 2
  • 71
  • 68
3

One possible approach for Helper method testing in the Ruby on Rails console is:

Struct.new(:t).extend(YourHelper).your_method(*arg)

And for reload do:

reload!; Struct.new(:t).extend(YourHelper).your_method(*arg)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Dino Reic
  • 3,586
  • 3
  • 22
  • 11
2

If you have added your own helper and you want its methods to be available in console, do:

  1. In the console execute include YourHelperName
  2. Your helper methods are now available in console, and use them calling method_name(args) in the console.

Example: say you have MyHelper (with a method my_method) in 'app/helpers/my_helper.rb`, then in the console do:

  1. include MyHelper
  2. my_helper.my_method
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131