Witam!
Chciałbym mieć możliwość zapisu kategorii (buckets) dokumentów podczas tworzenia dokumentu.
Niestety otrzymuje błąd You cannot call create unless the parent is saved
W konsoli widać jeszcze
0.3ms) BEGIN
↳ app/controllers/documents_controller.rb:21
(0.3ms) ROLLBACK
↳ app/controllers/documents_controller.rb:21
Completed 422 Unprocessable Entity in 109ms (ActiveRecord: 1.4ms)
class Document < ApplicationRecord
mount_uploader :file, FileUploader
delegate :user, to: :bucket
belongs_to :bucket, required: false
attr_accessor :new_bucket_name
before_save :create_bucket_from_name
def create_bucket_from_name
create_bucket(name: new_bucket_name) if new_bucket_name.present?
end
end
Bucket model
class Bucket < ApplicationRecord
belongs_to :user, required: false
has_many :documents
end
Tworzenie dokumentu
def create
@document = current_user.documents.new(document_params)
if @document.save
perform_upload_file_confirmation(@document.id)
redirect_to dashboard_path
end
end
Nie bardzo rozumiem dlaczego ma być po zapisie, przecież zanim zapisze dokument muszę mieć id (jest required false ale i tak chce wykorzystac to id do dokumentu) bucket więc bucket musi być zapisany przed dokumentem …
Jeśli dobrze myślę.
Sprawdziłem też jeśli stworze od nowa dwa modele bucket i document to korzystając z tego: https://rubyplus.com/articles/3501-Create-Model-Through-Text-Field-in-Rails-5
Można stworzyć bucket before_save podczas tworzenia Document.
W mojej aplikacji mam jeszcze Devise i user jest przypisany do dokumentu. I być może tutaj jest jakiś problem może chodzi o jakiś token tylko gdzie i jak to ominąć/naprawić
Osobiście mam jakąś awersje do callbacków i raczej stworzyłbym jakiś service object, który by wyglądał mniej więcej tak:
class DocumentService
def self.build(user, params)
new(user, params).build
end
def initialize(user, params)
@user = user
@params = params
end
def build
@user.documents.new(params_with_bucket)
end
private
def params_with_bucket
@params.merge(bucket: bucket)
end
def bucket
Bucket.find_by(id: @params[:bucket_id]) || Bucket.create(name: @params[:new_bucket_name], user: @user)
end
end
A potem w kontrolerze takie wywołanie:
def create
@document = DocumentService.build(current_user, document_params)
if @document.save
perform_upload_file_confirmation(@document.id)
redirect_to dashboard_path
end
end