2010-04-07 15 views
9

La mia app dovrebbe rendere html, per rispondere quando un utente fa clic su ajax-link.I miei metodi di supporto nel controller

mio regolatore:

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 

mio aiuto:

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 

ho provato questi metodi:

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

e:

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) 

Inoltre, so: helper_method, e funziona, ma non voglio sovraccaricare il mio ApplicationController con molti metodi

risposta

13

Oki. Ricapitoliamo. Si desidera accedere a determinate funzioni/metodi, ma non si desidera che tali metodi siano collegati all'oggetto corrente.

Quindi si desidera creare un oggetto proxy, che eseguirà il proxy/delegherà a tali metodi.

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 

E, nel controllore:

class UserController < ApplicationController 
    def your_method 
    Helper.link_to_profile 
    end 
end 

Il principale svantaggio di questo approccio è che le funzioni di supporto non si avrà accesso al contesto di controllo (EG non si avrà accesso a params , sessione, ecc.)

Un compromesso sarebbe quello di dichiarare tali funzioni come private nel modulo helper, quindi, quando includerete il modulo, saranno anche private nella classe controller.

module ApplicationHelper 
    private 
    def link_to_profile 
    end 
end 

class UserController < ApplicationController 
    include ApplicationHelper 
end 

, come indicato da Damien.

Aggiornamento: Il motivo per cui si ottiene l'errore "url_for" è che non si ha accesso al contesto del controller, come indicato sopra. Si potrebbe forzare il passaggio del controllore come parametro (Java-style;)) come:

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

e poi, in vostro aiuto:

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

o evento un hack più grande, presentato here. Tuttavia, vorrei raccomandare la soluzione rendendo i metodi privati ​​e includendoli nel controller.

+0

Sì, ho provato il tuo primo metodo, ma ho ottenuto: NoMethodError (metodo non definito 'url_for 'per nil: NilClass). Penso che il modulo helper non possa accedere agli helper di ActionView – FancyDancy

+0

Yap, è necessario avere accesso al contesto del controller. –

+0

Ho aggiornato la mia risposta per prendere in considerazione ciò che hai detto. –

15

Gli helper sono solo moduli ruby ​​che puoi includere in qualsiasi controller come ogni modulo

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 

E, nel controller:

class UserController < ApplicationController 
    include UserHelper 

    def create 
     redirect_to link_to_profile(User.first) 
    end 
end 
+0

Non voglio includere l'intero userhelper. E se lo facessi, UserController renderà disponibili quei metodi per richiederli tramite GET -/users/link_to_profile. Posso creare una classe personalizzata, ma cosa dovrei includere per ottenere il metodo "url_for"? – FancyDancy

+3

Non è possibile includere solo un metodo da un modulo. Crea un nuovo helper con solo i metodi che desideri includere nel controler. E includere questi metodi come privati ​​in modo che non siano accessibili dalle richieste http. –

Problemi correlati