1

根据我对 Ruby on Rails 和 ActiveRecord 的理解,当参数查找 ID 时,我可以使用 ActiveRecord 模型本身而不是其 ID。例如,如果我有一个Foo模型,belongs_to一个Bar模型,那么我可以写bar = Bar.new(foo_id: foo)而不是bar = Bar.new(foo_id: foo.id). 但是,在我现在制作的模型中(用于围棋游戏应用程序),情况似乎并非如此。

以下是模型中的相关代码:

class User < ActiveRecord::Base
  .
  .
  .
  has_many :participations, dependent: :destroy
  has_many :games, through: :participations
end

class Game < ActiveRecord::Base
  attr_accessible :height, :width

  has_many  :participations, dependent: :destroy
  has_many  :users, through: :participations

  def black_player
    self.users.joins(:participations).where("participations.color = ?", false).first
  end

  def white_player
    self.users.joins(:participations).where("participations.color = ?", true).first
  end
end

class Participation < ActiveRecord::Base
  attr_accessible :game_id, :user_id, :color

  belongs_to :game
  belongs_to :user

  validates_uniqueness_of :color, scope: :game_id
  validates_uniqueness_of :user_id, scope: :game_id
end

(颜色是一个布尔值,其中 false=black,true=white)

如果我创建了两个Users( black_playerid=1) 和white_player(id=2) 和 a Game game,我可以这样做:

game.participations.create(user_id: black_player, color: false)

并且game.participationsblack_player.participations显示了这个新的Participation

=> #<Participation id: 1, game_id: 1, user_id: 1, color: false, created_at: "2012-10-10 20:07:23", updated_at: "2012-10-10 20:07:23">

但是,如果我再尝试:

game.participations.create(user_id: white_player, color: true)

那么新的Participation有一个user_id1(black_player 的 id)。当我在同一个游戏中针对重复玩家进行验证时,这不是有效的Participation并且不会添加到数据库中:

=> #<Participation id: nil, game_id: 1, user_id: 1, color: true, created_at: nil, updated_at: nil> 

但是,如果我这样做:

game.participations.create(user_id: white_player.id, color: true)

然后它确实有效:

=> #<Participation id: 2, game_id: 1, user_id: 2, color: true, created_at: "2012-10-10 20:34:03", updated_at: "2012-10-10 20:34:03"> 

这种行为的原因是什么?

4

2 回答 2

2

似乎任何直接传递给 :belongs_to 子对象的父对象都被转换为布尔值,因此导致 id 为 1。解决方案之一是先启动对象,然后在保存之前直接设置父对象:

@participation = Participation.new
@participation.game = @game
@participation.user = @user
@participation.color = false
@participation.save

其他方法是传递 ID 而不是对象,就像你现在做的那样。

编辑:情况并非如此,留下信息:

尝试使用user而不是user_id

game.participations.create(user: white_player, color: true)

我认为可能发生的事情是它试图从您的用户对象中得出一个整数,因为您明确指定了列名而不是关系。"#<User:0x107f8a2f2584e0>"然后变为 1 或它在字符串中找到的任何第一个有效数字,您可以尝试它User.find(2).to_s.to_i应该在您的情况下返回 1。

于 2012-10-10T20:58:10.913 回答
0

ActiveRecord 将为您处理关联。但是,我可以从上面的代码中解决 2 个问题。首先,您正在尝试将对象“用户”分配给属性“用户 ID”。其次,对于 Participation 类的实例,该“用户”不可用于 mass_assignment。通过将哈希传递给创建调用来为对象分配属性,称为“mass_assignment”,黑客可以使用它来分配您可能也不想要的属性。出于这个原因,rails 提供了“attr_accessible”方法。您必须明确声明允许用户在“mass_assignment”期间设置的属性,方法是将它们作为符号传递给类定义中的“attr_accessible”方法。

attr_accessible :game, :user, :color

现在你可以

game.participations.create(:user => my_player_object)

请注意,如果您仍想在某些情况下分配“Id”,则还必须将其传递给 attr_accessible

attr_accessible :game, :user, :color, :game_id, :user_id
于 2012-10-11T03:33:36.173 回答