«Вырвать», но для одной извлеченной записи?

#ruby-on-rails #ruby

#ruby-on-rails #ruby

Вопрос:

У меня есть объект записи:

 2.7.0 :005 > o = OauthUser.first
  OauthUser Load (0.5ms)  SELECT "oauth_users".* FROM "oauth_users" ORDER BY "oauth_users"."id" ASC LIMIT $1  [["LIMIT", 1]]
2.7.0 :006 > o
 => #<OauthUser id: 1, name: "Person Name", email: "person@email.com", oauth_id: "111111111111111", oauth_provider: "google", oauth_token: "blahblahblah...", oauth_refresh_token: nil, oauth_expires_at: "2020-11-13 18:22:24", sync_emails: nil, last_email_sync: nil, manual_query: nil, created_at: "2020-11-13 17:22:25", updated_at: "2020-11-13 17:22:25"> 
  

Быстрым, грязным способом я просто добавляю это в представление с .to_json помощью вызова, чтобы я мог видеть различные атрибуты на экране.
Но я хочу удалить несколько атрибутов, которые я не хочу отображать или не должен отображать по соображениям безопасности.

Я думал, что мог бы просто написать такой метод:

 # app/models/oauth_user.rb
def details
  # don't show sensitive tokens, only show fields I care to see
  pluck(:id, :oauth_id, :oauth_expires_at, :sync_emails, :last_email_sync, :manual_query)
end
  

Но pluck для запросов.

Я знаю, что мог бы вручную что-то сделать в представлении или создать хэш в модели, но я думаю, что уже есть метод для того, что мне нужно, просто не найдя его в Google.

У меня уже есть одна запись, не нужно запрашивать с pluck помощью или select ; или map результатов.

Есть ли простой способ внести в белый список или черный список атрибуты, которые я хочу отобразить для одной записи?

Я пробовал pluck , select , map и tap безрезультатно.

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

1. о чем .to_json(only: %w[id oauth_id]) ? Или .to_json(except: [...])

2. Вау. Я не думал мутировать JSON, и я не знал, что вы можете сделать only и except на них. Спасибо! Если вы хотите опубликовать это в качестве ответа, я приму это и дам вам эти приятные, приятные моменты.

3. Вы также можете использовать attributes.values_at(:id, :oauth_id, :etc) для получения массива, подобного pluck gives

4. Гениально! @maxpleaner, спасибо!!

Ответ №1:

Похоже, что существует приличное количество вариантов, но, вообще говоря, то, о чем вы говорите, — это шаблон presenter.

Если бы вы хотели Hash получить из своей модели, это было бы просто:

 def details
  attributes.slice('id', 'oauth_id', 'oauth_expires_at', 
                   'sync_emails', 'last_email_sync', 'manual_query') 
end 
  

Если вам нужен более формальный объект, то здесь появляется presenter (для этого есть много библиотек, но мы просто напишем нашу собственную ради этого вопроса)

 class OauthUserPresenter
  WHITELIST = %w(id oauth_id oauth_expires_at sync_emails last_email_sync manual_query)
  WHITELIST.each {|attr| define_method(attr) {@_exposed_attributes[attr]}}

  def initialize(user) 
     @_exposed_attributes = user.attributes.slice(WHITELIST)
  end 

  def to_hash #this will allow for #as_json and #to_json 
    @_exposed_attributes
  end

end 
  

Затем вы можете вызвать как

 o = OauthUserPresenter.new(OauthUser.first)
  

технически o это объект presenter только для чтения. Ни один из других атрибутов не будет раскрыт, и вы по-прежнему можете получить доступ к методам как id , oauth_id , и т.д.

Презентаторы также позволяют добавлять другие методы, не загромождая модель, например

 class OauthUserPresenter
   def expired? 
     begin
       Time.parse(oauth_expires_at) <= Time.now
     rescue TypeError, ArgumentError #handle nil, empty string, and invalid times
       true
     end
   end 
end 
  

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

1. В этом случае хэш полностью в порядке, но я действительно ценю обзор докладчика. Кое-что, о чем я начал слышать, но еще не проверил. Спасибо!