【问题标题】:Can I define_method in rails models?我可以在 rails 模型中定义方法吗?
【发布时间】:2008-11-19 17:58:44
【问题描述】:

我的 rails 模型有代码试图在模型中 define_method(method_name)

我不断得到:

NoMethodError: undefined method `define_method'

我做错了什么?我在错误的地方这样做吗?我需要将此方法附加到此模型。我还能在哪里定义这个方法?

编辑: 对于那些要求查看代码的人:

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

【问题讨论】:

  • 您可以将模型中的代码粘贴到您正在使用的地方吗?

标签: ruby-on-rails ruby


【解决方案1】:

rails 模型并没有什么神奇之处,它只是一个普通的类,带有一堆预先存在的方法,

那么,问题是“我可以在一个类中定义_method”吗?

第 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 在类,我们在实例中,所以我们不能直接访问它。

尽管如此,我们将方法直接添加到类中,所以所有其他已经存在的 Cows 也会自动添加 speak 方法。

第 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/,祝你好运。当您意识到向实例“添加方法”实际上根本没有将其添加到实例时,它会有所帮助:-)

【讨论】:

  • “清楚地看到元类”链接今天已失效。这可能是同一篇文章:dannytatom.me/metaid。在元编程方面,这看起来也很有希望:yehudakatz.com/2009/11/15/….
  • 所有链接都失效了 :(
  • 很好的例子。解释得很好!
【解决方案2】:

如果您来这里是为了寻找如何动态定义 CLASS 方法,因为 define_method 不起作用(因为它定义了 INSTANCE 方法),这就是您的答案:

使用define_singleton_method :)

【讨论】:

  • 这个!不是一个简单的关键字搜索
【解决方案3】:

能够拼凑起来。但对实际发生的情况知之甚少。

我的实例方法 foo 正在打开类并在其上定义 bar 以便我可以在我的实例上调用它。更有经验的人会告诉我们这是否会同时打开一罐蠕虫。

不过,了解您对此的具体用途会很有用。

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"

【讨论】:

  • foo 正在打开元类。阅读我的答案链接的_why的文章,并准备弯曲你的大脑
【解决方案4】:

您的问题的答案是“是的,您可以”。至于为什么它不适合你——如果你不为代码提供一些上下文,就不可能确定为什么。

【讨论】: