使用ActiveRecord创建许多专辑

时间:2016-04-18 13:47:21

标签: ruby-on-rails ruby rake

这是一个搜索艺术家的佣金任务,如果它存在,它将存储艺术家专辑。我试图使用gem,但由于某种原因,宝石会返回我真正不需要的东西。如果我搜索艺术家,它的工作正常。

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我应该得到什么。

所以我决定自己编码,然后我意识到它保存了一个空模型,我的Album中的所有内容都是零。 2个问题:

1)我该如何解决?

2)如何保存所有专辑,而不只是一个?

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

1 个答案:

答案 0 :(得分: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&#39; ABBA&#39;艺术家记录)。

有关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部分。您需要在艺术家和专辑模型之间建立一对多(has_many)关联。然后你只需要遍历结果数组,为每个条目创建一个新的Album。

查看您的架构,您需要将一个整数属性添加到名为artist_id的相册模型中。您可以使用以下命令创建迁移:

rails g migration AddArtistToAlbums artist:references

magic 命令行语法应生成一个正确的迁移文件,该文件应如下所示:

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访问与相册相关联的艺术家。

在您直接深入解释回复正文之前,我可能会先检查一下我是否得到了正确的请求:

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

在处理响应之前,您需要解析JSON。在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数组。

if !album_response_json["results"].is_a?(Array)
  puts "Response JSON does not contain the expected 'results' array."
  exit
end

接下来,您正在通过索引album_response.body[0]从散列中访问键值,该值将是基于您的示例JSON的整数(23)。我认为您打算访问results数组的第一个元素。

您需要做的是迭代结果,为每张专辑创建一个新的模型对象。我注意到,在您的示例JSON响应中,有wrapperType的&#39;艺术家&#39;我认为你想过滤掉所以代码看起来像这样:

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

您现在应该按预期存储相册。

请注意。我跳过了为Album模型添加验证,但这是一个好主意。