Как я могу убедиться, что parent_id установлен правильно при создании нового элемента на основе существующего элемента? - PullRequest
1 голос
/ 12 августа 2010

Проблема

Забавная проблема.Забавно, потому что это выглядит непринужденно, пока вы не начнете думать об этом.Допустим, я позволяю людям создавать предметы на основе других предметов.Вы можете открыть /items/new?id=3 и, в отличие от вашего обычного нового действия, вместо просмотра пустой формы вы увидите форму, предварительно заполненную значениями из элемента-3.Таким образом, в отличие от вашего нового действия по умолчанию, мое выглядит следующим образом:

def new
  @item = params[:id] ? Item.find(params[:id]) : Item.new
end

Таким образом, вы можете получить доступ к действию с URL-адресом, подобным /items/new?id=1, и форма будет предварительно заполнена данными из элемента-1.

Пока все хорошо.

Теперь вы отправляете эти данные.Мое действие создания довольно стандартно.

def create
  @item = Item.new(params[:item])

  if @item.save
    # happy
  else
    # sad
  end
end

Здесь есть только одна проблема.Новый элемент, который был только что создан (назовем его item-2), должен знать, кто этот папа.В нашем случае это папка item-1 (поскольку исходная форма была предварительно заполнена данными из item-1), и поэтому item-2 должен иметь parent_id, установленный в 1. Только это не просто хорошоиметь.Он должен быть твердым, невозможным вмешиваться.Вы не должны иметь возможность подделать parent_id.

Поэтому мой вопрос - как я могу убедиться, что parent_id установлен правильно при создании нового элемента на основе существующего элемента?

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

Non-solution # 1

Таким образом, обычное решение для сохранения parent_id - это просто использовать его как скрытое поле в форме.

<% form_for @item do |f| %>
  ...
  <%= f.hidden_field :parent_id, :value => params[:id] %>
  ...
<% end %>

Но здесь я могу легко переключить его в своем html.Когда форма отправлена, сервер не имеет ни малейшего представления.Сервер просто «поверит», что элемент был создан с родителем [что угодно], когда он должен был быть родительским 1.

Non-solution # 2

На сервере я мог бы использоватьсеанс, чтобы сохранить, какой элемент вы редактируете.Тогда мое новое действие будет выглядеть следующим образом.

def new
  if params[:id]
    @item = Item.find(params[:id])
    session[:creating_item] = params[:id].to_i
  else
    @item = Item.new
    session[:creating_item] = :mine # this prevents loophole if session is cleared
  end
end

И мое действие создания примет это значение и установит его в parent_id.

def create
  @item = Item.new(params[:item])

  if session[:creating_item] == :mine
    @item.parent_id = nil
  elsif session[:creating_item].is_a?(Fixnum)
    @item.parent_id = session[:creating_item]
  else
    # session was probably cleared
    redirect_to root_url and return
  end

  if @item.save
    # happy
  else
    # sad
  end
end

Это не будет работать, если вы откроете /items/new несколько раз (например, в нескольких вкладках в браузере).Значение сеанса будет перезаписываться каждый раз.Поэтому, если вы отправляете форму, открытую в /items/new?id=1, но вы также открыли /items/new?id=2, то parent_id в сеансе будет равен 2. Неудачно.

Не решение # 3

Что если вы сохранитевсе открытые родители в массиве в сеансе, вместо того, чтобы просто перезаписывать одно значение.Ну, я не собираюсь выписывать длинные примеры, я просто скажу, что при отправке любой из открытых форм - вы будете знать, что это должен быть один из родителей, которых вы сохранили в сеансе (например, 1, 2 или 3), но вы все еще не знаете, какой.Затем вы можете сохранить данные из родительского 1, как если бы они были из родительского 3.

1 Ответ

0 голосов
/ 12 августа 2010

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

Альтернативой может быть небольшое изменение рабочего процесса.Сделайте так, чтобы действие действительно клонировало, и создайте новый элемент до , позволяющий пользователю редактировать.Таким образом, вся проблема становится спорной.Возможно, вам придется подтвердить с пользователем перед его созданием, чтобы убедиться, что у вас нет клонированных объектов по всей системе, или предоставить простую функцию удаления, если они передумают.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...