Change action respond_to depending on response code - ruby-on-rails

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

Related

Forwarding post parameters in a redirect_to rails

In my rails app, I want the user to be able to select an option in a 'new' form, but if the option already exists, I want it to update the current option.
I have this so far in my create method:
def create
#cost = Cost.new(cost_params)
if Cost.exists?(:category => #cost.category, :option => #cost.option)
redirect_to action: 'update', id: Cost.where(:category => #cost.category, :option => #cost.option).first.id
else
respond_to do |format|
if #cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: #cost, status: :created, location: #cost }
else
format.html { render action: "new" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
end
The problem is that it redirects me to, for example cost/9 url, which renders the show page. I want the id to send with the cost_params straight to the update method:
def update
#cost = Cost.find(params[:id])
respond_to do |format|
if #cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
Which should redirect to the index page.
is there any efficient way to do this?
And HTTP redirect always results in a GET request, not a POST request, so redirecting to update doesn't really make a lot of sense. That's not a Rails issue, that's just how HTTP works.
If you want to automatically update the relevant record, you have to do that from within the create action. The straightforward but lazy way would be to copy the code from update and paste it into if branch within create. The more correct way would be to extract the relevant part of update out into a separate, private method, and call that method from both create and update, something like:
def create
#cost = Cost.new(cost_params)
if Cost.exists?(:category => #cost.category, :option => #cost.option)
#cost = Cost.where(:category => #cost.category, :option => #cost.option).first
really_update
else
respond_to do |format|
if #cost.save
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully created.'] }
format.json { render json: #cost, status: :created, location: #cost }
else
format.html { render action: "new" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end
end
def update
#cost = Cost.find(params[:id])
really_update
end
private def really_update
respond_to do |format|
if #cost.update_attributes(cost_params)
format.html { redirect_to action: 'index', status: 303, notice: [true, 'Cost was successfully updated.'] }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #cost.errors, status: :unprocessable_entity }
end
end
end

Insert data into database from controller 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

Passing an argument on request.referrer

I'm building a site where a link to fill a new form can be clicked from an Event show page
<%= link_to 'Be a Contestant', new_form_path(:event_id => #event.id)%>
This creates a link like
http://localhost:3000/forms/new?event_id=2
Now if the form is filled with an error, when submitted, it returns an error
Couldn't find Event with 'id'=""
So I decided to use the request.referrer to redirect back to the previous page but it doesn't list the errors as use this method
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { redirect_to request.referrer }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end
I also tried this but to no avail.
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { redirect_to new_form_path(:event_id => request.referrer.params[:event_id]) }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end
What you probably really need to do is to add a hidden field event_id to the form because I'm betting that event_id doesn't get propagated from the #new to the #create action.
See here for more information on hidden_field_tag
You usually just render the edit view when there was an error in create:
def create
#form = Form.new(form_params)
respond_to do |format|
if #form.save
format.html { redirect_to #form, notice: 'Form was successfully created.' }
format.json { render :show, status: :created, location: #form }
else
format.html { render :edit, alert: 'Error creating ...' }
format.json { render json: #form.errors, status: :unprocessable_entity }
end
end
end

format.json { render json: #product.errors, status: :unprocessable_entity }

what is the use of
format.json { render json: #product, status: :created, location: #product }
format.json { render json: #product.errors, status: :unprocessable_entity }
in the following code of the controller Product
def create
#product = Product.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to #product, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
format.html { render action: "new" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
It renders a json response if json is requested, the same way it does with html if html is requested. If you load it in a browser, it is going to give you html, but you may want yo get the json if you are doing something with it. You should use "what is the use of" and not "function", which is ambiguous.

Get file name of Carrierwave upload in rails controller

I need to get the file name of and uploaded file in my controller so that i could set a default title (or name) to the uploaded file if the user did not assign one. I use Carrierwave to upload ing files.
My controller create action looks like this:
def create
#photo = Photo.new(params[:photo])
#photo.user_id = current_user.id
respond_to do |format|
if #photo.save
format.html { redirect_to #photo, notice: 'Photo was successfully created.' }
format.json { render action: 'show', status: :created, location: #photo }
else
format.html { render action: 'new' }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end
The solution was to get the filename from the carrierwave file like this:
def create
#photo = Photo.new(params[:photo])
#photo.user_id = current_user.id
#photo.name = #photo.image.file.filename if #photo.name == ""
respond_to do |format|
if #photo.save
format.html { redirect_to #photo, notice: 'Photo was successfully created.' }
format.json { render action: 'show', status: :created, location: #photo }
else
format.html { render action: 'new' }
format.json { render json: #photo.errors, status: :unprocessable_entity }
end
end
end

Resources