2

我希望创建一个与 wayActiveRecord::Basefind_by_'column_name'工作方式类似的函数。例如,如果我做类似的事情

User.find_by_address("1234 Apple Road")

它将通过address列查找。但我对它的工作原理感到困惑。

当我在代码中查看“动态匹配器”的代码时,我都看到了self.prefix,例如这里,但在我的研究中,我找不到任何关于Ruby或Ruby 的东西。self.suffixself.prefixself.suffix

我将如何创建这种功能?

4

2 回答 2

5

它使用method_missing,这是 Ruby 在调用具有无法识别名称的方法时提供的回调。这是在 Ruby 中创建具有动态名称的方法的标准方法。

传递给它的第一个参数是一个表示方法名称的符号,然后它接收传递给无法识别的方法的每个参数。

于 2013-07-09T20:49:48.260 回答
1

假设你有一个动物园,一个非常漂亮的动物园,里面有一群野生动物。当然,作为动物园管理员,你经常需要根据它们的需求和特点来寻找特定的动物。但随着动物园的发展壮大,不可能提前知道这些特征会是什么!让我们尝试解决这个问题...

首先,让我们定义什么是动物;

class Animal
  def initialize(attributes)
    @attributes = attributes
  end

  def [](value)
    @attributes[value]
  end
end

很容易。现在,让我们建造动物园吧!

class Zoo
  def animals
    @animals ||= []
  end
end

什么是没有动物的动物园?

zoo = Zoo.new

zoo.animals << Animal.new(type: "Mighty Giraffe", legs: 4, region: 'Africa')
zoo.animals << Animal.new(type: "Fierce Pidgin", legs: 2, region: 'America')
zoo.animals << Animal.new(type: "Wild Boar", legs: 4, region: 'Africa')

完美的。我们现在有一个满是动物的动物园。现在,我们知道它们都有其特定的特征,但我们仍然无法找到它们……能够像这样搜索我们的动物不是很好吗?

zoo.find_animals_by_region('Africa')

但请记住,我们事先并不知道所有这些特征!让我们尝试通过向我们的动物园添加一个特殊方法来解决这个问题。

class Zoo
  def animals
    @@animals ||= []
  end

  def method_missing(method_name, *args, &block)
    # stuff here
  end
end

太好了,我们现在可以在我们的动物园中捕获对未定义方法的所有调用,这意味着 find_animals_by_something 将立即被捕获,因为它是未定义的!此外,我们甚至得到了使用的 method_name。伟大的!让我们利用这个优势。

class Zoo
  def animals
    @@animals ||= []
  end

  def method_missing(method_name, *args, &block)
    if method_name.to_s.start_with?('find_animals_by_')
      # here we go!
    end
  end
end

开始了!我们现在只捕获以特殊关键字“find_animals_by_”开头的缺失方法。让我们在其中添加一些逻辑,不要忘记为不需要的方法调用 super!

class Zoo
  def animals
    @@animals ||= []
  end

  def method_missing(method_name, *args, &block)
    if method_name.to_s.start_with?('find_animals_by_')
      find_animals_by_attribute(method_name[16..-1], args[0])
    else
      super(method_name, *args, &block)
    end
  end

  def find_animals_by_attribute(attribute, value)
    animals.select{ |animal| animal[attribute.to_sym] == value }
  end
end

完毕!一个功能齐全的动物园,我们可以在其中搜索我们的动物!

于 2013-07-09T23:27:33.050 回答