views:

472

answers:

3

My app should render html, to answer when a user clicks ajax-link.

My controller:

def create_user
  @user = User.new(params)
  if @user.save
    status = 'success'
    link = link_to_profile(@user) #it's my custom helper in Application_Helper.rb
  else
    status = 'error'
    link = nil
  end

  render :json => {:status => status, :link => link}
end

My helper:

  def link_to_profile(user)
    link = link_to(user.login, {:controller => "users", :action => "profile", :id => user.login}, :class => "profile-link")
    return(image_tag("/images/users/profile.png") + " " + link)
  end

I have tried such methods:

ApplicationController.helpers.link_to_profile(@user)
# It raises: NoMethodError (undefined method `url_for' for nil:NilClass)

and:

class Helper
  include Singleton
  include ActionView::Helpers::TextHelper
  include ActionView::Helpers::UrlHelper
  include ApplicationHelper
end
def help
  Helper.instance    
end

help.link_to_profile(@user)
# It also raises: NoMethodError (undefined method `url_for' for nil:NilClass)

In addition, yes, I KNOW about :helper_method, and it works, but i don't want to overload my ApplicationController with a plenty of that methods

+1  A: 

helpers are just ruby modules which you can include in any controller just like any module.

module UserHelper
    def link_to_profile(user)
        link = link_to(user.login, {:controller => "users", :action => "profile", :id => user.login}, :class => "profile-link")
        return(image_tag("/images/users/profile.png") + " " + link)
    end
end

And, in your controller :

class UserController < ApplicationController
    include UserHelper

    def create
        redirect_to link_to_profile(User.first)
    end
end
Damien MATHIEU
i don't want to include the whole userhelper. And if I would do this, UserController will make that methods available to request them via GET - /users/link_to_profile. I can make custom class, but what should I include, to get method "url_for" ?
FancyDancy
You can't include only one method from a module.Create a new helper with only the methods you want included in controler.And include these methods as private so they won't be accessible from http requests.
Damien MATHIEU
+1  A: 

Oki. Let's recap. You want access to certaint functions/methods, but you don't want those methods to be attached to current object.

So you want to make a proxy object, that will proxy/delegate to those methods.

class Helper
  class << self
   #include Singleton - no need to do this, class objects are singletons
   include ApplicationHelper
   include ActionView::Helpers::TextHelper
   include ActionView::Helpers::UrlHelper
   include ApplicationHelper
  end
end

And, in controller:

class UserController < ApplicationController
  def your_method
    Helper.link_to_profile
  end
end

The main disadvantage to this approach is that from the helper functions you won't have access to controller context (EG you won't have access to params, session, etc)

A compromise would be to declare those functions as private in the helper module, therefore, when you will include the module, they will also be private in the controller class.

module ApplicationHelper
  private
  def link_to_profile
  end
end

class UserController < ApplicationController
  include ApplicationHelper
end

, as Damien pointed out.

Update: The reason why you get the 'url_for' error is that you do not have access to controller's context, as stated above. You could force passing the controller as a parameter(Java-style ;) ) like:

Helper.link_to_profile(user, :controller => self)

and then, in your helper:

def link_to_profile(user, options)
  options[:controller].url_for(...)
end

or event a bigger hack, presented here. However, i would reccomend the solution with making methods private and including them in the controller.

Vlad Zloteanu
Yes, i have tried your first method, but i got: NoMethodError (undefined method `url_for' for nil:NilClass). I think, the helper module can't get access to ActionView's helpers
FancyDancy
Yap, you must have access to the context of the controller.
Vlad Zloteanu
I updated my response to take in consideration what you said.
Vlad Zloteanu
+1  A: 

Take that! http://apotomo.de/2010/04/activehelper-rails-is-no-pain-in-the-ass/

That's exactly what you were looking for, dude.

Nick