Tapping into routing helpers

you would have to declare the resources in routes.rb

for a simple REST route for Person model:

map.resources :person

should be all to it. this would give you the default routes for the REST actions: index persons_path show person_path(id) new new_person_path create persons_path, :method => :post edit edit_person_path(id) update person_path(id), :method => :put destroy person_path(id), :method => :delete

change_password_path looks a bit strange to me, since you most likely have no password model

oops, it's the plural for the map.resources, of course:

map.resources :persons

or, i think rails handles that as

map.resources :people

(I'm not native nglish speaking, so not 100% sure if that's persons or people here, but definitely the plural form)

Thorsten Mueller wrote:

you would have to declare the resources in routes.rb

Hi Thorsten,

I should have stated in my original post that I have them mapped in routes.rb. The route helpers themselves work fine, except where I'm trying to use them. I can understand why they might not work automagically in a required file in lib/ (I'd guess that I'd need to include something for that to work), but I kind of thought that by putting a new helper file in helpers/ I'd have access to all other helpers, whether they be added by rails or me.

Peace, Phillip

If you add your helper to ApplicationHelper does this give you access to the helpers you're looking for?

best. mike

Hardbap wrote:

If you add your helper to ApplicationHelper does this give you access to the helpers you're looking for?

best. mike

On May 26, 2:18 pm, Phillip Koebbe <rails-mailing-l...@andreas-s.net>

Hi Mike,

I copied all of the code into application_helper.rb and got the same error. It makes sense (to a degree) that the route helpers are only available by default to controllers and views, but surely there is a simple way to gain access to them elsewhere.

Thanks for the input, Phillip

Let me get this straight: you're trying to use your url helpers outside of the normal request cycle? In that case where you code is doesn't matter - it's all about the environment in which it it used. I don't off the top of my head what bits you need to include/setup in order to get url helpers to work, but action mailer may provide some inspiration, since it has to do that.

Fred

I've never had to do this myself but I just quickly looked through my copy of " The Rails Way" and page 409 has a sample helper that does exactly this (I'm leaving out most of the code for brevity):

def breadcrumbs   ...

  html = [link_to('Home', home_path)]

  ... end

You say that the routes are working fine,are the routes you're trying to use defined when you do a rake routes?

Frederick Cheung wrote:

Hi Fred,

Let me get this straight: you're trying to use your url helpers outside of the normal request cycle?

That's probably the most succinct way of putting. I created a sidebar menu mechanism that is multi-level and depends on CSS classes and DOM ids to be a certain way. I started by having each sub menu in a partial, but that became quite unwieldy. As I got to looking at it, I thought I could DRY it up by making the generation dynamic. I had used TigraMenu (a JavaScript menu) in a previous project, and I kind of liked the idea of defining the structure of the menu in arrays and hashes, so I decided to go that route and iterate through them to build the menu.

In that case where you code is doesn't matter - it's all about the environment in which it it used. I don't off the top of my head what bits you need to include/setup in order to get url helpers to work, but action mailer may provide some inspiration, since it has to do that.

I'll start digging and see what I find!

Fred

Thanks Phillip

Phillip Koebbe wrote:

to go that route and iterate through them to build the menu.

I forgot to say that it was at this point that I put it into a module in lib/ because it had grown to about 350 LOC for the menu structure definition and the generation code.

Phillip

Hardbap wrote:

I've never had to do this myself but I just quickly looked through my copy of " The Rails Way" and page 409 has a sample helper that does exactly this (I'm leaving out most of the code for brevity):

def breadcrumbs   ...

  html = [link_to('Home', home_path)]

  ... end

You say that the routes are working fine,are the routes you're trying to use defined when you do a rake routes?

Yes, all the routes I'm trying to use work fine and are listed in rake routes. Is there anything included or required in that file?

Thanks, Phillip

I guess I didn't truly understand what you are trying to accomplish. I thought you were trying to access rails helper methods from your custom helpers. My bad.

Good luck.

No there is nothing required or include in this example, but it won't help you if you are trying to "use your url helpers outside of the normal request cycle" as Fred made clear. That example I cited won't be of much use in this case. Sorry to have wasted your time with that.

Hardbap wrote:

I guess I didn't truly understand what you are trying to accomplish. I thought you were trying to access rails helper methods from your custom helpers. My bad.

Good luck.

You understand correctly. I think it might have to do with scoping or something. I just did a simple test, similar to what you posted.

In application_helper.rb, I put

def link_to_test     link_to 'Person', person_path end

and called it in a view. It worked just like you would expect it to. Then it dawned on me that the difference in my attempted use is that it is outside of a def when I'm defining a constant. In my limited Ruby knowledge, I don't quite understand this.

Phillip

So here is some real code:

module ApplicationHelper   def link_to_test     link_to 'Person', person_path # works here   end # link_to_test

  MY_ACCOUNT_MENU = {     :id => 'my_account_menu',     :title => 'My Account',     :children => [       {         :title => 'Home',         :url => person_path # does not work here       }     ]   }

  # other menu constants defined here

  MENUS = {     :sa => SA_MENU,     :my_account => MY_ACCOUNT_MENU,     :player => PLAYER_MENU,     :parent => PARENT_MENU,     :coach => COACH_MENU,     :referee => REFEREE_MENU,     :sport_admin => SPORT_ADMIN_MENU,     :organization_admin => ORGANIZATION_ADMIN_MENU   }

  def generate_sidebar_menu(menu_type, sidebar_menu_state)     generate_menu(MENUS[menu_type], sidebar_menu_state)   end # generate

  private

  def generate_menu(menu, sidebar_menu_state)     # the gory details of generating the HTML   end end

Hardbap wrote: > I guess I didn't truly understand what you are trying to accomplish. I > thought you were trying to access rails helper methods from your > custom helpers. My bad.

> Good luck.

You understand correctly. I think it might have to do with scoping or something. I just did a simple test, similar to what you posted.

In application_helper.rb, I put

def link_to_test link_to 'Person', person_path end

and called it in a view. It worked just like you would expect it to. Then it dawned on me that the difference in my attempted use is that it is outside of a def when I'm defining a constant. In my limited Ruby knowledge, I don't quite understand this.

it's called scope, when you call "person_path" inside another method, the method doesn't know about it, i.e. class my_class   def method_1   end

  def method_2      #call method_!      self.method_1 ##see the self.   end end

Sorry man but there is a problem with your example when I put it to the test in irb. The name my_class is not a valid Ruby class name and this example works just fine on 1.8.6.

class MyClass   def method_1     puts "hello"   end

  def method_2    method_1 # see no self   end

  def method_3    call method_1 # this works too   end

  def method_4    self.method_1 # self works also   end

end

c = MyClass.new

c.method_1 #=> "hello" c.method_2 #=> "hello" c.method_3 #=> "hello"

Phillip:

Because you're defining MY_ACCOUNT_METHODS as a constant in a module it will not have access to the template methods.

Named routes methods are injected into ActionController::Base, and ActionView::Base, and since the Helper methods are usually called from those contexts, you can call the named routes methods from within the helper methods, but not within the helper declaration itself, if that makes sense.

so if you define a method in your helper:

def some_method   person_path end

"person_path" doesn't need to be recognized until it is called by the ActionView or ActionController class that has included this helper module. That ActionView or ActionController class will have also included the named routes methods so, it will know what it means.

So everything works as expected.

But if you call it from within the actual definition of the module, as you have done here, nobody has told it yet about the named routes, so it freezes up.

You can solve the problem in several ways. One way is to instead of declaring the :url for each menu in your constant, just declare a symbol for the method to call later:

MY_ACCOUNT_MENU = {     :id => 'my_account_menu',     :title => 'My Account',     :children => [       {         :title => 'Home',         :url_method => :person_path       }     ]   }

Then in generate_menu, to get the url, call self.send(menu[:url_method])

And in that case "self" will be the ActionView or ActionController object doing the calling, and it will know what "person_path" means.

Hope that helps.

JDevine wrote:

You can solve the problem in several ways. One way is to instead of declaring the :url for each menu in your constant, just declare a symbol for the method to call later:

MY_ACCOUNT_MENU = {     :id => 'my_account_menu',     :title => 'My Account',     :children => [       {         :title => 'Home',         :url_method => :person_path       }     ]   }

Then in generate_menu, to get the url, call self.send(menu[:url_method])

And in that case "self" will be the ActionView or ActionController object doing the calling, and it will know what "person_path" means.

Hope that helps.

JDevine,

Thanks for the insight. As I mentioned earlier, I thought it had to do with scoping. I guess I should have injected the word "magic" in my statement about Ruby knowledge:

"In my limited knowledge of Ruby magic, I don't quite understand this."

So I took your idea and extended it just a little.

    if menu.has_key?(:url)       url = menu[:url].class == String ? menu[:url] : self.send(menu[:url])       output += "<a href=\"#{url}\">"     end

I can mix the urls how I need to, either with the symbol that gets turned into a route helper or with a hard-coded string (for things that I don't have a named route for). I haven't thought it through completely yet, but I believe this approach will work fine for my whole menu structure. All of the resources I'll be linking on the menu will be singletons and I'll have a session variable storing an id, so I won't have to worry about ever having to pass a parameter to the routing helpers.

Cool. This was so much easier than trying to figure out ActionMailer. I started looking in there but my head started to spin. I was going to have to dig pretty deep before I could starting putting the pieces together.

Much appreciation to all who contributed to this thread.

Peace, Phillip