Как цепочка Rails ActiveRecord «где» содержит без нескольких запросов?

Я разработчик PHP, изучающий способность Ruby on Rails, я люблю ActiveRecord, и я заметил что-то действительно интересное. Именно поэтому методы ActiveRecord определяют конец цепочки методов для выполнения запроса.

@person = Person.where(name: 'Jason').where(age: 26) # In my humble imagination I'd think that each where() executes a database query # But in reality, it doesn't until the last method in the chain 

Как это колдовство работает?

Метод where возвращает объект ActiveRecord::Relation и сам по себе этот объект не выдает запрос базы данных. Это важно, когда вы используете этот объект.

В консоли вы, вероятно, будете это делать:

 @person = Person.where(name: "Jason") 

И затем blammo выдает запрос на базу данных и возвращает то, что кажется массивом всех по имени Jason. Yay, Активная запись!

Но тогда вы делаете что-то вроде этого:

 @person = Person.where(name: "Jason").where(age: 26) 

И затем это вызывает другой запрос, но это для людей, которых зовут Джейсон, которым 26 лет. Но он выдает только один запрос, итак, куда идет другой запрос?


Как и другие, это происходит, потому что метод where возвращает прокси-объект. Он фактически не выполняет запрос и не возвращает dataset, если только этого не попросят сделать это.

Когда вы запускаете что-либо в консоли, оно выводит проверенную версию результата того, что вы запустили. Если вы положите 1 на консоль и нажмите enter, вы получите 1 назад, потому что 1.inspect равен 1 . Магия! То же самое касается "1" . У множества других объектов нет метода inspect поэтому Ruby возвращается к Object который возвращает что-то ужасное, как .

Каждый объект ActiveRecord::Relation имеет метод inspect определенный на нем, чтобы он вызывал запрос. Когда вы пишете запрос в своей консоли, IRB будет вызывать inspect возвращаемого значения из этого запроса и выводить что-то почти читаемое человеком, например, массив, который вы увидите.


Если вы просто выдали это в стандартном скрипте Ruby, то запрос не будет выполняться до тех пор, пока объект не будет проверен (через inspect ) или не будет повторен с использованием each или не будет to_a метод to_a .

До тех пор, пока не произойдет одно из этих трех событий, вы можете связать столько операторов, сколько хотите, а затем, когда вы to_a inspect , to_a или each из них, он, наконец, выполнит этот запрос.

Существует ряд методов, которые называются «кикерами», которые фактически запускают запрос в базу данных. До этого они просто создают узлы AST, которые когда-то пинали, будут генерировать фактический SQL (или язык, скомпилированный для) и запускать запрос.

См. Это сообщение в блоге для более глубокого объяснения того, как это делается.

Вы можете прочитать код, но одна концепция здесь – прокси-шаблон.

Вероятно, @person не является реальным объектом, а прокси-сервером для этого объекта, и когда вам нужен какой-то атрибут, активная запись, наконец, выполняет запрос. Hibernate имеет ту же концепцию.

Может быть, слишком поздно, но вы можете использовать hash:

 @person = Person.where({name: "Jason", age: 26}) 

Результирующий запрос:

 SELECT "person".* FROM "person" WHERE "person"."name" = 'Jason' AND "person"."age" = 26 
Interesting Posts

Как позвонить в список контактов Android И выбрать один номер телефона со своего экрана сведений?

Поддерживает ли веб-представление на Android поддержку SSL?

Добавление локальных файлов .aar в мою структуру gradleиента

Ярлык клавиатуры для правого клика в Mac OS X

Isoweek в SQL Server 2005

Как упрощенная инструкция оператора работает для массивов и как получить iterator для массива?

Вызовите функции Go из C

Включение драйвера AMD Catalyst в Windows 8 приводит к отключению дисплея ноутбука

Как обновить с PHP v5.4 до PHP v5.5 в bitnami ubuntu

Как установить gcj на Linux?

Как открыть консоль2 (или любой другой exe) через панель местоположения проводника

Bash – как вы делаете это так, чтобы результат команды попадал в переменную?

Как изменить реализацию (обход) функции, объявленной извне

предупреждение: небезопасный доступ к миру dir / usr / local / bin в PATH, режим 040777

Как отключить «прыжок» якоря при загрузке страницы?

Давайте будем гением компьютера.