Unsure How To Modify ActionController::Base

Hello,

I would like to add a couple of methods like url_for in such a way that I can call these other methods in my actions just as I might call url_for. However I keep getting undefined method errors when I execute those calls.

Here's what I did:

1. Generated a plugin: $ script/generate plugin UrlForRouter

2. Created the file RAILS_ROOT/vendor/plugins/url_for_router/lib/url_for_router.rb
     This file looks like:

       module UrlForRouter
         def internal_url_for(options = {})
           host_url_for('0.0.0.0:3000', options)
         end

         def external_url_for(options = {})
           host_url_for('xxx.xxx.xxx.xxx', options) # anonymised
         end

         private
         def host_url_for(host, options = {})
           ENV['RAILS_ENV'] == 'development' ? url_for(options.merge(:host => host)) : url_for(options)
         end
       end

3. Edited RAILS_ROOT/vendor/plugins/url_for_router/init.rb to look like this:

       require 'url_for_router'
       ActionController::Base.include UrlForRouter

4. Restarted web server.

5. In my actions I call internal_url_for and external_url_for exactly as I would call url_for.
     I get the error: undefined method `external_url_for' for ...etc

Is this even the right way to proceed? If so, what am I doing wrong?

Many thanks,
Andy Stewart

Andrew Stewart wrote:

Hello,

I would like to add a couple of methods like url_for in such a way
that I can call these other methods in my actions just as I might
call url_for. However I keep getting undefined method errors when I
execute those calls.

Here's what I did:

1. Generated a plugin: $ script/generate plugin UrlForRouter

2. Created the file RAILS_ROOT/vendor/plugins/url_for_router/lib/
url_for_router.rb
     This file looks like:

       module UrlForRouter
         def internal_url_for(options = {})
           host_url_for('0.0.0.0:3000', options)
         end

         def external_url_for(options = {})
           host_url_for('xxx.xxx.xxx.xxx', options) # anonymised
         end

         private
         def host_url_for(host, options = {})
           ENV['RAILS_ENV'] == 'development' ? url_for(options.merge
(:host => host)) : url_for(options)
         end
       end

3. Edited RAILS_ROOT/vendor/plugins/url_for_router/init.rb to look
like this:

       require 'url_for_router'
       ActionController::Base.include UrlForRouter

4. Restarted web server.

5. In my actions I call internal_url_for and external_url_for
exactly as I would call url_for.
     I get the error: undefined method `external_url_for' for ...etc

Is this even the right way to proceed? If so, what am I doing wrong?

Many thanks,
Andy Stewart

>

Andrew,

I think that include method is private; not 100% sure, but I recall
having similiar troubles like you described. So you would have to
include it like:

ActionController::Base.send :include, UrlForRouter

Andy,

Unless you want to share these methods across multiple apps don't
bother making a plugin. Just do the following:

1) Put url_for_router.rb in your lib/
2) Include the module in application.rb

class ApplicationController < ActionController::Base
  include UrlForRouter
  ...
end

3) That's it!

Also, if you want to use these methods in your views you can simply
add the following to your module.

module UrlForRouter

    # --- [ ActionView helper methods ] ---
    def self.included(base)
      base.send :helper_method, :internal_url_for, :external_url_for
    end

end

Hope this helps.

Unless you want to share these methods across multiple apps don't
bother making a plugin. Just do the following:

I was thinking that I would reuse this code in future apps. Now that you mention it though, there's no need at the moment. So I'm going with your approach.

1) Put url_for_router.rb in your lib/
2) Include the module in application.rb

class ApplicationController < ActionController::Base
  include UrlForRouter
  ...
end

3) That's it!

That works wonderfully in my controller. Thanks!

However I also have a model (which doesn't subclass ActiveRecord) where I am trying to call my {internal, external}_url_for methods and I get this error:

   undefined method `url_for'
   #{RAILS_ROOT}/lib/url_for_router.rb:16:in `host_url_for'
   #{RAILS_ROOT}/lib/url_for_router.rb:10:in `external_url_for'

My model class finds and calls my methods but the UrlForRouter module can't resolve url_for in this context. What should I do here?

Also, if you want to use these methods in your views you can simply
add the following to your module.

module UrlForRouter

    # --- [ ActionView helper methods ] ---
    def self.included(base)
      base.send :helper_method, :internal_url_for, :external_url_for
    end

end

Very nice!

Hope this helps.

Yes it does, very much.

Thanks!
Andy

Bojan, thanks for this. I tried it but unfortunately it didn't work for me. However that's probably down to some other flaw on my part rather than your suggestion.

Thanks,
Andy

1) Put url_for_router.rb in your lib/
2) Include the module in application.rb

class ApplicationController < ActionController::Base
  include UrlForRouter
  ...
end

That works wonderfully in my controller. Thanks!

However I also have a model (which doesn't subclass ActiveRecord) where I am trying to call my {internal, external}_url_for methods and I get this error:

  undefined method `url_for'
  #{RAILS_ROOT}/lib/url_for_router.rb:16:in `host_url_for'
  #{RAILS_ROOT}/lib/url_for_router.rb:10:in `external_url_for'

My model class finds and calls my methods but the UrlForRouter module can't resolve url_for in this context. What should I do here?

Just for the record, I found this post[1] which argues persuasively for keeping knowledge of URLs out of models (as well as showing a good way to generate URLs within ActionMailer). So I moved the URL knowledge out of my model. Simple, really, when I thought about it.

Regards,
Andy

[1] http://www.ryandaigle.com/articles/2006/08/23/whats-new-in-edge-rails-form-urls-in-your-actionmailers-and-elsewhere