As part of my Rails learning, I've found a situation where I would like to be able to execute a method under a different controller's context. Something like:
def login_user old_controller = @controller @controller = AccountController.new post :login, :login => 'patrick', :password => 'sekrit' @controller = old_controllerend
def login_user old_controller = @controller @controller = AccountController.new post :login, :login => 'patrick', :password => 'sekrit'
@controller = old_controllerend
I'd like to write a helper method that accepts a controller type and a codeblock, then do something like (in pseudo-ruby)
def execute_under_different_controller controller, block old_controller = @controller @controller = controller block() @controller = old_controllerend
I don't think that it is the syntax, although I'm going to try to execute it. In order to do this, I need to figure out how to pass a codeblock to a method and execute it.
In order to figure this out, I need to write some tests. So, off I go to powershell to create a new gem for this. I had a set of tests before when I was learning some basic Ruby initially, inspired by Mike Clark's Ruby Learning Test series.
newgem learning_ruby --test=rspec
My first test looks like this
describe "Passing a codeblock" do it "should set a value" do @value = 0 execute_this do @value = 1 end @value.should == 1 end def execute_this block block endend
describe "Passing a codeblock" do it "should set a value" do @value = 0 execute_this do @value = 1 end @value.should == 1 end
def execute_this block block endend
This is my belief that Ruby should really work the way that I think it should. Well, going to my command-line
spec spec
That didn't work. I got a "wrong number of arguments (0 for 1)" error. I guess it doesn't just pass the do blocks like I thought it should. Let's try this line:
execute_this { @value = 1 }
I believe that the {} notation is a stand-in for "do end," so this should give me the same result. Same result, so I'll leave it like this. The question is how to execute a passed in block. Off to "Programming Ruby." What do you know, it appears you just call yield. Let's try it:
def execute_this yieldend
And, it worked! Hurra. Now, I can get back to my Rails problem. I want to execute under a different controller, so I'll change the following method:
to
def login_user execute_under_different_controller AccountController.new do post :login, :login => 'patrick', :password => 'sekrit' endend
def execute_under_different_controller controller old_controller = @controller @controller = controller yield @controller = old_controllerend
That worked. So, here's a question, could I just pass AccountController in and have the execute method call new? Let's try it.
def login_user execute_under_different_controller AccountController do post :login, :login => 'patrick', :password => 'sekrit' endend
def execute_under_different_controller controller old_controller = @controller @controller = controller.new yield @controller = old_controllerend