Подтвердить что ты не робот

Могу ли я определить метод в моделях рельсов?

Моя модель рельсов имеет код, который пытается define_method(method_name) внутри модели.

Я продолжаю получать:

NoMethodError: undefined method `define_method'

Что я делаю неправильно? Я делаю это не в том месте. Мне нужен этот метод, привязанный к этой модели. Где еще я могу определить этот метод?

EDIT: Для тех, кто хочет увидеть код:

for field in rdev_fields
  next if self.attributes.include?(field)
  count = count + 1
  rdev_hash[field.to_sym] = self.attributes["attribute#{count}"]
  if !self.respond_to?(field) then
    define_method("#{field}") do
      self.send("attribute#{count}".to_sym)
    end
  end
end
4b9b3361

Ответ 1

Там нет ничего волшебного или о модели рельсов, это просто обычный класс с кучей ранее существовавших методов,

Итак, вопрос: "Могу ли я определить метод в классе"?

Часть 1: Да, вы можете.

Важным отличием является то, что вы можете определить метод в классе, а не в методе экземпляра

Например:

class Cow
  define_method "speak" do
    "MOOOO"
  end
end

Cow.new.speak
=> "MOOOO"

Это должно работать нормально. Обратите внимание, что вы определяете его в классе Cow, поэтому любые другие коровы, которые у вас уже есть, автоматически получат этот метод.

Часть 2: Что вы делаете, если хотите определить метод из метода экземпляра?

Вы не можете определять методы из метода экземпляра, поэтому вам нужно схватить класс и использовать его для определения метода. Вот так:

class Cow
  def add_speak
    self.class.send(:define_method, :speak) do
      "MOOOO added"
    end
  end
end

Cow.new.speak
NoMethodError: undefined method 'speak' for #<Cow:0xb7c48530>

Cow.new.add_speak
Cow.new.speak
=> "MOOOO added"

Проблема решена. Астуальные читатели заметят, что в этом примере я использую send(:define_method) - это необходимо, потому что define_method является закрытым, а частные методы доступны только для того, в котором они находятся. В этом случае define_method находится в class, мы находимся в этом экземпляре, поэтому мы не можем напрямую обращаться к нему.

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

Часть 3: Что вы делаете, если хотите определить метод только для одного объекта, а не для всех объектов этого класса?

Пример:

class Cow
  def add_speak_just_me
    class << self
      define_method "speak" do
        "MOOOO added for just me"
      end
    end
  end
end

Cow.new.speak
NoMethodError: undefined method 'speak' for #<Cow:0xb7c72b78>

c = Cow.new
c.add_speak_just_me
c.speak
=> "MOOOO added for just me" # it works, hooray

Cow.new.speak # this new cow doesn't have the method, it hasn't been automatically added
NoMethodError: undefined method `speak' for #<Cow:0xb7c65b1c>

Как это работает? Вниз по раввилону, ты идешь!

Прочтите это: http://dannytatom.me/metaid/ и удачи. Это помогает, когда вы понимаете, что "добавление метода" в экземпляр фактически не добавляет его в экземпляр: -)

Ответ 2

смог согнуть это вместе. Очень мало понимания того, что происходит на самом деле.

Мой метод экземпляра foo открывает класс и определяет панель на нем, чтобы затем я мог вызвать это в моем экземпляре. Более опытные люди сообщают нам, если это одновременно открывает банку червей.

Было бы полезно узнать ваше конкретное использование для этого.

class User < ActiveRecord::Base

  def foo
    (class << self; self; end).class_eval do
      define_method(:bar) {puts "bar"}
    end
  end
end

u = User.first
u.foo
u.bar #=> "bar"

Ответ 3

Если вы пришли сюда, чтобы узнать, как динамически определять метод CLASS, потому что define_method не работал (потому что он определяет методы INSTANCE), вот ваш ответ:

Используйте define_singleton_method:)

Ответ 4

Ответ на ваш вопрос: "да, вы можете". Что касается того, почему он не работает для вас - невозможно точно сказать, почему, если вы не предоставляете какой-либо контекст для кода.