添加直接在模型上调用的方法

时间:2016-02-17 09:59:15

标签: ruby-on-rails model rubygems customization

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

我的第一个例子来自PaperClip,其中行has_attached_file直接写在类上,并引用另一个植入(lib / Paperclip)。

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

这个想法是不必手动调用您想要的每个方法的特定方法。模型开头只需要一行即可。

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

我想针对2种方法watch_herego_for_it调用方法do_it_again。我不想这样称呼它:

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

谢谢你的帮助!

2 个答案:

答案 0 :(得分:3)

所以我自己测试了这个&&进一步回到@max的答案(无论如何我都有点想,但他肯定正确指出了......)

您可以使用许多资源:

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

  

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

您正在寻找的是与宣布课程有关。我有这么多的经验,所以我写这个是为了我自己的利益:

  

对于那些来自静态面向对象语言的人,比如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效果不佳

答案 1 :(得分: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中,接收者本身就是Test类。请记住,类名只是一个指向类Class的实例的常量。

class_eval是Module类的一种方法,意味着接收器将是一个模块或一个类。传递给class_eval的块在该类的上下文中进行计算,就像使用class关键字声明类一样。

补充阅读: