How can I call controller/view helper methods from the console in Ruby on Rails?
Asked Answered
S

15

473

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?
Stated answered 29/9, 2008 at 22:36 Comment(1)
100 years later, I still google for thisStated
S
499

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
Stated answered 21/7, 2009 at 19:15 Comment(5)
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?Loveliesbleeding
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(...)Waistband
For NoMethodError: undefined method `protect_against_forgery?' for nil:NilClass define a function called protect_against_forgery? within the console that returns falseArria
how do I set the currently logged in user?Jaxartes
@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).Gormand
H
158

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.

Holloway answered 17/9, 2009 at 1:40 Comment(6)
A link to official documentation on app object would be good.Villagomez
It is an instance of the ActionController::Integration::Session class. I have updated the answer to include that.Holloway
How can I authenticate the console, so I can check controllers that require authentication?Tope
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.Holloway
That link is broken (as it's Rails 2.x). app is now an ActionDispatch::Integration::Session : api.rubyonrails.org/classes/ActionDispatch/Integration/…. The get, post, patch methods are defined in api.rubyonrails.org/classes/ActionDispatch/Integration/…Misspend
Been working with Rails for two years now, first time I heard of this awesome way to hit controllers!Banana
A
119

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
Agateware answered 6/2, 2012 at 12:7 Comment(2)
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. ThanksMurguia
@Murguia That should never happen. Instead, put the methods in a service object, and call the service from both ApplicationController and your script.Happiness
I
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.

Iridescence answered 30/9, 2008 at 0:19 Comment(0)
C
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'
Chavey answered 22/6, 2011 at 7:2 Comment(3)
And to find paths you want, app.methods.grep(/_path/) :)Brutify
And it's not always controler/action, depends on your routes, e.g. could be /users/all and map to Api::UsersController#index :)Brutify
@Brutify Or rake routes. :)Happiness
I
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
Insufficient answered 27/5, 2014 at 22:2 Comment(3)
NameError: undefined local variable or method app for main:ObjectFlaggy
you also need disable forgery_protection ApplicationController.allow_forgery_protection = falseLadin
Wow that's probably easier. What I wrote is with forgery protection. You don't need to disable it, but I'm sure it's more convenient!Insufficient
M
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.

Monied answered 31/1, 2009 at 14:27 Comment(1)
> => Notice: debugger option is ignored since Ruby 2.0 and it will be removed in future versions.Sanjuana
K
15

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

controller.method_name
helper.method_name
Kaliningrad answered 30/10, 2013 at 11:22 Comment(0)
S
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

Selfopinionated answered 29/3, 2013 at 18:19 Comment(0)
C
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.

Candancecandela answered 25/7, 2009 at 23:58 Comment(0)
S
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
Sunset answered 1/2, 2019 at 9:54 Comment(1)
It works! But how can I update action variables. Ex: def show response = @user.contributions end How do I override the @user variable?Diversion
G
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

Gastrotrich answered 24/12, 2017 at 7:18 Comment(0)
O
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)
Odoriferous answered 15/6, 2016 at 8:57 Comment(0)
A
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
Afterheat answered 8/1, 2018 at 7:15 Comment(0)
M
1

Trying to edit Tbabs' answer, but on second thought, better add an answer.

Like the most upvoted answer said, the app method is available in the console.
A handful of examples are there.

I want to point out that the official API doc has mentioned the functionalities here: https://api.rubyonrails.org/classes/Rails/ConsoleMethods.html

By reading the doc, you will discover that there is also the new_session method that you might prefer over app for the use case.

Mal answered 20/9, 2023 at 16:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.