2013-07-09 2 views
2

Я ищу, чтобы создать функцию, которая работает аналогично тому, как работает ActiveRecord::Basefind_by_'column_name'. Например, если я делаю что-то вродеКак работает метод ActiveRecord :: Base «find_by_»?

User.find_by_address("1234 Apple Road")

это будет выглядеть вверх через address колонку. Но я недоумеваю, как это работает.

Я вижу как код self.prefix, так и self.suffix, когда я смотрю код для «динамических согласований» в коде, например. here, но в своем исследовании я ничего не могу найти о self.prefix или self.suffix для Ruby.

Как бы создать такую ​​функцию?

ответ

5

Он использует method_missing, который является обратным вызовом, который Ruby предоставляет при вызове метода с непризнанным именем. Это стандартный способ создания методов с динамическими именами в Ruby.

Первым аргументом, переданным ему, является Символ, представляющий имя метода, и затем получает каждый аргумент, переданный непризнанному методу.

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

Perfect. Теперь у нас есть зоопарк, полный животных. Теперь мы знаем, что все они имеют свои специфические характеристики, но мы все еще не можем их найти ... Было бы здорово, если бы мы могли искать таких животных?

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 будет улов сразу же, как это не определенно! Более того, мы даже получаем имя метода, которое было использовано. Большой! Давайте использовать это в наших интересах.

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 

Done! Полностью функциональный зоопарк, в котором мы можем искать наших животных!

Смежные вопросы