Разница Rails в объекте, созданном с помощью методов .find (: id) и .where()

#ruby-on-rails

#ruby-on-rails

Вопрос:

В чем разница в объектах, созданных с помощью этих двух методов:

 tec = Technique.find(6)
tec2 = Technique.where(:korean => 'Jok Sul')
  

Данные, возвращаемые для каждого из них, абсолютно одинаковы, однако первый объект будет идеально реагировать на унаследованный метод, такой как update_attributes, в то время как второй объект выдаст ошибку «метод не найден».

Когда я делаю tec.class и tec2.class один из них — ActiveRecord:: Relationship, а другой вообще не дает мне класс, он просто выводит содержимое объекта.

Возможно, когда вы используете метод .where, вы получаете массив, даже если есть только одно совпадение, и поэтому вам всегда приходится выдавать .каждый метод для получения содержимого? Но это затрудняет работу, когда вы хотите обновить записи и т.д.

Может кто-нибудь прояснить это для меня? В частности, как работать с совпадениями, найденными с помощью метода .where.

Спасибо.

Ответ №1:

Попробуйте:

 tec2 = Technique.where(:korean => 'Jok Sul').first
  

Комментарии:

1. Отлично, я никогда об этом не думал. На самом деле это возвращает только один элемент и будет реагировать на те же методы, что и .find. Спасибо.

Ответ №2:

Хороший вопрос.

 tec_scope = Technique.where(:korean => 'Jok Sul') # create an internal query
  

Помните, здесь создается только запрос, он не выполняется. Вы можете программно построить поверх этого запроса, если пожелаете. Область видимости (или запрос, если вы того пожелаете) будет выполнена двумя способами. «Неявный» или «Явный». Неявный способ выполнения запроса происходит, например, в консоли, которая вызывает метод в области видимости, который автоматически запускает запрос для вас. Этого не произойдет в ваших контроллерах, если вы не запустите его явно для .например

 tec_scope.all # returns array
tec_scope.first # retuns one element
  

Области видимости просто добавляют предложения / предикаты where к вашему запросу. Это построение запроса и задержка выполнения до тех пор, пока это не понадобится.

Однако,

 tec_objects = Technique.find(6) # explicitly runs a query and returns one object (in this case)
  

Это приведет к явному запуску запроса тут же. Это вопрос времени выполнения запроса.

Разница небольшая, но очень важная.

Это не имеет никакого отношения к тому, получаете ли вы один результат или массив.

 Technique.find([4,5]) # will return an array
Technique.find(4) # will return one object
Technique.where(:some_key => "some value").all # will return an array
Technique.where(:id => 5).first # will return one object
  

Разница заключается во времени выполнения запроса. Не позволяйте консоли обмануть вас, заставив поверить, что разницы нет. Консоль неявно запускает запрос для вас 🙂

Комментарии:

1. @kakubei я думал, ты хочешь знать разницу между where и find. Не понял, что вы просто хотели узнать о where (условии).first 🙂

2. @aditya Я хотел оба, так что теперь я доволен, ваше объяснение очень хорошее, и .first отлично работает.

Ответ №3:

find(6) Возвращает один объект, потому что вы указываете идентификатор объекта в базе данных, который гарантированно будет уникальным по соглашению.

where Вызов возвращает коллекцию, которая может содержать всего 1 элемент, но он все равно возвращает коллекцию, а не отдельный объект.

Вы можете выявить это различие. Используя ваш пример кода, если вы вызываете tec.class против tec2.class Я думаю, вы обнаружите, что они не относятся к одному и тому же классу объектов, как вы ожидаете.

То есть методы, доступные для коллекции объектов, отличаются от методов, доступных в экземпляре этого объекта.

Комментарии:

1. На самом деле, метод where возвращает ActiveRelation, а не коллекцию

2. Спасибо за объяснение, я отмечаю приведенное ниже в качестве ответа, потому что оно на самом деле иллюстрирует, как с этим справиться, чтобы я мог использовать те же методы, что и .find()