ActiveRecord :: Base“find_by_”方法如何工作?

时间:2013-07-09 20:47:02

标签: ruby activerecord

我希望创建一个与ActiveRecord::Base的{​​{1}}工作方式类似的功能。例如,如果我做了类似

的事情

find_by_'column_name'

它将通过User.find_by_address("1234 Apple Road")列进行查找。但我对它是如何工作感到困惑。

当我查看代码中“动态匹配器”的代码时,我看到了addressself.prefix,例如here,但在我的研究中,我找不到关于Ruby的self.suffixself.prefix的任何内容。

我如何创建这种功能?

2 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分: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

完成!一个功能齐全的动物园,我们可以搜索我们的动物!