views:

43

answers:

3

Let's say I have methodA

  def methodA
    note = Note.find(params[:id])
    note.link = params[:link]
    note.linktype = params[:linktype]
    note.save
    redirect_to(notes_url)
  end

When I call this method from a view like this, it works fine

<%= link_to image_tag(w.link, :border =>0), methodA_path(:linktype => w.linktype, :link => w.link, :id => @note.id) %>

But, if I call the method from another method in the same controller like this:

def methodB
   ...
   methodA(:id => params[:id], :link => link, :linktype => "image")
end

I get this error:

wrong number of arguments (1 for 0)

The parameters that methodA is getting are still the same parameters that methodB got, not the ones that I'm sending from methodB. How do I get around this problem? Thank for reading.

A: 

I assume by addMedia you mean methodA

Note, method methodA_path is not the same as methodA. First one is automatically generated because you have a route named methodA and returns url necessary to access that route. Thus, it returns string. While methodA usually renders html template.

If you want to delegate rendering to another action, you can do something like this: redirect_to :action => :methodA, :id => 1, :otherParam => 2

Nikita Rybak
A redirect is not the same as calling the method, and if the routing is configured to require a POST (which it should be, since `methodA` is not idempotent), then it won't have the same effect either. Not that I recommend calling actions from actions, as I mention in my answer.
Ian Terrell
@Ian _Not that I recommend calling actions from actions_ And I also think it's not what he wanted :) That we can only guess
Nikita Rybak
+2  A: 

Several things:

  • The Ruby, and therefore Ruby on Rails, naming convention is to use underscore notation rather than camelcase. So it should be method_a rather than methodA.
  • It looks like methodA is a controller action. If you look at your method signature, you're not actually defining any method parameters. That's a good thing: actions don't take any.
  • The params call in the methodA action is not accessing method parameters, but is access the Rails request params hash.
  • In your view, you're not actually calling the method. Rather, you're linking to the action, which, when clicked, initiate a request that is routed to that action. The actual method you're calling is methodA_path, which is generating the URL. This is a shortcut to url_for that automatically fills in some parameters for you (the other ones are in the hash you're passing). This method was automatically generated for you from your routes. Do a rake routes from the root of your app for a little more information.
  • If you wanted to call the action method from methodB, which is probably unwise, you don't need to pass it the parameters. Since methodB is also an action being called in its own request cycle, the params hash is still available to methodA, and it will find all of those things just fine. I'd suggest, however, extracting any common functionality into a third helper method and calling that from each action; calling actions from other actions feels like a code smell to me.

A bit of a summary: methodA and methodA_path are different methods. The former takes no parameters but accesses the Rails request parameters hash, while the latter takes parameters to pass to url_for.

This is all pretty basic, so I strongly suggest you read Agile Web Development with Rails (3rd edition for Rails 2, 4th for Rails 3).

Ian Terrell
Thanks for this, I'll check out the book. Quick question, when you say "extracting any common functionality into a third helper method and calling that from each action", should I put the third method in the same controller, or actually in the helper file for the controller?
ben
Helper methods that are called from the controller should be in the controller, roughly speaking. The helper file is for methods that are called from the views.
Ian Terrell
+1  A: 

A call to method_a_path and method_a are not the same.

  • The method_a does not take parameters. It accesses the parameters from the params hash set to the controller instance during action invocation.

  • The method_a_path does not invoke method_a, it just generates the URL for invoking the method. Actual invocation happens when the user clicks on the link and the rails server processes the request.

If you want to reuse the method in a diffrent context extract the code of the action to a new method as shown below:

class PostsController < ApplicationController
  def add_media
    add_media_with_para(params)
  end

  def action2
    add_media_with_para(:id => params[:id], :link => link, :linktype => "image")
  end
private

  def add_media_with_para p = {}
    note = Note.find(p[:id])
    note.link = p[:link]
    note.linktype = p[:linktype]
    note.save
    redirect_to(notes_url)    
  end
end

Now in your view you can obtain the path to add_media action as follows:

posts_add_media_path(:linktype => w.linktype, :link => w.link, :id => @note.id)
KandadaBoggu
Thanks for this, it really helped/
ben