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