Могу ли я определить метод в рельсовых моделях? - PullRequest
21 голосов
/ 19 ноября 2008

В моей модели рельсов есть код, который пытается 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

Ответы [ 4 ]

77 голосов
/ 20 ноября 2008

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

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

Часть 1: Да, можно.

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

Например:

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

Cow.new.speak
=> "MOOOO"

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

Часть 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 находится в класс, мы в экземпляре, поэтому мы не можем получить к нему прямой доступ.

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

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

Пример:

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 голосов
/ 18 ноября 2014

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

Использование define_singleton_method:)

2 голосов
/ 19 ноября 2008

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

Мой метод экземпляра 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"
1 голос
/ 19 ноября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...