NoMethodError при спробі викликати допоміжний метод із контролера Rails


75

Я отримую NoMethodErrorпри спробі отримати доступ до методу, визначеного в одному з моїх допоміжних модулів, з одного з моїх класів контролерів. Додаток My Rails використовує helperметод класу із :allсимволом, як показано нижче:

class ApplicationController < ActionController::Base
  helper :all
  .
  .
end

Я розумію, що це повинно зробити так, щоб усі мої класи контролерів автоматично включали всі допоміжні модулі в каталог app / helpers, отже, змішуючи всі методи в контролерах. Це правильно?

Якщо я явно includeдопоміжний модуль у контролері, то все працює правильно.


Чи контролер, про який йде мова, успадковує від ApplicationController?
Майкл Сепкот

Так. Я отримую проблему у двох контролерах, які використовують розглянутий метод, і обидва контролери успадковують від ApplicationController.
Джон Топлі

Відповіді:


50

helper :all робить усі помічники (так, усі) доступними у поданнях, він не включає їх у контролер.

Якщо ви хочете поділитися деяким кодом між помічником і контролером, що не дуже бажано, оскільки хелпер - це код інтерфейсу, а контролер - це код контролера, ви можете або включити помічника в контролер, або створити окремий модуль і включити його в контролер і помічник також.


1
Дякую, це має сенс. У мене є якийсь код, яким я хочу поділитися між двома контролерами. Я створю новий модуль і включу його.
Джон Топлі

Це справді найкращий підхід
ggomeze

2
Це насправді про спільний доступ між двома контролерами? Або між контролером і видом? Думаю, останнє. Тож шлях gamecreature (@template, view_context) мені здається правильним.
Паскаль

Мої прикольні методи переспрямування знаходяться в помічниках. Вони потрібні мені від моїх контролерів. Я не думаю, що це погано.
Віктор Пудеєв

2
Ви кажете, що небажано включати допоміжні методи в контролер, оскільки код інтерфейсу та код контролера повинні бути окремими. Але що, якщо ви робите фільтрацію, і вам, очевидно, потрібно отримати доступ до хешу параметрів у контролері та поданні, а іноді для доступу до змінних параметрів вам потрібно викликати методи у поданні та контролері. То що б ви зробили за таких обставин?
JohnMerlino

133

Щоб використовувати допоміжні методи, вже включені в механізм шаблонів:

  • Rails 2: використовуйте @templateзмінну.
  • Rails 3: має приємний метод контролера view_context

Приклад використання виклику 'number_to_currency' у методі контролера:

# rails 3 sample
def controller_action
  @price = view_context.number_to_currency( 42.0 ) 
end

# rails 2 sample
def controller_action
  @price = @template.number_to_currency( 42.0 ) 
end

3
Це найкраща відповідь групи - вона повинна бути вгорі
Obie

8
Для рейок 3. ЦЕ ВІДПОВІДЬ.
Хуанін,

Немає пояснення, як користуватися view_context.
Sarah Vessels

3
Іншим рішенням (працює в обох версіях рейок) є використання: ApplicationController.helpers.number_to_currency (42.0)
gamecreature

31

якщо вам потрібно поділитися методом між контролером та помічником / видом, ви можете просто визначити за допомогою 'helper_method' у верхній частині контролера:

class ApplicationController < ActionController::Base
  helper_method :my_shared_method
  ...

  def my_shared_method
    #do stuff
  end
end

сподівання, що допомагає


2
Лінія helper_method :my_shared_methodзовсім НЕ потрібно бути «зверху» .. він може піти куди - небудь, і я , як це найкраще безпосередньо над визначенням ( def my_shared_method).
user664833

29

Допоміжні методи від контролерів

Один із способів отримати доступ до ваших допоміжних методів - це просто включити ваш допоміжний файл.

include LoginHelper
cool_login_helper_method(x,y,z)

Це приведе всі методи з цього допоміжного модуля до сфери застосування у вашому контролері. Це не завжди добре. Щоб тримати область окремою, створіть об’єкт, надайте йому повноважень цього помічника та використовуйте його для виклику методів:

login_helper = Object.new.extend(LoginHelper)
login_helper.cool_login_helper_method(x,y,z)

Помічник: усі

helper :allробить усі ваші допоміжні методи з усіх ваших допоміжних модулів доступними для всіх ваших поглядів , але це не робить нічого для ваших контролерів. Це пов’язано з тим, що допоміжні методи розроблені для використання у поданнях, і, як правило, не повинні отримувати доступ з контролерів. У новіших версіях Rails ця опція завжди ввімкнена для кожного контролера за замовчуванням.



5

Час, коли я вважаю, що це є найбільш необхідним, - це написання флеш-пам'яті або спеціальних засобів перевірки помилок. За певних обставин приємно використовувати у флеш-повідомленні такі речі, як помічники link_to. Я використовую наступне рішення, щоб отримати помічники ActionView у контролер. Майте на увазі, що, як було згадано вище, це порушує поділ MVC, тому, якщо хтось має кращу ідею, повідомте мене!

Під ApplicationController додайте це:

class Something
  include Singleton
  include ActionView::Helpers::UrlHelper
end

а всередині ApplicationController додайте

def foo
  Something.instance
end

і нарешті, у контролері, де ви хочете отримати доступ до допоміжного коду:

messages << "<li class='error'>Your have an Error!<%= foo.link_to('Fix This', some_path) %></li>"

Сподіваюся, це якимось чином допомагає!



4

До будь-якого помічника можна отримати доступ за допомогою змінної @template у контролері.

@ template.my_super_helper


3

Контролер не може отримати доступ до допоміжних методів автоматично. Ми повинні включити їх до контролера програми.

модуль ApplicationHelper

 def hello_message
    "Hello World"
 end

кінець

клас ApplicationController <ActionController :: Base

  include ApplicationHelper

  def message
     hello_message
  end

кінець


2

Помічники повинні використовуватися з шаблонами, тобто. перегляди, а не в контролерах. Ось чому ви не можете отримати доступ до методу. Якщо ви хочете поділитися методом між двома контролерами, вам доведеться визначити його, наприклад, у ApplicationController. helper: все говорить, що будь-який метод, який ви визначите в будь-якому допоміжному файлі в каталозі app / helpers, буде доступний для будь-якого шаблону.


1

Це можна зробити двома способами: або створити модуль, або використати змінну @template. Перегляньте це, щоб отримати докладнішу інформацію http://www.shanison.com/?p=305


1

Якщо ви зміните файл application_controller.rb на цей ...

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include SessionsHelper
end

... тоді всі помічники будуть доступні для всіх контролерів.


0

Якщо у вас є лише ApplicationHelper у вашій app/helpersпапці, ніж вам доведеться завантажувати його у свій контролер include ApplicationHelper. За замовчуванням Rails завантажує лише допоміжний модуль, який має те саме ім’я, що і ваш контролер. (наприклад, ArticlesController завантажить ArticlesHelper). Якщо у вас багато моделей (наприклад, статті; публікації; категорії), вам доведеться завантажувати кожну з них у ваш контролер. документи

Помічник

module PostsHelper
    def find_category(number)
        return 'kayak-#{number}'
    end
    def find_other_sport(number)
        "basketball" #specifying 'return' is optional in ruby
    end
end

module ApplicationHelper
    def check_this_sentence
        'hello world'
    end

end

Приклад контролера

class ArticlesController < ApplicationController
    include ApplicationHelper
    include PostsHelper
    #...and so on...

  def show#rails 4.1.5
    #here I'm using the helper from PostsHelper to use in a Breadcrumb for the view
    add_breadcrumb find_other_sport(@articles.type_activite), articles_path, :title => "Back to the Index"
    #add_breadcrumb is from a gem ... 
    respond_with(@articles)
  end
end

0

Будь ласка, спробуйте include SessionsHelperв ApplicationController

class ApplicationController < ActionController::Base
  include SessionsHelper
  ...
end
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.