You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby CLI报错:undefined method `title' for []:Array (NoMethodError)

解决你的Spotify榜单CLI工具错误&潜在问题排查

嘿,作为Ruby新手能写到这已经很棒了!咱们先把你卡了几小时的NoMethodError搞定,再一步步梳理其他隐藏问题:

1. 核心错误原因拆解

你遇到的undefined method 'title' for []:Array,本质是把数组当成单个Song对象来调用方法,具体坑点在这几个地方:

  • 在CLI#get_song里,你调用Topspotifysongs::Songs.get_song_details(input),但当前这个方法返回的是数组(collect的默认返回值),而且完全没用到传入的input参数;
  • 接着你把这个数组传给show_song_details,然后调用song.title——数组哪来的title方法?自然就报错了。

2. 分步修复代码

第一步:重构Songs类的抓取与数据逻辑

当前的Songs.get_song_details既没正确抓取数据,也没初始化Song对象,咱们拆成两个方法:一个抓全量榜单,一个根据排名找单首歌:

class Topspotifysongs::Songs
  attr_accessor :title, :artist, :rank, :streams, :spotify_url
  @@all = []

  def initialize(title=nil, artist=nil, rank=nil, streams=nil, spotify_url=nil)
    @title = title
    @artist = artist
    @rank = rank
    @streams = streams
    @spotify_url = spotify_url
    @@all << self
  end

  def self.all
    @@all
  end

  # 新增:抓取所有榜单歌曲并初始化Song对象
  def self.scrape_all_songs
    require 'nokogiri'
    require 'open-uri'
    
    begin
      doc = Nokogiri::HTML(open("https://spotifycharts.com/regional"))
      # 修正CSS选择器:定位每一行歌曲的tr元素
      doc.css("tbody tr").each do |row|
        # 提取标题:页面里标题在.chart-table-track下的strong标签
        title = row.css(".chart-table-track strong").text.strip
        # 提取歌手:去掉"by "前缀
        artist = row.css(".chart-table-track span").text.gsub("by ", "").strip
        # 提取排名并转成整数
        rank = row.css(".chart-table-position").text.strip.to_i
        # 提取播放量
        streams = row.css(".chart-table-streams").text.strip
        # 提取Spotify链接:a标签的href属性
        spotify_url = row.css(".chart-table-image a").attr("href").value.strip

        # 初始化Song对象并存入@@all
        new(title, artist, rank, streams, spotify_url)
      end
    rescue OpenURI::HTTPError, SocketError => e
      puts "⚠️  网络出错了:#{e.message}"
      exit
    end
  end

  # 修改:根据用户输入的排名返回单个Song对象
  def self.get_song_details(target_rank)
    @@all.find { |song| song.rank == target_rank }
  end
end

第二步:修正CLI类的交互逻辑

现在CLI需要先加载全量数据,再处理用户输入,还要兼容无效输入的情况:

class Topspotifysongs::CLI
  def start
    puts "正在加载Spotify全球榜单..."
    Topspotifysongs::Songs.scrape_all_songs
    puts "加载完成!请输入你想查看的歌曲排名(1-200):"
    get_song
  end

  def get_song
    input = gets.strip.to_i
    song = Topspotifysongs::Songs.get_song_details(input)

    if song
      # 歌曲存在则展示详情
      puts "------------------------------------------------------------------------"
      show_song_details(song)
      puts "------------------------------------------------------------------------"
    else
      # 处理无效排名输入
      puts "⚠️  请输入1-200之间的有效数字哦!"
    end

    # 询问是否继续查询
    puts "\nWould you like to show another song? (y/n)"
    repeat_or_done
  end

  def show_song_details(song)
    puts "----------- #{song.title} by #{song.artist} -----------"
    puts ""
    puts "Ranking: #{song.rank}"
    puts ""
    puts "Streams: #{song.streams}"
    puts ""
    puts "Link to song: #{song.spotify_url}"
    puts ""
  end

  def repeat_or_done
    input = gets.strip.downcase
    case input
    when "y"
      puts "\n请输入歌曲排名:"
      get_song
    when "n"
      puts "感谢使用!再见👋"
    else
      puts "请输入y或n哦!"
      repeat_or_done
    end
  end
end

3. 其他潜在问题排查

  1. 依赖检查:确保你已经安装了nokogiri,运行命令安装:

    gem install nokogiri
    

    (open-uri是Ruby标准库,不需要额外安装)

  2. Scraper类的冗余:你代码里提到了Topspotifysongs::Scraper但没实现,如果想把抓取逻辑拆分到单独的Scraper类,可以这么写:

    class Topspotifysongs::Scraper
      def self.scrape_chart_data
        require 'nokogiri'
        require 'open-uri'
        doc = Nokogiri::HTML(open("https://spotifycharts.com/regional"))
        doc.css("tbody tr").map do |row|
          {
            title: row.css(".chart-table-track strong").text.strip,
            artist: row.css(".chart-table-track span").text.gsub("by ", "").strip,
            rank: row.css(".chart-table-position").text.strip.to_i,
            streams: row.css(".chart-table-streams").text.strip,
            spotify_url: row.css(".chart-table-image a").attr("href").value.strip
          }
        end
      end
    end
    

    然后在Songs类的scrape_all_songs里调用:

    def self.scrape_all_songs
      Topspotifysongs::Scraper.scrape_chart_data.each do |data|
        new(data[:title], data[:artist], data[:rank], data[:streams], data[:spotify_url])
      end
    end
    
  3. 测试启动:最后在入口文件里启动CLI即可:

    Topspotifysongs::CLI.new.start
    

内容的提问来源于stack exchange,提问作者zachjohnson1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 23:17:42