Insert data into database from controller Ruby On Rails? - ruby-on-rails

In my def Create funciton in casting_controller. I create an Casting object and save it. this is ok, but i also want to create a LinkCastingToModel object, insert data to it from my controller, but when i check, the data is always nil. How can i insert data into it
def create
#casting = Casting.new(casting_params)
#casting.models_booked = 0
link = LinkModelAndCasting.new
link.client_id = #casting.id
link.save
# link_model_and_casting = LinkModelAndCasting.new(:casting_id => #casting.id)
# link_model_and_casting.save
respond_to do |format|
if #casting.save
format.html { redirect_to #casting, notice: 'Casting was successfully created.' }
format.json { render :show, status: :created, location: #casting }
else
format.html { render :new }
format.json { render json: #casting.errors, status: :unprocessable_entity }
end
end
end
I use postgresql, thanks.

It's because when you're assigning clinet_id to link from #casting.id, till then #casting was not saved, so the id is actually nil.
You'll have to call #casting.save before that. Then it will work. Something like this:
def create
#casting = Casting.new(casting_params)
#casting.models_booked = 0
#casting.save
link = LinkModelAndCasting.new
link.client_id = #casting.id
link.save
# link_model_and_casting = LinkModelAndCasting.new(:casting_id => #casting.id)
# link_model_and_casting.save
respond_to do |format|
if #casting.id
format.html { redirect_to #casting, notice: 'Casting was successfully created.' }
format.json { render :show, status: :created, location: #casting }
else
format.html { render :new }
format.json { render json: #casting.errors, status: :unprocessable_entity }
end
end
end

Related

Rails 7: How to check from outside transaction block if record was updated successfully

I've searched through the rails docs but not find any method which can check if record was corectly updated from outside transaction block because I dont want to put respond_to block into my transaction because it is bad practise. Is there any method like persisted? which I use with create/save method...
def update
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
#invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if #invoice.method `some method to check if invoice was updated`
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end
I just edit my code as bellow, capture result of the transaction to variable is_updated. When in transaction error occurred then is_updated would be false and changes are rolled back. If no error occurred is_updated true.
def update
is_updated =
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
#invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if is_updated
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end end
Calling .update on an ActiveRecord object will return true if it was able to store it to db or false if any error occurred.
I'd take advantage of that and store its result on a variable, like the following:
def update
updated = false
ActiveRecord::Base.transaction do
address = Address.find_or_create_by(address_params)
#invoice_account = InvoiceAccount.find_or_create_by(invoice_account_params
.merge({ :invoice_address_id => address.id }))
#invoice = Invoice.find_by_id(params[:id])
updated = #invoice.update(invoice_params.merge({ purchaser_id: #invoice_account.id }))
end
respond_to do |format|
if updated
format.html { redirect_to invoice_url(#invoice), notice: "Invoice was successfully updated." }
format.json { render :show, status: :ok, location: #invoice }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: #invoice.errors, status: :unprocessable_entity }
end
end
end

change behaviour of Create if record with same attribute exists

I'm building an app like reddit where you add a Submission to a specific user page. Submission has a few attribute including an attribute called url.
I want to check when adding a new submission if already a submission with that same url exists for that specific page, and if it exist, vote for it instead of creating it as a new submission. If not, just add it as a new submission. I'm using the act_as_votable gem here.
Here is the create method:
def create
#user = User.friendly.find(params[:user_id])
#submission = #user.submissions.new(submission_params)
#submission.member_id = current_user.id
#submission.creator_id = #user.id
#submission.is_viewed = false
#submission.get_thumb_and_title_by_url(#submission.url)
respond_to do |format|
if #submission.save
format.html { redirect_to #user, notice: 'Submission was
successfully created.' }
format.json { render :show, status: :created, location: #submission }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
you should take a look at https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_create_by and https://apidock.com/rails/v4.0.2/ActiveRecord/Relation/find_or_initialize_by
Now on your code we can make changes like
def create
#user = User.friendly.find(params[:user_id])
#submission = #user.submissions.find_or_initialize_by(submission_params)
if #submission.id.present?
# What to do if the record exists
else
# if its a new record
#submission.member_id = current_user.id
#submission.creator_id = #user.id
#submission.is_viewed = false
#submission.get_thumb_and_title_by_url(#submission.url)
end
respond_to do |format|
if #submission.save
format.html { redirect_to #user, notice: 'Submission was
successfully created.' }
format.json { render :show, status: :created, location: #submission }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
I hope that this can put you on the right track
Happy Coding

Rails: How to update multiple models together, with proper rollback (kind of manual nested attributes)

I (for various reasons) have decided not to use nested_attributes. Here is my current controller:
def update
# Update snippet
#snippet.update(snippet_params)
# Update hotspot
#snippet.hotspot.update(hotspot_params)
# Update text
#snippet.text.update(medium_params_with(:text))
# Update audio
if params[:audio] {
#snippet.audio.destroy
#snippet.media << Audio.new(medium_params_with(:audio))
}
respond_to do |format|
if success = true #fix this up
format.html { redirect_to #project, notice: 'Snippet was successfully updated.' }
format.json { render :show, status: :ok, location: #snippet }
else
format.html { redirect_to #project, warning: 'Highlight was not updated.' }
format.json { render json: #snippet.errors, status: :unprocessable_entity }
end
end
end
This is more or less OK if nothing goes wrong.
How do I wrap this into something like:
try {
update everything
} else {
undo any changes I made while trying to update everything
}
if success {
etc
} else {
etc
}
If what you are changing are ActiveRecord models using a SQL database then http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html might provide exactly what you're looking for.
Following #Jonah's answer, I wrapped the DB changes in ActiveRecord::Base.transaction:
def update
success = ActiveRecord::Base.transaction do
# Update snippet
#snippet.update(snippet_params)
# Update text
#snippet.text.update(medium_params_with(:text))
# Update audio
if params[:audio]
#snippet.audio.destroy
#snippet.media << Audio.new(medium_params_with(:audio))
end
end
respond_to do |format|
if success
format.html { redirect_to #project, notice: 'Snippet was successfully updated.' }
format.json { render :show, status: :ok, location: #snippet }
else
format.html { redirect_to #project, warning: 'Highlight was not updated.' }
format.json { render json: #snippet.errors, status: :unprocessable_entity }
end
end
end

Getting ID from an item that's not saved yet

I am saving data to two different models at once. This has successfully been done.
These two models are associated with each other, so one most store the others ID on save. How to I store the questionnaire_contact_id in QuestionnaireResult?
class QuestionnaireResultsController < ApplicationController
def create
#questionnaire_result = QuestionnaireResult.new(params[:questionnaire_result])
#questionnaire_contact = QuestionnaireContact.new(params[:questionnaire_contact])
respond_to do |format|
if #questionnaire_result.save
#questionnaire_contact.save
format.html { redirect_to root_path, notice: 'Questionnaire was successfully submited.' }
format.json { render json: questionnaires_path, status: :created, location: questionnaires_path }
else
format.html { render action: "new" }
format.json { render json: questionnaires_path.errors, status: :unprocessable_entity }
end
end
end
end
You should use activerecord associations:
def create
#questionnaire_result = QuestionnaireResult.new(params[:questionnaire_result])
#questionnaire_contact = #questionnaire_result.questionnaire_contacts.new(params[:questionnaire_contact])
respond_to do |format|
if #questionnaire_result.save #this line will automatically save associated contact
# code
else
# code
end
end
end
Solved, it was as easy as doing this:
class QuestionnaireResultsController < ApplicationController
def create
#questionnaire_result = QuestionnaireResult.new(params[:questionnaire_result])
#questionnaire_contact = QuestionnaireContact.new(params[:questionnaire_contact])
respond_to do |format|
#questionnaire_contact.save
#questionnaire_result.admin_questionnaire_contact_id = #questionnaire_contact.id
if #questionnaire_result.save
format.html { redirect_to root_path, notice: 'Questionnaire was successfully submited.' }
format.json { render json: questionnaires_path, status: :created, location: questionnaires_path }
else
format.html { render action: "new" }
format.json { render json: questionnaires_path.errors, status: :unprocessable_entity }
end
end
end
end

Change action respond_to depending on response code

I have the following create action:
def create
#report = Report.new(params[:report])
#file = params[:report][:data_file]
res = #report.get_report(#file, #report.year, #report.month)
file = open('report.pdf','wb')
file.write(res.body)
#report.file = file
respond_to do |format|
if #report.save
format.html { redirect_to #report, notice: 'Report was successfully created.' }
format.json { render json: #report, status: :created, location: #report }
else
format.html { render action: "new" }
format.json { render json: #report.errors, status: :unprocessable_entity }
end
end
end
However the HTTP response stored in the res variable can have a 200 code, or a 400 code that indicates a Bad Request. I want that if the res.code is 400, it also goes back to the new action with a warning message.
I tried including that condition on the respond_to if like below, but it didn't worked. It seems that after creating the instance it redirected to edit action. It makes no sense.
respond_to do |format|
if #report.save and res.code == 200
format.html { redirect_to #report, notice: 'Report was successfully created.' }
format.json { render json: #report, status: :created, location: #report }
else
format.html { render action: "new" }
format.json { render json: #report.errors, status: :unprocessable_entity }
end
end
What would be the correct way to do it?
It's a bit of a complicated workflow, but it looks like if res's status is 400, you just want to render the new form again. So you can early escape using the below:
if res.status != 200
render :new
return
end
respond_to do |format|
if #report.save
format.html { redirect_to #report, notice: 'Report was successfully created.' }
format.json { render json: #report, status: :created, location: #report }
else
format.html { render action: "new" }
format.json { render json: #report.errors, status: :unprocessable_entity }
end
end

Resources