2015-07-11 3 views
1

Я пытаюсь создать небольшую игру с поворотом по 2 игрока, используя Rails, для инициализации игры требуется только 1 игрок, который установит поле, к которому может присоединиться другой игрок. Каждый игрок в игре будет иметь земли, которая может содержать здания, отношения между ними следующим образом:Rails manual commit records

#Game 
has_many :lands 
#Land 
belongs_to :game 
has_many :buildings 
#Building 
belongs_to :game 

Только игра имеет контроллер, так как это мастер их всех, так что, когда игра должна быть инициализированный запрос будет содержать информацию для создания земли и зданий, и все они рассматриваются как единое целое, поэтому, если одна из этих записей выходит из строя, я не хочу ничего совершать. Я думал об использовании building.save if land.save, но это вызовет ошибку, так как я сохраняю здание на земле, которая не выходит, но если я сначала сэкономлю землю, а здание потерпит неудачу, мне нужно будет удалить землю и игру, это усложняется с несколькими зданиями и различными ошибками, поступающими из разных мест, чтобы справиться со всеми этими условиями.

Какие еще варианты можно использовать для достижения этого?

Edit: Игровой контроллер будет что-то вроде этого:

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

Можете вставить здесь свой код? Его легче читать, чем вы пытаетесь описать, что происходит в вашем контроллере. – max

+0

Я еще не написал игровой контроллер, вот где я застрял в том, как писать его, чтобы достичь того, о чем упоминалось, я попытаюсь обновить общую форму, как я думаю, что она появится , –

+0

Как вы думаете, вы можете перефразировать свой вопрос? Это похоже на то, что вы ищете транзакции, тогда я мог только понять примерно 1/10 вопроса. – max

ответ

0

Вы можете обернуть запросы в транзакции:

ActiveRecord::Base.transaction do 
    # put your calls here 
end 

И вы должны использовать .save! метод, так что исключения, созданные валидации вышвырнуты, в противном случае запросы не молча.

+0

Я посмотрю на это, это будет проверять все записи без ошибок? –

+0

Никакие транзакции не являются вроде функции отмены в вашей базе данных. Вы можете выполнять несколько операторов SQL, а затем откатываться (отменить) в любой момент до совершения транзакции. Вы можете использовать это вместе с проверками, но они действительно являются отдельными понятиями. – max

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 

Но еще важнее не пытаться делать все в одном действии контроллера. Это приводит к действительно хрупким и сложным проектам.

Вместо этого вы можете выполнить настройку своей игры в несколько этапов.

  1. Пользователь 1 создает игру POST /games
  2. Пользователь 1 перенаправляется на GET /games/1
  3. Поскольку нет земли Пользователь 1 бы создать землю, заполнив форму, и которые ПОСТЫ к /games/1/lands. Затем он перенаправляется обратно на /games/1.
  4. Пользователь теперь может видеть землю, которую мы только что создали в игровом режиме.
  5. Пользователь 1 решает построить ручку для свинья на земле 1. Он нажимает кнопку, которая отправляет POST /lands/1/buildings. Но у пользователя 1 не хватает ресурсов, поэтому проверка для здания не выполняется. Мы показываем сообщения об ошибках пользователю.

Как вы, наверное, догадались, что браузерный дизайн игры требует широкого использования ajax и javascript. Построение API на стороне сервера - это небольшая часть.

+0

Я просматриваю вложенные атрибуты, это лучшее решение в сочетании с транзакцией. Я не хочу использовать несколько шагов, так как пользователю не разрешается редактировать созданную им игру и не допускать редактирования во время игры. –