I have a rails controller where every action has the same respond_to block for every action, eg:
def some_action
respond_to do |format|
format.html { redirect_to :back }
format.js { render layout: false }
end
end
Is there a way that I can set this as the default response for all actions? I know that I can use
respond_to :html, :js
at the top of the controller, but can this be used to set the specific responses for each format?
Going though respond_with and respond_to documentation and source code. You can either
Use respond_to
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'User was successfully created.'
format.html { redirect_to(#user) }
format.xml { render xml: #user }
else
format.html { render action: "new" }
format.xml { render xml: #user }
end
end
end
OR respond_with
respond_to :html, :xml
def create
#user = User.new(params[:user])
flash[:notice] = 'User was successfully created.' if #user.save
respond_with(#user)
end
A work around is to create your own custom respond method, or manually check for the mime type as follows:
****NOTE: this is a really bad practice, I recommend sticking to conventions.
def some_action
render json: {"a" => "s"} if request.format.json?
render :some_action if request.format.html?
end
If you want all actions to respond exactly the same, move the respond_to block into a method.
def some_action
# do things
respond
end
def another_action
# do more things
respond
end
def special_action
# do special things
respond
end
private
def respond
respond_to do |format|
format.html { redirect_to :back }
format.js { render layout: false }
end
end
This will DRY up your controller, which I assume was the question.
Related
I am using this 3rd party controller:
class LibController
def update
# 29 lines of code
respond_with resource
end
end
I want to do something other than the respond_with at the end. But I don't want to just copy/paste all 29 lines into MyController.update. Unfortunately I can't figure out a way to render or redirect anywhere else:
class MyController < LibController
def update
super
redirect_to somewhere_else
end
end
I get a DoubleRenderError: Render and/or redirect were called multiple times in this action. I assume this is because respond_with calls render immediately. Is there a way to block/prevent that?
Thanks!
I think you are doing a twice redirection.
Try to remove one redirection on your update method.
Check sample code below that shows equivalent response when using respond_with.
def create
#user = User.new(params[:user])
flash[:notice] = 'User was successfully created.' if #user.save
respond_with(#user)
end
Which is exactly the same as:
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = 'User was successfully created.'
format.html { redirect_to(#user) }
format.xml { render xml: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.xml { render xml: #user.errors, status: :unprocessable_entity }
end
end
end
Presently I'm using respond_to like this.
respond_to do |format|
format.html {render layout: false }
end
I know a sentence like respond_to {| format | format.html } can be written respond_to :html.
But how can I write without first block if format.html also have a block argument?
I want to write like respond_to :html, {render layout: false }.
Could it be you have this confused with respond_with?
class PeopleController < ApplicationController
respond_to :html
def index
#people = Person.all
respond_with #people
end
end
respond_with can be configured just as respond_to:
respond_with(#people) do |format|
format.html { render layout: false }
end
See the API documentation or this Railscast for more information about respond_with.
I have the following code:
def edit
#post = Post.find(params[:id])
if !current_user.posts.include?(#post)
permission_denied
end
respond_to do |format|
format.html # edit.html.erb
format.json { render :json => #post }
end
end
def permission_denied
flash[:notice] = 'Sorry, you are not authorized to access that page.'
redirect_to root_url
end
How could adapt this code, so it doesn't show me the "Render and/or redirect were called multiple times in this action" . I have tried adding "and return" to redirect_to root_url and return, but I keep getting the same error.
You should return from the edit action:
def edit
#post = Post.find(params[:id])
return permission_denied if !current_user.posts.include?(#post)
respond_to do |format|
format.html # edit.html.erb
format.json { render :json => #post }
end
end
I get a ActiveModel::MassAssignmentSecurity::Error when I try to running my app to save the login and password details.
got the following error
Can't mass-assign protected attributes: name, password, password_confirmation, salt
app/controllers/users_controller.rb:43:in new'
app/controllers/users_controller.rb:43:increate'
here is the code from the control file
class UsersController < ApplicationController
# GET /users
# GET /users.json
def index
#users = User.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
format.json { render json: #user }
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "edit" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :no_content }
end
end
end
Answer in Stack Overflow and credits for Damien Mathieu
In your model, you need to add tag_attributes to the attr_accessible call.
For example :
class User < ActiveRecord::Base
attr_accessible :tags_attributes
end
If you already call it once, you can either add this field as an argument of the method, or make a second call. Both options are equivalent.
Having to specify all accessible parameters wasn't a default until a few months.
This guide has been updated to reflect the change of default. But the new version hasn't been deployed yet, this is why it's not specified.
I think you forgot to add the attr_accessible parameters in your model. Check out Rails API for more information regarding attr_accessbile and what it protects from.
Like waldyr.ar said, also you can use attr_protected
Is there something like:
respond_to do |format|
format.html || format.xml do
#big chunk of code
end
end
I would like to do that for DRY's sake.
Respond_to actually allows you to specify your common block for different formats by using any:
format.any(:js, :json) { #your_block }
You can use a format like this:
class PeopleController < ApplicationController
respond_to :html, :xml, :js
def index
#people = Person.find(:all)
respond_with(#people) do |format|
format.html
format.xml
format.js { #people.custom_code_here }
end
end
end
Which would achieve what you are looking for, if you have a situation that is more complex let me know. See this article on the respond_with method for more help.
when you
respond_to do |format|
format.html do
#block
end
format.xml do
#block
end
end
or you
respond_to do |format|
format.html { #block }
format.xml { #block }
end
you are taking advantage of ruby blocks, which are evaluated as Procs. Therefore you could do
respond_to do |format|
bcoc = Proc.new do
# your big chunk of code here
end
format.html bcoc
format.xml bcoc
end
but perhaps you could move some of that logic into your data structure?