#ruby-on-rails #arrays #ruby #data-structures #null
#ruby-on-rails #массивы #ruby #структуры данных #null
Вопрос:
Я получаю данные из внешнего API в своем приложении Rails для интерфейса React. Я хотел бы очистить данные до того, как они попадут во внешний интерфейс, и попытаться получить доступ к вложенным данным в непредсказуемом ответе API. Иногда вложенные данные возвращают что-то и в других случаях nil
. Это проблема (я думаю).
Я пробовал различные способы защиты с условиями, но это, похоже, не работает.
Вот метод, с которым я работаю:
def song_details
search = HTTParty.get("https://musicbrainz.org/ws/2/release/#{params[:songId]}?inc=artist-credits artist-rels media recording-level-rels url-rels work-level-rels recording-relsamp;fmt=json", {
headers: {"User-Agent" => "Songly/ver 1.0", "Contact" => "demiansims@gmail.com"}
})
end
Если я вызываю search['relations'][0]['artist']['name']
консоль Rails, я получаю обратно красивую строку имени.
Если я попытаюсь запустить:
search['relations'].map { |r| r['artist'].each { |a| puts a['name'] }}
Я получаю no method for Nil class on []
сообщение об ошибке. Я знаю, это потому, что некоторые значения равны нулю.
Вот полная картина вложенных данных (стоит 1 итерация — их около 20):
{"end"=>nil,
"attribute-values"=>{},
"artist"=>
{"id"=>"70047e57-0153-4117-b0fc-a1d2e322e5ef",
"name"=>"Donald Fagen",
"disambiguation"=>"",
"sort-name"=>"Fagen, Donald"},
"ended"=>false,
"direction"=>"backward",
"type-id"=>"01ce32b0-d873-4baa-8025-714b45c0c754",
"begin"=>nil,
"target-type"=>"artist",
"target-credit"=>"",
"type"=>"composer",
"attributes"=>[],
"attribute-ids"=>{},
"source-credit"=>""}
Я пытаюсь получить имя, relations -> artist -> name
если даже есть «исполнитель» или «имя», и оно не равно нулю. Как мне подойти к этому? Извините, я новичок в Rails и только начинаю разбираться со структурами данных. И я предполагаю, что я прав, заботясь о данных в серверной части перед отправкой в React?
Редактировать
Приведенные ниже предложения намного ближе, но я все еще получаю ошибки при попытке обернуть данные:
def song_details
search = HTTParty.get("https://musicbrainz.org/ws/2/release/#{params[:songId]}?inc=artist-credits artist-rels media recording-level-rels url-rels work-level-rels recording-relsamp;fmt=json", {
headers: {"User-Agent" => "Songly/ver 1.0", "Contact" => "demiansims@gmail.com"}
})
search['relations'].present?
search['relations'].map do |r|
r['artist'].present?
artist = {
name: r['artist', 'name'],
role: r['type'].present? amp;amp; r['type'],
id: r['artist', 'id'],
disambiguation: r['artist', 'disambiguation'],
attributes: r['attributes'] amp;amp; r['attributes'].each { |a| a }
}
end
artist
end
Я получаю такие ошибки, как:
app/controllers/api/v1/searches_controller.rb:26:in `[]'
app/controllers/api/v1/searches_controller.rb:26:in `block in song_details'
app/controllers/api/v1/searches_controller.rb:21:in `map'
app/controllers/api/v1/searches_controller.rb:21:in `song_details'
Комментарии:
1. является ли исполнитель массивом, почему вы перебираете исполнителя
Ответ №1:
Это хороший пример, в котором вы можете использовать Hash#dig
artist_names = search['relations'].map { |r| r.dig('artist', 'name') }
Ответ №2:
Вы можете использовать метод try в rails метод try возвращает nil, если данные не существуют в объекте, обратитесь к этой ссылке для справки, если это не сработает, используйте нулевые проверки, такие как a.present?
или a.blank?
Если вы хотите проверить nil, то с предоставленным вами образцом и предполагая, что он будет в массиве, вы можете использовать
a.map { |r| r['artist'] amp;amp; r['artist']['name'] } //a is array of object you specified
Вы делаете это неправильно r[‘исполнитель’, ‘имя’] выдает ошибку
def song_details
search = HTTParty.get("https://musicbrainz.org/ws/2/release/#{params[:songId]}?inc=artist-credits artist-rels media recording-level-rels url-rels work-level-rels recording-relsamp;fmt=json", {
headers: {"User-Agent" => "Songly/ver 1.0", "Contact" => "demiansims@gmail.com"}
})
search['relations'].present?
search['relations'].map do |r|
r['artist'].present?
artist = {
name: r.dig('artist', 'name'),
role: r['type'],
id: r.dig('artist', 'id'),
disambiguation: r.dig('artist', 'disambiguation'),
attributes: r['attributes'] amp;amp; r['attributes'].each { |a| a }
}
end
artist
завершение
Комментарии:
1. Хорошо, я думаю, что оба решения, приведенные выше, становятся намного ближе. Если я запускаю только одну строку, имена отображаются просто отлично:
search['relations'].map { |r| r['artist'] amp;amp; r['artist']['name'] }
Но если я попытаюсь реализовать оболочку с необходимыми средствами защиты, напримерr['artist'].present?
, я все равно получаю ошибки.2. Можете ли вы обновить ответ с помощью обновленного кода и ошибки, которую вы получаете
3. Хорошо, да, я сделал это в ПРАВКЕ выше.
4. вы получаете
relations
объект непосредственно из ответа??? (как правило, какой бы ответ вы ни получили, это будет тело ответа, а не ответ)5. @demiansims обновил мой ответ, пожалуйста, проверьте, помогает ли это