I have a Rails controller where I accidentally defined the ‘edit’ method inside the ‘create’ method.
My Controller with the error:
class UsersController < ApplicationController
...
def create
@user = User.new(params[:user])
...
def edit
@user = User.find(params[:id])
@title = "Edit user"
@check = "BORK" # something I added for testing the rendered output
end
end
end
An example test;
it "should have the right title" do
get :edit, :id => @user
response.should have_selector('title', :content => 'Edit user')
end
So when I run the tests (I use rspec) and output the response.body, the User edit.html.erb template is rendered correctly; all the instance variables are visible. So all the tests pass.
Visiting the ‘edit’ URL correctly shows an error; the template uses @user instance variable, and it’s not set correctly. Of course correcting the controller fixes the error.
I don’t understand why the tests pass at all and why, in the test, all the instance variable values are visible?
My instinct suggests this is a scope problem? Something about @user being an instance variable, and that in the tests it’s set within the scope of the test, but in my controller it’s within the scope of the inner ‘edit’ method? But how does the test even find the ‘edit’ method? In what scope does that inner ‘edit’ method exist?
You should realise that the
defconstruct is as much executable code as anifstatement. It’s not invalid to put it inside another method, but it won’t be run until the outer method is called:The reason this was erroring in your browser was because Rails reloads all (most) of your classes each request. So, even if you had visited the
createaction – which would cause theeditmethod to be defined – the following request would have unloaded it again.However in the test environment, if an earlier test had called the
createaction then that would have defined theeditaction for future tests. You would see a different result if your tests were run in a different order (which in itself makes it a bad idea to rely on this).Generally of course this isn’t what you want at all, so just clear it up and move along 🙂