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

Rails 7使用PORO处理第三方API数据时出现未知属性错误

问题描述

从NHL API获取的比赛数据结构如下:

{:gamePk=>2023010045,
 :link=>"/api/v1/game/2023010045/feed/live",
 :gameType=>"PR",
 :season=>"20232024",
 :gameDate=>"2023-09-29T00:30:00Z",
 :status=>{:abstractGameState=>"Preview", :codedGameState=>"1", :detailedState=>"Scheduled", :statusCode=>"1", :startTimeTBD=>false},
 :teams=>
  {:away=>{:leagueRecord=>{:wins=>0, :losses=>0, :type=>"league"}, :score=>0, :team=>{:id=>19, :name=>"St. Louis Blues", :link=>"/api/v1/teams/19"}},
   :home=>{:leagueRecord=>{:wins=>0, :losses=>0, :type=>"league"}, :score=>0, :team=>{:id=>16, :name=>"Chicago Blackhawks", :link=>"/api/v1/teams/16"}}},
 :venue=>{:id=>5092, :name=>"United Center", :link=>"/api/v1/venues/5092"},
 :content=>{:link=>"/api/v1/game/2023010045/content"}}

为了将数据转换为PORO,编写了以下Game类:

class Game

  attr_reader :start_time, :home_team, :away_team

  def initialize(data)
    @start_time = data[:gameDate].to_datetime.strftime("%F")
    @home_team = data[:teams][:home][:team][:name]
    @away_team = data[:teams][:away][:team][:name]
  end
end

但执行Game.new(game)时,会抛出以下错误之一:

eval error: unknown attribute 'gamePk' for Game.

或

ActiveModel::UnknownAttributeError (unknown attribute 'gamePk' for Game.

错误回溯信息:

eval error: unknown attribute 'gamePk' for Game.

          raise UnknownAttributeError.new(self, k.to_s)
          ^^^^^
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activemodel-7.0.7/lib/active_model/attribute_assignment.rb:51:in `_assign_attribute'
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activerecord-7.0.7/lib/active_record/attribute_assignment.rb:21:in `block in _assign_attributes'
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activerecord-7.0.7/lib/active_record/attribute_assignment.rb:13:in `each'
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activerecord-7.0.7/lib/active_record/attribute_assignment.rb:13:in `_assign_attributes'
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activemodel-7.0.7/lib/active_model/attribute_assignment.rb:34:in `assign_attributes'
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activerecord-7.0.7/lib/active_record/core.rb:468:in `initialize'
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activerecord-7.0.7/lib/active_record/inheritance.rb:75:in `new'
  /Users/jrbobbdobbs/.rbenv/versions/3.1.4/lib/ruby/gems/3.1.0/gems/activerecord-7.0.7/lib/active_record/inheritance.rb:75:in `new'
  (rdbg)//Users/jrbobbdobbs/Documents/projects/sites/hockey/ChicagoBlackhawks/app/facades/game_facade.rb:1:in `block in create_games'

核心疑问:为何Game类未引用:gamePk字段,Rails仍会抛出该字段的未知属性错误?

原因分析

你的Game类被Rails识别成了ActiveRecord模型类,导致调用Game.new(game)时,实际执行的是ActiveRecord的初始化逻辑,而非你自定义的initialize方法。

从错误回溯的调用链可以看到,代码走到了active_record/core.rb的initialize方法,而非你编写的初始化逻辑。触发这个问题的常见场景:

  • Game类存放在app/models目录下,Rails默认会自动让该目录下的类继承ActiveRecord::Base(即使你没显式写继承代码)
  • 你不小心让Game类继承了ActiveRecord::Base,触发了ActiveRecord的属性赋值机制——它会尝试将传入哈希中的所有键(包括:gamePk)作为模型属性赋值,但你的类并未定义这些属性,因此抛出错误。
解决方案

提供三种可行的解决方式:

  1. 确保类为纯Ruby对象
    显式定义不继承任何ActiveRecord相关类的纯Ruby类,避免Rails自动添加模型特性:

    class Game
      attr_reader :start_time, :home_team, :away_team
    
      def initialize(data)
        @start_time = data[:gameDate].to_datetime.strftime("%F")
        @home_team = data[:teams][:home][:team][:name]
        @away_team = data[:teams][:away][:team][:name]
      end
    end
    
  2. 调整类的存放目录
    如果Game类当前在app/models目录下,将其移到非模型目录,比如app/poros、app/services等,Rails不会为这些目录下的类自动添加ActiveRecord继承。

  3. 标记为抽象类(需留在models目录时)
    如果必须将Game类放在app/models目录,可将其标记为抽象类,阻止ActiveRecord的属性赋值逻辑:

    class Game < ActiveRecord::Base
      self.abstract_class = true
    
      attr_reader :start_time, :home_team, :away_team
    
      def initialize(data)
        @start_time = data[:gameDate].to_datetime.strftime("%F")
        @home_team = data[:teams][:home][:team][:name]
        @away_team = data[:teams][:away][:team][:name]
      end
    end
    

内容的提问来源于stack exchange,提问作者J.R. Bob Dobbs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:22:12