Mark Needham

Thoughts on Software Development

Archive for the ‘rails’ tag

Rails: Using helpers inside a controller

with one comment

For about an hour or so this afternoon we were following the somewhat evil practice of using a method defined in a helper inside a controller.

The method was defined in the ApplicationHelper module:

module ApplicationHelper
	def foo
		# do something
	end
end

So we initially assumed that we’d just be able to reference that method inside any of our controllers since they all derive from ApplicationController.

That wasn’t the case so our next attempt was to try and add it as a helper:

class FooController < ApplicationController
	helper :application
end

Which makes it accessible from the view but not from the controller…

Eventually we called Ashwin to help us out and he came across this thread on dzone.

About half way down the page ovhaag points out that we can use ‘@template’ to get access to helper methods:

In any controller, there is a “@template”-instance and you can call helper methods on this.

I found this trick in http://media.railscasts.com/videos/132_helpers_outside_views.mov

Ryan is not sure if this use is intended but it is very short and today it works.

We can use that instance variable like so:

class FooController < ApplicationController
	def our_method
		# We can call foo like this
		@template.foo
	end
end

We eventually found out another way to do what we wanted but it seems like a neat little trick

Written by Mark Needham

January 11th, 2011 at 5:09 pm

Posted in Ruby

Tagged with

Rails: A slightly misleading error

without comments

We recently created a new project to handle the reporting part of our application and as with all our projects we decided not to checkin any configuration “.yml’ files but rather ‘.yml.example’ files which people can then customise for their own environments.

So in our config directory would look something like this when you first checkout the project:

  • config
    • database.yml.example
    • some.yml.example

And we’d need to copy those files to get ‘.yml’ versions, changing any parameters that we need to for our local environment.

The disadvantage of this approach is that you have an extra step on using a project for the first time, a step that I’ve been meaning to automate.

Several people ran into a somewhat confusing error message when running our rake file after forgetting to create these ‘.yml’ files which looked like this:

> rake db:migrate
(in /Users/mneedham/SandBox/project)
rake aborted!
uninitialized constant ActiveRecord
 
(See full trace by running task with --trace)

Running with –trace didn’t reveal our mistake but interestingly launching ‘script/console’ did!

script/console
Loading development environment (Rails 2.3.5)
/Users/mneedham/SandBox/project/config/environment.rb:4:in `initialize':Errno::ENOENT: No such file or directory - /Users/mneedham/SandBox/project/config/some.yml
/Users/mneedham/SandBox/project/vendor/rails/railties/lib/rails/backtrace_cleaner.rb:2:NameError: uninitialized constant ActiveSupport::BacktraceCleaner
/Users/mneedham/SandBox/project/vendor/rails/railties/lib/console_with_helpers.rb:5:NameError: uninitialized constant ApplicationController
ruby-1.8.7-p299 >

This is the environment.rb file in which we were loading that yml file:

config/environment.rb

....
require 'yaml'
some_file = File.join(File.dirname(__FILE__), "some.yml")
...

It’s a relatively simple mistake to make so I was surprised that rake didn’t tell us that the file didn’t exist rather than failing when trying to require ActiveRecord.

Written by Mark Needham

November 16th, 2010 at 9:17 pm

Posted in Ruby

Tagged with ,

RSpec: Testing Rails routes

without comments

Something which I keep forgetting is how to write controller tests where I want to check whether an action correctly redirected to another action.

With most of the routes in our application we’ve created a ‘resourceful route’ where each action maps to a CRUD operation in the database.

We can do that with this type of code in routes.rb:

ActionController::Routing::Routes.draw do |map|
	map.resources :foos
end

Several helper methods based on named rotes get created and included in our controllers when we do this and we have access to those inside our specs.

We can see the named routes by executing the following command from the terminal:

mneedham@markneedham.local ~/SandBox/rails_test$ rake routes CONTROLLER=foos
(in /Users/mneedham/SandBox)
    foos GET    /foos(.:format)          {:action=>"index", :controller=>"foos"}
         POST   /foos(.:format)          {:action=>"create", :controller=>"foos"}
 new_foo GET    /foos/new(.:format)      {:action=>"new", :controller=>"foos"}
edit_foo GET    /foos/:id/edit(.:format) {:action=>"edit", :controller=>"foos"}
     foo GET    /foos/:id(.:format)      {:action=>"show", :controller=>"foos"}
         PUT    /foos/:id(.:format)      {:action=>"update", :controller=>"foos"}
         DELETE /foos/:id(.:format)      {:action=>"destroy", :controller=>"foos"}

The following helper methods would be created for this resource as per the documentation in resources.rb:

# Named Route Helpers
# ============ =====================================================
# foos foos_url, hash_for_foos_url,
# foos_path, hash_for_foos_path
#
# foo foo_url(id), hash_for_foo_url(id),
# foo_path(id), hash_for_foo_path(id)
#
# new_foo new_foo_url, hash_for_new_foo_url,
# new_foo_path, hash_for_new_foo_path
#
# edit_foo edit_foo_url(id), hash_for_edit_foo_url(id),
# edit_foo_path(id), hash_for_edit_foo_path(id)

Keeping this in mind means that if we do something like this inside our ‘create’ action:

class FoosController < ApplicationController
   def create
      ...
      redirect_to :action => :index
   end
end

We’d be able to test that redirection with a spec along the following lines:

describe "POST create" do
   it "should redirect back to the index page" do
      post :create, :foo => { :bar => "value" }
 
      response.should redirect_to foos_path
   end
end

We can also use any of those other helper methods inside our tests which seems obvious looking at it now but wasn’t for me until a colleague pointed it out.

It is pretty cool to be able to write specs like this and they seem much more readable than the equivalents you’d be able to test around ASP.NET MVC code in C#.

Written by Mark Needham

October 13th, 2010 at 6:25 pm

Posted in Ruby

Tagged with ,

Rails: before_filter, rescue_from and so on

without comments

One thing I’ve noticed while browsing our Rails code base is that the first entry point inside a controller is much less frequently the method corresponding to the action than it would be with a C# ASP.NET MVC application.

The concept of filters exists in ASP.NET MVC but on the projects I’ve worked on they’ve been used significantly less than before filters would be in a Rails application.

As a result I’m getting much more in the habit of checking for the before filters in the ApplicationController when an action isn’t working as expected to try and figure out what’s going on.

One which caught us out the other day is the ‘rescue_from’ method which gets mixed in from Rescuable.

Every single time we tried to login we were just getting redirected back to the login page again with no exception being reported anywhere.

Eventually we realised that the InvalidAuthenticityToken exception was being thrown because we somehow had a different token stored in our browser’s cookie than was in the form.

Since our LoginController extends the ApplicationController, the following logic was being used to handle the exception:

class ApplicationController < ActionController::Base
   rescue_from ActionController::InvalidAuthenticityToken, :with => :redirect_to_referer
 
  def redirect_to_referer_or_path
    redirect_to request.referer
  end

We initially didn’t spot it because it was hidden away between a whole load of other before filters and includes of modules.

The convention as far as I can tell is to try and keep as little code as possible inside the action method and handle common logic – such as looking up a user based on an id or handling exceptions – in filters.

It helps to keep the code inside actions pretty clean and remove duplication but I just need to remember to check both the action and the top of the class for any filters when investigating problems.

Written by Mark Needham

October 5th, 2010 at 8:53 am

Posted in Ruby

Tagged with ,

Rails: Faking a delete method with ‘form_for’

with 2 comments

We recently had a requirement to delete an item based on user input and wanting to adhere to the ‘RESTful’ approach that Rails encourages we therefore needed to fake a HTTP Delete method request.

The documentation talks a little about this:

The Rails framework encourages RESTful design of your applications, which means you’ll be making a lot of “PUT” and “DELETE” requests (besides “GET” and “POST”). However, most browsers don’t support methods other than “GET” and “POST” when it comes to submitting forms.

Rails works around this issue by emulating other methods over POST with a hidden input named “_method”, which is set to reflect the desired method:

The example provided is for the ‘form_tag’ helper method where you just need to pass a hash containing an entry with a key ‘:method’ and value ‘delete’.

We tried to do the same with ‘form_for’ but unfortunately found that that the hidden ‘_method’ field was still being set to ‘POST’.

It turns out that ‘form_for’ expects the ‘:method’ to be provided as part of the right hand most argument as part of a hash with the key ‘:html’.

We therefore need to write something like this if we want to simulate a delete request:

 <% form_for(item, :html => {:method => 'delete'}) do  %>
 ...
 <% end %>

The hidden field is eventually created inside form_tag_helper.rb:

def extra_tags_for_form(html_options)
          ...
          method_tag = case method
            when /^get$/i # must be case-insensitive, but can't use downcase as might be nil
              html_options["method"] = "get"
              ''
            when /^post$/i, "", nil
              html_options["method"] = "post"
              token_tag
            else
              html_options["method"] = "post"
              tag(:input, :type => "hidden", :name => "_method", :value => method) + token_tag
          end
 
         ...
end

I’m not finding the method signatures of many Ruby libraries particularly intuitive at the moment.

It seems like a lot of times the favoured approach is to pass in a hash into methods and then work off implicit knowledge that Ruby/Rails programmers have about the way that hashes are typically used.

While this makes methods very flexible it seems more difficult to understand how to use them as a consumer than if they took in specifically typed values as parameters.

It’ll be interesting to see if/how my opinion changes with respect to this.

Written by Mark Needham

September 20th, 2010 at 6:52 pm

Posted in Ruby

Tagged with ,

Rails: Populating a dropdown list using ‘form_for’

without comments

Last week we were trying to make use of Rails’ ‘form_for’ helper to populate a dropdown list with the values of a collection that we’d set to an instance variable in our controller.

My colleague pointed out that we’d need to use ‘collection_select‘ in order to do this.

We want to put the values in the ‘foos’ collection onto the page. ‘foos’ is a hash which defines some display values and their corresponding values like so:

class FooController < ActionController::Base
	def index
		# @mainFoo defined with some value irrelevant to this example
		@foos = { "value1" => 1, "value2" => 2 }
	end
end

The code we need to do this looks like this:

<%form_for @mainFoo, :html => { :name=> "ourForm", :id=> "ourForm" },:url => {:controller => "foo", :action => :bar} do | mainFoo |%>
 
<%= foo.collection_select :foo_id, {"Please select"=>""}.merge!(@foos), :last, :first, { :selected => "Please select" }, {:name => "foo", :id => "foo"} %>

The method signature that we’re passing those parameters to reads like this:

def collection_select(method, collection, value_method, text_method, options = {}, html_options = {})

In this case we want the selected value to always be ‘Please select’ so we need to specify that in the ‘options’ hash. If ‘selected’ wasn’t specified in the hash then the code would try to make the selected value @mainFoo.foo_id which in this case has no value anyway.

The other thing which I thought was quite neat is the way that you need to provided the ‘value_method’ and ‘text_method’ as parameters so that the dropdown list can be constructed with the appropriate labels and values.

In this case we have the display values as the keys in the hash and the values as the values in the hash so we can retrieve those entries from the collection by using the ‘:last’ and ‘:first’ methods.

We end up in the following method:

      def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
        options = collection.map do |element|
          [element.send(text_method), element.send(value_method)]
        end

This creates an array of arrays which is used later on.

In our case the values passing through this method would read like this:

        collection = { "value1" => 1, "value2" => 2 }
 
        options = collection.map do |element|
          [element.send(text_method), element.send(value_method)]
        end
 => [["value1", 1], ["value2", 2]]

I was initially a bit confused about how we were able to call the ‘collection_select’ method on ‘mainFoo’ but a quick browse of the ActionPack code showed that ‘mainFoo’ actually represents a wrapper around that object rather than the object itself.

Written by Mark Needham

August 31st, 2010 at 1:22 am

Posted in Ruby

Tagged with ,

Ruby: Parameterising with ActiveResource

without comments

We’ve been using Ruby/Rails on my current project to create a RESTful web service. One of the problems we wanted to solve was making the data queried by this web service configurable from our build.

We started off with the following bit of code (which makes use of the recently added ActiveResource class):

1
2
3
class MyClass < ActiveResource::Base
  self.site = "http://localhost:3000/"
end

And then called this class as follows:

1
MyClass.create(:param => "param-value")

This worked fine for us until we wanted to parameterise the ‘site’ value so that we could set it to different values depending which build we were running (dev/ci/qa). We tried all the obvious ways – overriding the constructor and passing in the site, trying to set the site by calling MyClass.site but none of them did what we wanted. We eventually ended up creating a new method to create an instance of the class with our configurable site:

1
2
3
4
5
6
7
8
class MyClass < ActiveResource::Base

def instance(site, args)
  self.site = site
  new(args) unless args.nil?
end

end

We then call the code like this:

1
2
my_class = MyClass.instance("http://localhost:3000", :param => "param-value")
my_class.save

It seems like a bit of a hack but it got it working!

Out of interest it has taken me ages to try and find a way to put the Ruby code on here in a readable format. I tried to use the TextMate exporter but that wasn’t giving me any love. I eventually ended up using Spotlight, a neat little tool written by Tyler Jennings. I found it from Jake Scruggs blog post.

Written by Mark Needham

August 8th, 2008 at 10:16 pm

Posted in Ruby

Tagged with , , ,

Watching a master at work

with one comment

I’ve always found it fascinating watching people who really excel in their field going about business, be it footballers, tennis players, actors, whoever.

This week at TWU I’ve been playing around with some Ruby on Rails as I mentioned in the previous post, and yesterday I had the opportunity to watch one of the leading figures in the Ruby on Rails field at work. Take a bow Obie Fernandez, who gave several of the TWU attendees a demonstration of how to develop applications using Ruby on Rails. It was actually bordering on the severely impressive watching the speed at which he thought through concepts and then transformed them into code.

I also realised that the way I’d been using the language previously had been dubious at best. I hadn’t realised that you can take care of database creation without using MySQL Administrator, nor had I realised quite how ‘clever’ Ruby on Rails is at mapping database tables to models created in the application.

It was almost painful watching how simple it is to do arduous tasks, such as creating textboxes and drop down boxes, in Ruby on Rails and it almost made me want to weep as I recalled the many hours I’ve spend using PHP and C# tweaking interaction between code and stored procedures/queries.

So +1 for Ruby on Rails and I certainly hope to improve my ability with it over the next few weeks.

Written by Mark

September 2nd, 2006 at 1:01 am

Posted in Ruby

Tagged with , , ,