Как в rails создать запись, если зависящая от неё запись ещё не сохранена и нет id?
Столкнулся с забавной проблемой.
К примеру есть посты, у поста может быть много картинок через has_many.
Картинки загружаю ajax и если пост уже создан то нет никаких проблем, отослать id поста, создать картинку и привязать её к посту. (редактирование)
Проблема возникает когда хочу создать новый пост, где собственно нет id так как модель не сохранена. И получается привязать картинку пока никуда не могу так как нет id.
Картинки загружаю ajax чтобы их сразу можно было вставлять в создаваемый пост.
Есть какие то соображения в какую сторону копать? Или я вообще не правильный подход сделал?
Делать nested_forms и сохранять картинки вместе с постом не вариант - нужно именно при написании поста, загрузить новую картинку в один клик и вставить в пост.
Вы можете создать эти картинки без указания владельца, вернуть их ID в качестве результата ajax-запроса и сохранить эти ID в форме. При сохранении поста смотрите, какие ID картинок у вас вместе с формой пришли и им после сохранения поста проставляете ID владельца.
Мой способ - при создании формы генерирую случайный uuid в hidden-поле, и его же передаю в ajax-загрузку картинок. Если форма отправлена, то по этому uuid ищу картинки и привязываю их к объекту. Ну и задачу в крон поставить для очистки не привязанных картинок
А где вы запоминаете этот uuid? Потому как от new до create ничего не запоминается. Или в куку бросать этот uuid.
И как вы потом ищете не привязанные картинки если они уже привязаны к uuid?
Ну и отдельный контроллер для прикрепленных файлов есть, с единственным методом create, который получает файлы, создает модель и возвращает ответ что файл принят.
@vsuhachev Ну у меня так же, только ещё есть destroy... Но не суть. Вот у вас форма
вы находитесь в new, отправили вы этот uuid (в другой контроллер, картинка загрузилась) - и дальше как вы знаете какой uuid искать в create уже, где сама форма уже сабмитится - чтобы привязать картинки к моделе?
= simple_form_for resource ... do |f|
- unless form_id.blank?
= hidden_field_tag 'form_id', form_id
... в том же вью инициализация DropzoneJS, который ajax'ом грузит картинки
coffee:
Dropzone.options.media =
params:
'medium[session_id]': "#{form_id}"
'medium[mediable_id]': "#{mediable_id}"
'medium[mediable_type]': "#{mediable_type}"
то-есть form_id параметром уходит в MediaController в ajax-запросе.
Далее, если нажат сабмит в форме, этот же form_id уходит в контроллер владельца картинки, в котором все склеивается. Если владелец уже существует, то mediable_id и mediable_type оказываются заполнены и привязка по form_id пропускается.
Вы когда отправляете в MediaController вы заполняете mediable_id значением из form_id я правильно понимаю?
То есть вы когда отправляете в контроллер владельца, вы берёте form_id ищете в базе картинки с таким id и меняете на id владельца?
У меня тоже полиморфизм используется, по сути тоже самое. Ваш вариант с единым id подходит лучше.
@vsuhachev Но тогда как быть с такой ситуацией - юзер заходит в форму, загружает пару картинок и закрывает браузер. То есть картинки загружены mediable_id не пустой в нём значение из form_id.
То что выше предложили добавлять загруженные id картинок в форму и потом по ним проходить - так mediable_id остаётся пустым если юзер вдруг решит после загрузки пары картинок закрыть браузер или не захочет дальше продолжать заполнять форму. Так мы можем сделать запрос и картинки у которых mediable_id == nil, удалить.
А в вашем случае как? Чистить не привязанные картинки?
Нет, все 3 параметра form_id, mediable_id, mediable_type передаются отдельно и просто сохраняются в картинку. Если mediable_id и mediable_type не пустые, то владелец оказывается уже привязан. Если их нет, то создаем картинку с пустой связью и заполненным form_id.
Удаляю по связке пустой mediable_id и updated_at больше чем час назад.
Всем спасибо за ответы. Оба варианта хороши, но я сделал через сессию - залитые id картинок храню в сессии и потом при сохранение поста - прохожусь по загруженным картинкам и выставляю id поста.
Если юзер зальёт картинки и не станет продолжать создание поста, как предложил @vsuhachev такие картинки будут чистится кроном.