Подтвердить что ты не робот

Получить определенные атрибуты из модели ActiveRecord

Скажем, что у меня есть модель User с атрибутами :id, :first_name, :last_name, and :email. В моем приложении гостевые пользователи не должны видеть User email and last_name. Я знаю, как выбрать конкретные значения, если я хочу список пользователей, но я не знаю, как я могу получить конкретные атрибуты конкретного пользователя, например

User.find_by(id: 5).select(:id, :first_name).

Одним из решений этого является пользователь

User.find_by(id: 5).attributes.slice('id', 'first_name') 

но затем я получаю хэш вместо записи AR. Я мог бы сделать

User.select(:id, :first_name).find_by(id: 1) 

но то, что я не знаю, какие фильтры я должен фильтровать, поскольку мне нужно сначала знать пользователя.

Не могли бы вы мне помочь?

4b9b3361

Ответ 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)

Ничего себе... Я пошел дальше, чем ожидалось. Надеюсь, что некоторые из них были полезны!

Ответ 2

Попробуйте следующее:

User.where(id: 5).pluck(:id, :first_name) 

он возвращает массив, содержащий значения id и first_name

Ответ 3

Это будет работать также

User.select(:id, :first_name).find(5)