Ответ 1
То, что сказал Choco, будет работать, если вы хотите, чтобы массив не являлся активным экземпляром записи. Если вы хотите использовать активный экземпляр записи, выполните следующие действия:
User.where(id: 5).select(:id, :first_name).take
Вот еще информация. Я не уверен, насколько вы это делаете/не знаете, поэтому я предполагаю, что вы знаете меньше, чем больше.
Я предполагаю, что вы понимаете, что вы делаете выше, это цепочка методов - то есть вы вызываете метод, а затем вызываете другой метод по результату первого метода. Например:
User.find_by(id: 5).attributes.slice('id', 'first_name')
Вы вызываете метод find_by_id
в классе User
. Этот метод вернет экземпляр класса User
(т.е. Активный экземпляр записи). У этого экземпляра есть метод под названием attributes
, который вы вызываете. Метод attributes
возвращает экземпляр класса Hash
, представляющий поля в предыдущем экземпляре активной записи. Hash
имеет метод slice
, который вы вызываете по очереди. Метод slice
возвращает другой экземпляр Hash
, содержащий подмножество указанных вами полей.
Итак, концепция, которая должна быть понятна, заключается в том, что когда вы используете методы цепочки, вы не вызываете каждый последующий метод на одно и то же - вы вызываете его на возвращаемое значение предыдущего метода в цепочке.
ОК, поэтому с этим:
Все методы find
предназначены для запроса базы данных и возврата одного экземпляра модели Active Record или простого массива ruby, содержащего несколько экземпляров моделей Active Record.
Множество других методов - select
, where
и т.д. НЕ удаляйте базу данных сразу и НЕ должны возвращать активный экземпляр записи. Все они возвращают экземпляр ActiveRecord::Relation
. ActiveRecord::Relation
похож на потенциальную группу записей, соответствующих определенным условиям, и вы можете добавить к ней дополнительные условия. Это похоже на "запрос базы данных, ожидающий того, чтобы произойти", или "запрос базы данных, который может или, возможно, еще не был".
Когда вы вызываете метод типа where
, order
или select
на ActiveRecord::Relation
, он возвращает экземпляр ActiveRecord::Relation
, то есть вы имеете экземпляр того же класса и можете цепные методы из этого класса, например: User.where(name: 'Fred').select(:id, :name).order('name ASC')
Ваш экземпляр ActiveRecord::Relation
будет очень умным и не будет беспокоить попадание в базу данных до тех пор, пока вы не вызовете метод, который явно указывает, что вам нужны записи сейчас - например, each
, all
, take
, и др.
Итак, я пошел дальше дольше, чем планировалось здесь, поэтому я завершу. Здесь код, который я впервые упомянул, с разбитым, сильно прокомментированным объяснением ниже:
User.where(id: 5).select(:id, :first_name).take
сломать его:
my_relation = User.where(id: 5)
# The database will not have been hit yet - my_relation
# is a query waiting to happen
my_second_relation = my_relation.select(:id, :first_name)
# The database has STILL not been hit.
# the relation now contains both the conditions
# from the previous my_relation, and the new 'select'
# criteria we specified
my_user = my_second_relation.take
# OK, 'take' means we want the first record
# matching all our criteria,
# so my_second_relation will hit the database
# to get it, and then return an Active Record
# instance (ie, an instance of the User class)
Ничего себе... Я пошел дальше, чем ожидалось. Надеюсь, что некоторые из них были полезны!