2013-07-09 38 views
2

我正在创建一个功能,其工作方式与ActiveRecord::Basefind_by_'column_name'工作方式类似。例如,如果我这样做ActiveRecord :: Base“find_by_”方法如何工作?

User.find_by_address("1234 Apple Road")

它会查找通过address列。但我很困惑它是如何工作的。

当我查看代码中“动态匹配器”的代码时,我看到self.prefixself.suffix,例如, here,但在我的研究中,我找不到任何关于用于Ruby的self.prefixself.suffix

我该如何创建这种功能?

回答

5

它使用method_missing,这是一个回调,当一个名字不可识别的方法被调用时,Ruby提供了回调。这是在Ruby中使用动态名称创建方法的标准方法。

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

1

比方说,你有一个动物园,一个非常漂亮的动物园,一群野生动物。当然,作为动物园饲养员,你经常需要根据他们的需求和特点找到特定的动物。但随着动物园的成长和壮大,事先不可能知道这些特征是什么!让我们试着解决这个问题...

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

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

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

够简单。现在,我们来建造动物园!

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

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

​​

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

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 

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

相关问题