2010-04-07 2 views
9

Мое приложение должно отображать html, чтобы ответить, когда пользователь нажимает ajax-ссылку.Мои вспомогательные методы в контроллере

Мой контроллер:

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 

Моя помощница:

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 

Я попробовал такие методы:

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

и:

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) 

Кроме того, да, я ЗНАЮ о: helper_method, и он работает, но я не хочу перегружать мой ApplicationController большим количеством таких методов.

ответ

13

Оки. Давайте повторим. Вы хотите получить доступ к определенным функциям/методам, но не хотите, чтобы эти методы были привязаны к текущему объекту.

Итак, вы хотите создать прокси-объект, который будет прокси/делегировать эти методы.

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 

И в контроллере:

class UserController < ApplicationController 
    def your_method 
    Helper.link_to_profile 
    end 
end 

Основным недостатком такого подхода является то, что из вспомогательных функций, вы не будете иметь доступ к контроллеру контекста (например, вы не будете иметь доступ к Params , сеанс и т. д.)

Компромиссом было бы объявить эти функции как частные в вспомогательном модуле, поэтому, когда вы включите модуль, они также будут закрыты в классе контроллера.

module ApplicationHelper 
    private 
    def link_to_profile 
    end 
end 

class UserController < ApplicationController 
    include ApplicationHelper 
end 

, as Damien Указанный.

Обновление: Причина, по которой вы получаете ошибку «url_for», состоит в том, что у вас нет доступа к контексту контроллера, как указано выше. Вы могли бы заставить пропускание контроллера в качестве параметра (Java-стиля;)), как:

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

, а затем, в вашем помощнике:

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

или событие больше хака, представленный here. Тем не менее, я бы рекомендовал решение, сделав методы частными и включив их в контроллер.

+0

Да, я пробовал свой первый метод, но я получил: NoMethodError (неопределенный метод 'url_for 'для nil: NilClass). Я думаю, вспомогательный модуль не может получить доступ к помощникам ActionView – FancyDancy

+0

Yap, вы должны иметь доступ к контексту контроллера. –

+0

Я обновил свой ответ, чтобы принять во внимание то, что вы сказали. –

15

помощники - это просто рубиновые модули, которые вы можете включить в любой контроллер только как любой модуль.

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 

И, в контроллере:

class UserController < ApplicationController 
    include UserHelper 

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

Я не хочу включать весь пользовательский режим. И если я это сделаю, UserController сделает эти методы доступными для запроса их через GET -/users/link_to_profile. Я могу создать собственный класс, но что мне включить, чтобы получить метод «url_for»? – FancyDancy

+3

Вы не можете включить только один метод из модуля. Создайте новый помощник с помощью только тех методов, которые вы хотите включить в контроллер. И включить эти методы как частные, чтобы они не были доступны из HTTP-запросов. –

Смежные вопросы