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

时间:2021-04-08 19:02:18

I'm looking to create a function that works similarly to the way ActiveRecord::Base's find_by_'column_name' works. For example, if I do something like

我希望创建一个与ActiveRecord::Base的find_by_'column_name'工作类似的函数。例如,如果我做类似的事情

User.find_by_address("1234 Apple Road")

用户。find_by_address(苹果路1234号)

it will look up via the address column. But I'm perplexed as to how it works.

它将通过address列查找。但我对它是如何运作感到困惑。

I see both self.prefix and self.suffix when I look at the code for "dynamic matchers" in the code, e.g. here, but in my research I can't find anything about self.prefix or self.suffix for Ruby.

我看到两个自我。前缀和自我。当我查看代码中“动态匹配器”的代码时,比如这里,但是在我的研究中,我找不到任何关于self的信息。前缀或自我。后缀为Ruby。

How would I create this kind of function?

如何创建这种函数?

2 个解决方案

#1


5  

It uses method_missing, which is a callback that Ruby provides when a method with an unrecognised name is called. This is the standard way to create methods with dynamic names in Ruby.

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

The first argument passed to it is a Symbol representing the name of the method, and it then receives every argument passed to the unrecognised method.

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

#2


1  

Let's say you have a zoo, a very nice zoo, with a bunch of wild animals. Of course, as a zoo keeper, you often needs to find specific animals based on their needs and characteristics. But as the zoo grow and grow, it's impossible to know in advance what will be these characteristics! Let's try to fix this...

假设你有一个动物园,一个很不错的动物园,有一群野生动物。当然,作为一个动物园管理员,你经常需要根据他们的需要和特点来寻找特定的动物。但是随着动物园的成长,不可能提前知道这些特征是什么!让我们来解决这个问题……

First, let's define what is an animal;

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

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

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

Easy enough. Now, let's build the zoo!

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

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

What is a zoo without any animals?

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

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')

Perfect. We now have a zoo full of animals. Now, we know they all have their specific characteristics, but we're still unable to find them... Wouldn't it be great to be able to search our animals like this?

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

zoo.find_animals_by_region('Africa')

But remember, we don't know in advance all these characteristics! Let's try to fix this by adding a special method to our zoo.

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

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

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

Great, we can now catch all calls to undefined methods on our zoo, which mean that find_animals_by_something will be catch right away, as it is undefined! Moreover, we even get the method_name that was used. Great! Let's use this to our advantage.

很好,我们现在可以捕获对动物园中未定义方法的所有调用,这意味着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

Here we go! We now catch only missing methods that starts with the special keyword "find_animals_by_". Let's add a little logic in there, and don't forget to call super for unwanted methods!

在这里,我们走吧!我们现在只捕捉以特殊关键字“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

Done! A fully functional zoo in which we can search our animals!

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

#1


5  

It uses method_missing, which is a callback that Ruby provides when a method with an unrecognised name is called. This is the standard way to create methods with dynamic names in Ruby.

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

The first argument passed to it is a Symbol representing the name of the method, and it then receives every argument passed to the unrecognised method.

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

#2


1  

Let's say you have a zoo, a very nice zoo, with a bunch of wild animals. Of course, as a zoo keeper, you often needs to find specific animals based on their needs and characteristics. But as the zoo grow and grow, it's impossible to know in advance what will be these characteristics! Let's try to fix this...

假设你有一个动物园,一个很不错的动物园,有一群野生动物。当然,作为一个动物园管理员,你经常需要根据他们的需要和特点来寻找特定的动物。但是随着动物园的成长,不可能提前知道这些特征是什么!让我们来解决这个问题……

First, let's define what is an animal;

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

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

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

Easy enough. Now, let's build the zoo!

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

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

What is a zoo without any animals?

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

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')

Perfect. We now have a zoo full of animals. Now, we know they all have their specific characteristics, but we're still unable to find them... Wouldn't it be great to be able to search our animals like this?

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

zoo.find_animals_by_region('Africa')

But remember, we don't know in advance all these characteristics! Let's try to fix this by adding a special method to our zoo.

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

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

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

Great, we can now catch all calls to undefined methods on our zoo, which mean that find_animals_by_something will be catch right away, as it is undefined! Moreover, we even get the method_name that was used. Great! Let's use this to our advantage.

很好,我们现在可以捕获对动物园中未定义方法的所有调用,这意味着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

Here we go! We now catch only missing methods that starts with the special keyword "find_animals_by_". Let's add a little logic in there, and don't forget to call super for unwanted methods!

在这里,我们走吧!我们现在只捕捉以特殊关键字“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

Done! A fully functional zoo in which we can search our animals!

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