2016-04-18 10 views
1

アーティストを検索するレーキタスクです。存在する場合は、アーティストのアルバムとともに保存します。私はgemを使用しようとしましたが、何らかの理由で宝石が本当に必要としないものを返します。私がアーティストを検索すると、それはうまく動作します。ActiveRecordを使用して多数のアルバムを作成する

result = ITunesSearchAPI.lookup(:id => 372976 , :entity => 'album') 

これを返します。

{"wrapperType"=>"artist", "artistType"=>"Artist", "artistName"=>"ABBA", "artistLinkUrl"=>"https://itunes.apple.com/us/artist/abba/id372976?uo=4", "artistId"=>372976, "amgArtistId"=>3492, "primaryGenreName"=>"Pop", "primaryGenreId"=>14} 

を私はまったく必要とするものではありませんています。 Here's私は何をすべきですか?

私はそれを自分自身でコーディングすることに決めました。そして空のモデルを保存することに気付きました。私のアルバムのすべては無しです。 2つの質問:

1)どうすれば修正できますか?

2)どうすれば1つではなくすべてのアルバムを保存できますか?

require 'net/http' 

    task :artist,[""] => :environment do |t, args| 
    result = ITunesSearchAPI.search(:term => args.to_s, :entity => 'musicArtist') 
    if result.empty? then puts "Nothing was found. Try another artist." 
     puts result 
    elsif result 
     uniqueness = Artist.find_by(itunes_id: result[0]["artistId"]) 
     if uniqueness.nil? 
     Artist.create(name: result[0]["artistName"], itunes_id: result[0]["artistId"]) 
     puts result 
     else 
     puts "The artist already exists in database" 
     end 
    end 
    if uniqueness.nil? 
    album = URI('https://itunes.apple.com/lookup') 
    album_params = { :id => result[0]['artistId'], :entity => 'album'} 
    album.query = URI.encode_www_form(album_params) 
    album_response = Net::HTTP.get_response(album) 
    puts album_response.body 
    Album.create!(name: album_response.body[0]["collectionName"], artwork_url_100: album_response.body[0]["artworkUrl100"]) 
    end 
end 

スキーマ:

ActiveRecord::Schema.define(version: 20160418120725) do 

    create_table "albums", force: true do |t| 
    t.string "name" 
    t.string "artwork_url_100" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "artists", force: true do |t| 
    t.string "name" 
    t.integer "itunes_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    add_index "artists", ["itunes_id"], name: "index_artists_on_itunes_id", unique: true 

end 
+0

「Album」のスキーマとモデルコードを投稿できますか? –

+0

@AnthonyE確かに、投稿を更新しました。アルバムはbelongs_to:artist これはそれです。 – r0uder

答えて

1

回答パート1には、おそらく、独自性と存在のために、いくつかのモデルの検証を追加する必要があります。あなたのartist.rbファイル:

class Artist < ActiveRecord::Base 
    ... 
    validates :itunes_id, presence: true, uniqueness: true 
    validates :name, presence: true, uniqueness: true 
    ... 
end 

これは、あなたのモデルが無効な状態で保存されないようにする必要があります。 itunes_idnameの各属性は、存在していなくてもかまいません(2つの 'ABBA'アーティストレコードを持つことはできません)。

ActiveRecordの検証の詳細を

はで見つけることができます:あなたは、あなたのコードは、既存のレコードを、それらを簡素化することができ、更新をチェックするための場所であなたの検証ルールを持ってたら http://guides.rubyonrails.org/active_record_validations.html

へ:

artist = Artist.where(itunes_id: result[0]["artistId"]).first_or_initialize 
artist.name = result[0]["artistName"] 
artist.save 

その後、我々は、データベースに永続化からレコードを防ぐ任意のエラーをチェックするために得る:

if artist.errors.any? 
    puts "There were errors preventing the artist being saved:" 
    artist.errors.full_messages.each do |message| 
    puts " - #{message}" 
    end 
    puts "Result data: #{result}" 
    exit 
end 

このブロックを過ぎると(終了していない)、私たちのartistオブジェクトが有効で永続化されたモデルオブジェクトであることがわかります。

パート2への回答アーティストとアルバムモデルの間に1対多(has_many)の関連付けが必要です。結果の配列を繰り返して、各エントリの新しいアルバムを作成するだけです。

スキーマを確認するには、artist_idというアルバムモデルに整数属性を追加する必要があります。あなたはコマンドを使用して、マイグレーションを作成することができます。

rails g migration AddArtistToAlbums artist:references 

魔法コマンドライン構文は次のようになります正しい移行ファイルを生成する必要があります:

class AddArtistToAlbums < ActiveRecord::Migration 
    def change 
    add_reference :albums, :artist, index: true, foreign_key: true 
    end 
end 

データベースを更新するためにrake db:migrateを実行しますスキーマ

あなたartist.rbモデルファイルでは、あなたが今、次を追加することができます。

class Artist < ActiveRecord::Base 
    ... 
    has_many :albums 
    ... 
end 

あなたはそれの関連属性albumsを通じてアーティストに関連したアルバムを今すぐアクセスすることができます。

あなたは今、次を追加することができ、あなたのalbum.rbモデルファイルでは:

class Album < ActiveRecord::Base 
    ... 
    belongs_to :artist 
    ... 
end 

あなたは今、それが関連属性artistだを通じて、アルバムに関連したアーティストにアクセスすることができます。あなたはJSONを解析する必要が応答に対処できるようにするには

if !album_response.is_a?(Net::HTTPOK) 
    puts "There was an error fetching albums." 
    exit 
end 

:あなたがまっすぐに応答の本体を解釈するに飛び込む前に

私はおそらく私が最初の要求の正しい種類を得たかどうかをチェックします。 require 'json'でのファイルの先頭に、その後album_response.bodyなどを解析する:私も期待通りに体が移植されていることを確認するためにチェックしたいその後

album_response_json = JSON.parse(album_response.body) 

を。

if !album_response_json.is_a?(Hash) 
    puts "Response JSON is not a Hash as expected." 
    exit 
end 

また、応答ハッシュが予想されるresultsの配列であることを確認することもできます。

次に、あなたはあなたの例JSONに基づく整数(23)になり、インデックスalbum_response.body[0]によってハッシュからキーの値にアクセスしていました。私はあなたがresults配列の最初の要素にアクセスすることを意味すると思う。

あなたがする必要があるのは、結果を繰り返して各アルバムの新しいモデルオブジェクトを作成することです。予想通りになりましたアルバムが保存されている必要があり

album_response_json["results"].each do |album_hash| 
    next if album_hash["wrapperType"] == "artist" 
    artist.albums.create!(name: album_hash["collectionName"], artwork_url_100: album_hash["artworkUrl100"]) 
end 

:私はあなたの例JSON応答で、私はあなたがそうコードは次のようになりますフィルタリングしたいと推定「アーティスト」のwrapperTypeがあることに気づい。

注。過去にアルバムモデルにバリデーションを追加するのはやめましたが、それは良い考えです。

+0

このような偉大な答えをありがとうございます。 "NoMethodError:未定義のメソッド" each "for" results ":String" 結果がどこに得られるかわからないようです。 – r0uder

+0

申し訳ありませんが、私はスキップして、応答本文の解析に関する詳細を渡しました。レスポンスボディをJSONとして解析する方法を示すために答えを更新しました。あなたが持っているエラーは本当に大きな文字列であるレスポンスボディにあり、文字列オブジェクトには 'each'メソッドがありません!これが今あなたのために働くことを願っています。 –

+0

ありがとう、あなたは私の一日をした:]。私はあなたをアップアップすることができればいいが、私は十分な評判を得るとすぐにそれをやるだろう。 – r0uder

関連する問題