我试图使用Rails构建一个小型2玩家回合制游戏,初始化游戏只需要1个玩家,他们将设置该区域,然后另一个玩家可以加入。游戏中的每个玩家将拥有一个可以包含建筑物的土地,它们之间的关系如下:
#Game
has_many :lands
#Land
belongs_to :game
has_many :buildings
#Building
belongs_to :game
只有游戏有一个控制器,因为它是所有游戏的主人,所以当游戏初始化时,请求将包含创建土地和建筑物的信息,并且所有都被视为一个,所以如果其中一个记录失败我不想做任何事情。我想过使用building.save if land.save
但是它会产生错误,因为我将建筑物保存到一块没有退出的土地上,但是如果我先保存土地并且建筑物失败那么我就#&# 39; ll需要删除土地和游戏,它会变得复杂,有多个建筑物进入,并且来自多个地方的各种错误可以处理所有这些条件。
我可以使用哪些其他选项来实现这一目标?
编辑: 游戏控制器将是这样的:
class GamesController < ApplicationController
def create
#generate new land to contain buildings
land = Land.new(user: @current_user)
#generate new buildings from array of hashes, contains coords+land_id
buildings = []
params[:buildings].each do |building|
buildings.push Building.new(building.merge!({land: land}))
end
game = Game.new(user_1: @current_user, land_1: land)
land.game = game #set the game it belongs to
#some code here to save land+game+buildings
#if one of them failed then nothing is saved at all.
end
end
还有一个问题是我无法保存这样的游戏,因为它可以验证土地的存在,并且无法保存土地,因为它可以验证游戏的存在,同样适用于他们验证的建筑物土地的存在。因此,我需要一个能够一次性保存它们的代码,并且仍能成功验证它们。
答案 0 :(得分:1)
您可以将查询包装在事务中:
stream file Usage: STREAM FILE <filename> <escape digits> [sample offset]
Send the given file, allowing playback to be interrupted by the given digits, if any.
Use double quotes for the digits if you wish none to be permitted.
If sample offset is provided then the audio will seek to sample offset before play starts.
Remember, the file extension must not be included in the filename.
Returns: failure: 200 result=-1 endpos=<sample offset> failure on open: 200 result=0 endpos=0 success: 200 result=0 endpos=<offset> digit pressed: 200 result=<digit> endpos=<offset>
您应该使用ActiveRecord::Base.transaction do
# put your calls here
end
方法,以便抛出验证创建的异常,否则查询将无声地失败。
答案 1 :(得分:0)
在Rails中,您可以使用accepts_nested_attributes_for
从同一表单创建嵌套模型:
class User < ActiveRecord::Base
has_many :pets
accepts_nested_attributes_for :pets
validates_associated :pet
end
class UserController < ApplicationController
def new
@user = User.new
@user.pets.build
end
def create
@user
end
def pet_params
params.require(:user).permit(pets_attributes: [:name, :type])
end
end
您还可以使用可用于将记录插入数据库的事务,并在以后的条件失败时回滚。
class OrdersController < ApplicationController
def create
@order = Order.new(order_params)
Order.transaction do
@payment = Payment.new(customer: @order.customer, amount: order.amount)
raise ActiveRecord::Rollback unless @order.save && @payment.save
end
end
end
但更重要的是不要试图在一个控制器动作中做所有事情。它导致了非常脆弱和过于复杂的设计。
相反,您可能希望通过多个步骤进行游戏设置。
POST /games
GET /games/1
/games/1/lands
。然后他被重定向回/games/1
。 POST /lands/1/buildings
的按钮。但是用户1没有足够的资源,因此构建验证失败。我们向用户显示错误消息。正如您可能猜到的那样 - 浏览器游戏设计需要广泛使用ajax和javascript。构建服务器端API只是一小部分。