I recently updated a controller from a plain
render :json => #something
to
respond_to do |format|
format.html {
redirect_to #something
}
format.json {
puts "found json format"
format.json { render json: #something, status: :created }
}
end
But, now I'm getting ActionView::MissingTemplate errors. My question is, if I use the respond_to do |format| block, am I required to use a template? What if I just want to return plain json?
Btw, the puts statement in the json respond_to block is being called successfully.
I think the problem is puts being called inside of your format.json block and the nesting of format.json inside of it's own block. Try removing both (as below).
respond_to do |format|
format.html {
redirect_to #something
}
format.json {
puts "found json format"
format.json { render json: #something, status: :created }
}
end
Try:
respond_to do |format|
format.html { redirect_to #something }
format.json { render json: #something, status: :created }
end
You are telling that you accept HTML and JSON formats. Since your request comes from HTML you'll have the HTML template rendered.
If you want to return only JSON remove that line from your code. Also check the docs on respond_to.
Probably you already know it, but there's a guide on Layouts and Rendering.
Remove the format.json part from within the json rendering block (you have an unnecessary block within your block):
respond_to do |format|
format.html {
redirect_to #something
}
format.json {
render json: #something, status: :created
}
end
I think the reason your code is prompting an error it's because you have
format.json {
format.json { render json: #something , status: :created }
}
You should have:
format.json {
render json: #something , status: :created
}
Related
I am trying to pass through a devise user id from my Agent model (current_agent.id) into my Nested AgentActivity model whenever I update the parameters on my Submission model. How would I go about achieving this?
Currently my code on Submission controller (doesn't throw an error but doesn't do anything):
#submission.agent_activities.first.agent_id = current_agent.id
respond_to do |format|
if #submission.update(submission_params)
format.html { redirect_to #submission, notice: 'Submission was successfully updated.' }
format.json { render :show, status: :ok, location: #submission }
else
format.html { render :edit }
format.json { render json: #submission.errors, status: :unprocessable_entity }
end
end
Yes, you're just assigning agent_id, but don't saving it. Should be:
#submission.agent_activities.first.update(agent_id: current_agent.id)
And this line should go after if #submission.update(submission_params)
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
I have a session variable (user_id) that I'd like to include as a foreign key on a record the user is inserting. I have the form values all coming through the form submit to my controller's entity.update(params) method without a problem using the default params definition. That code looks like
def brand_params
#brand_params = params.require(:brand).permit(:name, :brand_type, :profile_id)
end
The update method looks like
if #brand.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.' }
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
Now I'd like to append the :profile_id session variable to the #brand_params and following other threads here, I've tried a setter method:
def set_brand_params(key, val)
if #brand_params != nil
#brand_params[key] = val
end
end
However, calling this, #brand_params is always nil. Trying to directly add to the brand_params hash doesn't work because it's a better method. If there's a better way to meet this (I'd assume common) use case, I'm all ears! Otherwise, I'd like to know why the var is always nil though in this context, at least the brand_params method sees it as defined and with value. I got this solution in Adding a value to ActionController::Parameters on the server side
Here is the update method as requested:
def update
puts "update"
set_brand_params("profile_id", session[:prof])
respond_to do |format|
if #brand.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.' }
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
end
end
I'm not agree with merge your data with the params. Because you must permit only the fields you expect your user update. In this case you don't want the user update profile_id on brands, and that is a security best practice.
Then brand_params must be:
def brand_params
#brand_params = params.require(:brand).permit(:name, :brand_type)
end
Your method update may look by this:
def update
#brand = Brand.find(params[:id])
#brand.assign_attributes(profile_id: session[:prof])
respond_to do |format|
if #barnd.update(brand_params)
format.html { redirect_to #brand, notice: 'Widget was successfully updated.'}
format.json { render :show, status: :ok, location: #brand }
else
format.html { render :edit }
format.json { render json: #brand.errors, status: :unprocessable_entity }
end
end
end
You don't need the method set_brand_params at all.
If this don't do the trick, please publish the entry controller, and I hope we find the issue.
edit: add respond_to.
The join method below in the teams_controller.rb is sent the following data through submission of a form using EmberJs
{"id"=>"3", "user_id"=>"42", "action"=>"join", "controller"=>"teams"}
The record is getting created with the join method below (according to the console), but the code for what happens after the save is throwing an error
ArgumentError (too few arguments):
app/controllers/teams_controller.rb:145:in `format'
app/controllers/teams_controller.rb:145:in `join'
I copied the code following the #team.save method from the Rails scaffold generator, so I'm a little surprised. The hope is that it will respond with the json, but I left in the html format just because (maybe there's a graceful degradation benefit). Can you tell me why that error's being thrown and/or how I could avoid it?
Rails method
def join
#team = Team.find(params[:id])
id = params[:user_id]
#team.user_ids = #team.user_ids.push(id)
if #team.save
format.html { redirect_to #team, notice: 'Joined Team' }
format.json { render json: #team, status: :created, location: #team }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
Update,
I should also note that, based on the line number of the error message, the method seems to be treating the format as html, however, I wanted it to be treated as json
I forgot to put respond_to do |format| around the code.
respond_to do |format|
if #team.save
format.html { redirect_to #team, notice: 'Joined Team' }
format.json { render json: #team, status: :created, location: #team }
else
format.html { render action: 'new' }
format.json { render json: #team.errors, status: :unprocessable_entity }
end
end
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