#ruby-on-rails #ruby
#ruby-on-rails #ruby
Вопрос:
Кто-нибудь знает, почему включенный метод не работает внутри метода класса?
class MyClass
include ActionView::Helpers::NumberHelper
def test
puts "Uploading #{number_to_human_size 123}"
end
def self.test
puts "Uploading #{number_to_human_size 123}"
end
end
ree-1.8.7-2011.03 :004 > MyClass.new.test
Uploading 123 Bytes
=> nil
ree-1.8.7-2011.03 :005 > MyClass.test
NoMethodError: undefined method `number_to_human_size' for MyClass:Class
from /path/to/my/code.rb:9:in `test'
from (irb):5
ree-1.8.7-2011.03 :006 >
Ответ №1:
Для тех, кто хочет использовать некоторые пользовательские помощники в библиотеке уровня класса или модели, иногда не стоит включать все помощники. Вместо этого вызовите его напрямую:
class MyClass
def test
::ApplicationController.helpers.number_to_human_size(42)
end
end
(Взято из http://makandracards.com/makandra/1307-how-to-use-helper-methods-inside-a-model )
Ответ №2:
Трудно сказать, не видя вашего вспомогательного кода, но include
все методы в этом модуле будут вставлены в экземпляры класса, в который вы включаете. extend
используется для переноса методов в класс. Следовательно, если у вас есть только методы, определенные в NumberHelper, они помещаются во все экземпляры MyClass, но не в класс.
Способ, которым работает множество расширений Rails, использует методы, которые были объединены в ActiveSupport::Concern . Вот хороший обзор.
По сути, расширение ActiveSupport::Concern в ваших модулях позволит вам указать в подмодулях, называемых ClassMethods и InstanceMethods, какие функции вы хотите добавить к классам и экземплярам, в которые вы включаете свой модуль. Например:
module Foo
extend ActiveSupport::Concern
module ClassMethods
def bar
puts "I'm a Bar!"
end
end
module InstanceMethods
def baz
puts "I'm a Baz!"
end
end
end
class Quox
include Foo
end
Quox.bar
=> "I'm a Bar"
Quox.new.baz
=> "I'm a Baz"
Я использовал это раньше, чтобы делать такие вещи, как определение функции bar в ClassMethods, а затем также сделать ее доступной для экземпляров, определив метод bar с тем же именем, который просто вызывает this.class.bar, делая его вызываемым из обоих. Есть много других полезных вещей, которые делает ActiveSupport::Concern, например, позволяет вам определять блоки, которые вызываются обратно, когда модуль включен.
Так вот, это происходит именно здесь, потому что вы include
используете свой helper, что может указывать на то, что эта функциональность более универсальна, чем helper — помощники автоматически включаются только в представления, поскольку они предназначены только для помощи с представлениями. Если вы хотите использовать своего помощника в представлении, вы могли бы использовать helper_method
макрос в своем классе, чтобы сделать этот метод видимым для ваших представлений, или, что еще лучше, создать модуль, как указано выше, и не думать о нем как о вспомогательном средстве, а использовать include, чтобы включить его в классы, в которых вы хотите его использовать. Я думаю, что я бы пошел по этому пути — ничто не говорит о том, что вы не можете создать модуль HumanReadableNumber и include
его в NumberHelper, чтобы сделать его легко доступным в ваших представлениях.
Комментарии:
1. Таким образом, мы можем просто расширить класс с помощью помощника, если нам нужны эти функции, верно?
Ответ №3:
Я столкнулся с той же проблемой. Вот как я это решил,
helper = Object.new.extend(ActionView::Helpers::NumberHelper)
helper.number_to_human_size(1000000)
Благодаря RailsForum.
Комментарии:
1. Очень простое решение.. Спасибо 🙂
2. Это не мой вопрос, поэтому я не могу принять ваш ответ как приемлемый. 🙁
Ответ №4:
Я столкнулся с той же проблемой. в моем случае замена include
на extend
заставила это работать.
class MyClass
extend ActionView::Helpers::NumberHelper
...
end