【问题标题】:add methods directly called on model添加直接在模型上调用的方法
【发布时间】:2016-02-17 09:59:15
【问题描述】:

我想实现我自己在类加载时调用的方法。

我的第一个示例来自PaperClip,其中has_attached_file 行直接写在类上,并指代周围某处的另一个植入(lib/Paperclip)。

我想实现一个方法,以便为类上的其他方法调用。我希望它看起来链接 before_filter 但在模型上。

这个想法是不必在您想要的每个方法上手动调用特定方法。只需在模型开头的一行就足够了。

我尝试使用Concern,但据我所知,我只能定义类/实例方法,包括一些依赖项等等。

我想为go_for_itdo_it_again 2 个方法调用watch_here 方法。我不想这样称呼它:

def go_for_it
  watch_here :go_for_it
  puts "Do it!"
end

def do_it_again
  watch_here :do_it_again
  puts "Do it again!"
end

private
def watch_here(name)
  puts "I'm watching on #{name}"
end

我宁愿有类似的东西:

watch_here :go_for_it, :do_it_again

感谢您的帮助!

【问题讨论】:

  • 你能给出上下文吗?这是concerns 的工作,但我需要知道你想要达到的目标
  • 我添加了一些细节。够了吗?
  • 那么你想要做的是添加一个钩子,它基本上以before_action 样式注入代码到你定义的方法中?
  • 我想做类似的事情。我没有任何代码,我给你读一读
  • 这正是我想做的,目前我无法做到。感谢您的宝贵时间!

标签: ruby-on-rails model rubygems customization


【解决方案1】:

所以我自己对此进行了测试&&进一步@max的回答(无论如何我都这么认为,但他肯定正确地指出了这一点)......


您可以使用许多资源:

经过一些简短的研究,我发现了这个问题: Ruby on Rails - passing a returned value of a method to has_attached_file. Do I get Ruby syntax wrong?

问题是您试图在声明 (has_attached_image)中使用实例方法picture_sizes_as_strings

您正在寻找与声明类有关的内容。我和你一样有这方面的经验,所以我写这篇文章是为了我自己的利益:

对于那些来自静态面向对象语言(例如 C++ 和 Java)的人来说,开放类 的概念是相当陌生的。 Ruby 有开放类是什么意思?这意味着在运行时可以更改类的定义。 Ruby 中的所有类都可以随时由用户更改。

class Talker
  def self.say(*args)
    puts "Inside self.say"
    puts "self = #{self}"
    args.each do |arg|
      method_name = ("say_" + arg.to_s).to_sym
      send :define_method, method_name do
        puts arg
      end
    end
  end
end

class MyTalker < Talker
  say :hello
end

m = MyTalker.new

m.say_hello

似乎如果您delcare该类,它将在init 中运行声明性(?) 方法。这些方法可用于填充对象的其他部分...在has_many :associations 的情况下,它将创建@parent.associations 的实例方法。

由于ActiveRecord::Concerns是模块,你需要这样对待它们(根据我找到的epic tutorial):

#app/models/concerns.rb
require 'active_support/concern'

module Helper
  extend ActiveSupport::Concern

  module ClassMethods
    def help(*args) #-> each argument represents a method
      args.each do |arg|
        method_name = ("say_" + arg.to_s).to_sym
        send :define_method, method_name do
          puts arg
        end
      end
    end
  end

end

#app/models/x.rb
class X < ActiveRecord::Base
  include Helper
  help :help
end

@x = X.new
@x.say_help #-> puts "help"

[[仍在解决剩下的]] -- 如何添加到实例方法;似乎super 不太好用

【讨论】:

  • 我认为对我帮助最大的是意识到 Ruby 中的 OO 更像 JavaScript 或 Smalltalk。 Ruby 类与 Java、C+ 甚至 PHP 中的静态石碑没有任何共同之处。类只是工厂和原型的对象。
  • 感谢你们,它几乎完成了。我现在希望在 existing 方法上注入代码。我不想创建一个新的。我的help :foo, :bar 在现有的foobar 方法上注入代码。就像那样,我确信这段代码将首先执行。
  • Hum.. 这个类由一个库(并且只有一个库)使用呢?我不能关注不是从ActiveRecord::Base 继承的类,不是吗?
  • 为此,我必须使用@max 的答案并手动调用此方法。如果此方法在库中,那可能会很棒。这样,在我的应用程序中几乎任何地方都可以轻松使用它。
  • 没有什么能阻止你在instance_evalclass_eval 中使用define_method - 你只需要注意self 是什么。
【解决方案2】:

啊,元编程的乐趣!要为类动态添加方法或行为,您可以使用 instance_evalclass_eval

请注意,这是一个相当高级的主题,您首先应该对 Ruby 中的类、模块和消息传递的工作原理有一个大致的了解!


module Magic
  def self.included(base)
    base.extend ClassMethods
  end
  module ClassMethods
    def make_awesome
      # self here is the class - so we are adding class methods
      self.instance_eval do
        def magic_class_method
          puts "I'm a metamagical class method, deal with it."
        end
        # you could call another class method such as
        # before_save :magic_instance_method
      end
      self.class_eval do
        def magic_instance_method
          puts "I'm metamagical instance method, deal with it."
        end
      end
    end
  end
end

class Test
  include Magic
  make_awesome
end

Test.magic_class_method 
# => "I'm a metamagical class method, deal with it."
Test.magic_instance_method 
# => "I'm metamagical instance method, deal with"

这有点违反直觉,但疯狂背后是有原因的:

instance_eval 中,接收者是测试类本身。请记住,类名只是一个指向类Class 的实例的常量。

class_eval是Module类的一个方法,意思是接收者是一个模块或者一个类。传递给 class_eval 的块在该类的上下文中进行评估,就像使用 class 关键字声明一个类一样。

补充阅读:

【讨论】:

  • 所以我认为您正在做的是创建一个响应类和实例级别调用的方法是正确的吗?这与调用has_attached_file 等有什么关系?
  • 那就对了!缺少的单词是meta-programming。我会更深入地看看你给我的文件。您是否有想法在通过 splat 参数传递的方法上注入代码?
  • "Ruby 类定义在运行时进行评估" -- 这就是 instance_evalclass_eval 的来源
  • @RichardPeck 是的,大多数 Rails DSL 东西,如关联、验证、回调等都是围绕与此类似的模式构建的。这就是所有“魔法”的来源:)
猜你喜欢
  • 1970-01-01
  • 2019-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多