Rails 5.1使用nested_attributes_for更新连接表上的属性

时间:2018-03-05 18:43:02

标签: ruby-on-rails ruby-on-rails-5.1

我的API后端有三个模型 - UserGameOwnership,它们充当用户和游戏之间的连接表。

我有一个调用远程API的服务方法来获取用户拥有的游戏数据。然后,它使用数据将相关游戏添加到数据库中,并使用额外数据(game_count)更新用户,并创建用户与其游戏之间的关系。我能够做到这一点:

class GameService
  def self.getGamesForUser(user)
    # response hash gets populated here

    games = response[:games].map do |data|
      Game.find_or_create_by(app_id: data[:appid]) do |g|
        g.name = data[:name]
        g.icon = data[:img_icon_url]
        g.logo = data[:img_logo_url]
      end
    end

    user.update games: games, game_count: response[:game_count]
  end
end

到目前为止,这么好。在更新用户时,会自动创建用户和游戏之间的所有权关联。但我还想在连接表中同时添加额外的属性(如播放时间)。我一直无法找到一个很好的解决方案。我尝试通过向游戏模型添加nested_attributes_for并调用

来查看accepts_nested_attributes_for :ownerships
g.ownerships_attributes = [{
  playtime: data[:playtime_forever]
}]

在更新用户之前,但似乎没有任何效果。我觉得必须有一个优雅的解决方案,我只是没有看到它。

以下是我的模型的代码:

User.rb

class User < ApplicationRecord
  has_many :ownerships
  has_many :games, through: :ownerships
end

Game.rb

class Game < ApplicationRecord
  has_many :ownerships
  has_many :owners, through: :ownerships, source: :user
end

Ownership.rb

class Ownership < ApplicationRecord
  belongs_to :user
  belongs_to :game
end

1 个答案:

答案 0 :(得分:0)

在迭代游戏时,将游戏时间保存在哈希中(将game.id作为键)

games = response[:games].map do |data|
  playtimes = Hash.new
  game = Game.find_or_create_by(app_id: data[:appid]) do |g|
    g.name = data[:name]
    g.icon = data[:img_icon_url]
    g.logo = data[:img_logo_url]
  end
  #This is outside the find_or_create_by because it must be done for all games, not just the newly created.
  playtimes[game.id] = data[:playtime_forever]
end

Finnaly,在更新游戏后,更新联接表中的游戏时间:

user.ownerships.find_each do |own|
  own.update_attributes(:playtime => playtimes[:own.game_id])
end