I was bouncing around the Rails API documentation yesterday, and I noticed a few rails console
tricks I haven’t seen before. There’s been plenty of posts about irb
and Rails before, but I’m hoping you’ll learn something new here. The following console samples were taken with Basecamp Next on Rails version 3.2.3.
Dive into your app
Running the app
method in rails console
gives you an integration session instance, so you can use it just like when you’re a normal integration test for Rails.
>> app.class
=> ActionDispatch::Integration::Session
Generating routes was always a hassle. What module did I need to include again? Did you remember to set the default_url_options
? Stop googling and just use app
:
>> app.project_path(Project.first)
=> "/projects/130349783-with-attachments"
It can make requests inside of your app as well:
>> app.get "/735644780/projects/605816632-bcx.atom"
=> 200
>> app.response.body
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<feed xml:lang=\"en-US\" ...
Check out ActionDispatch::Integration::Session and ActionDispatch::Integration::RequestHelpers to see what else this object can help you with.
Try out a helper
Getting a console session bootstrapped with Rails’ helpers is also a pain, which helper
can fix for you! You could also use it to play with building HTML tags, or any existing Rails helper that ActionView knows about.
>> helper.truncate("Testing", length: 4)
=> "T..."
>> helper.link_to "Home", app.root_path
=> "<a href=\"/\">Home</a>"
One gotcha with helper
is using instance variables inside of helper methods. Yes, I’m aware this is a Bad Idea™ with helpers in general, but I haven’t worked in a single Rails app without one. Here’s a small example of a method with one:
def title_tag(title = nil)
if @project.present? && title.nil?
content_tag :title, @project.name
elsif @project.present?
content_tag :title, "#{@project.name}: #{title}"
else
content_tag :title, title
end
end
We can use our old friend Object#instance_variable_set
to violate a core principle of OOP and let us try this helper out in the console:
>> helper.title_tag "Testing!"
=> "<title>Testing!</title>"
>> helper.instance_variable_set :@project, Project.first
=> #<Project id: 130349783, ...
>> helper.title_tag
=> "<title>With attachments!</title>"
>> helper.title_tag "Posts"
=> "<title>With attachments!: Posts</title>"
Dealing with a helper that uses params
is also not straightforward. However, we can trick ActionView into listening to us with a tiny hack. This is the console, after all! Let’s say we have this helper method:
def javascript_debugging_options
if params[:javascript_debugging] == "enabled"
{ debug: true, digest: false }
else
{}
end
end
Usually ActionView needs an entire ActionDispatch::Request
from the controller to figure out what parameters came in from the user. We can trick it with a little OpenStruct instead:
>> helper.controller = OpenStruct.new(params: {})
=> #<OpenStruct params={}>
>> helper.javascript_debugging_options
=> {}
>> helper.controller = OpenStruct.new(params: {javascript_debugging: "enabled"})
=> #<OpenStruct params={:javascript_debugging=>"enabled"}>
>> helper.javascript_debugging_options
=> {:debug=>true, :digest=>false}
Where does that method come from?
Hunting down the exact location of a given method isn’t always easy. Luckily, Ruby can point you in the right direction with Method#source_location
:
>> Project.instance_method(:trash).source_location
=> ["/Users/qrush/37s/apps/bcx/app/models/project.rb", 90]
Whoa! You’ll get back an array with the full path of where the method was defined along with that method’s line number in the file.
I’ve used this when looking for code buried inside of gems as well. Let’s try it on app
:
>> app.method(:get).source_location
=> ["/Users/qrush/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/bundler/gems/rails-7d95b814583b/actionpack/lib/action_dispatch/testing/integration.rb", 32]
This tip has saved me from an immense amount of source diving. Try it out!
More tips
Looking for more tips? JEG2 gave a neat talk at RailsConf about some of the hidden parts of Rails you might not know about. If you have some of your own, please share!