I am trying to do an AJAX call with Rails. The call is to the change_profile action in my controller. The contents of this action are as follows:
def change_profile
#test = params[:test]
puts "AAAAAAA #{#test}"
respond_to do |format|
format.html
format.js
end
render(:text => "FINISHED THE AJAX REQUEST")
end
When I call this, however, the Rails console says:
ActionView::MissingTemplate (Missing template main/change_profile ....
I don't understand why this is happening. Since I'm rendering text, shouldn't it know not to try to find the template and just render the text?
When left without a {}, the respond_to block looks for a file called change_profile.erb.js or some other change_profile.xxx.js. Add your code within the respond_to block
def change_profile
#test = params[:test]
puts "AAAAAAA #{#test}"
respond_to do |format|
format.html
format.js {
render :text => "FINISHED THE AJAX REQUEST"
}
end
end
Related
In my CoinsController, I have added a respond_to method in my index controller. I'm not sure if my code is right but here is my index controller below:
def index
paginated = paginate(Coin.recent)
render_collection(paginated)
respond_to do |format|
format.json do
format.html # index.html.erb
format.json { render json: render_collection(paginated) }
end
end
end
I read the few documents I found online about respond_to do |format| method and when I tried adding it manually the way it is in the documentation, I get an Unknown Format error. What I'm trying to do is have logic that handles both html and json, so that it can act as a json api and a view renderer.
Any ideas?
Ok guys so I found out the solution to my problem:
def index
paginated = paginate(Coin.recent)
# render_collection(paginated)
respond_to do |format|
format.json do
render_collection(paginated)
end
format.html do
render :index
end
end
end
I had commented out the render_collection(paginated) and then added json and html to it's own block and it worked.
The respond_to block in a create controller in my Rails app is not redirecting on a successful save... I'm sure this is a simple solution, but I am inexperienced with Rails and this is the first time that I am encountering this problem.
The form is set so that :remote => true, and the controller is as follows...
def create
#store = current_user.stores.new(store_params)
respond_to do |format|
if #store.save
format.html { redirect_to root_path }
else
format.html { flash[:alert] = "Save failed! #{#store.errors.full_messages.join(";")}"
render "new" }
format.js {}
end
end
end
And while I'm on the subject, the code from the else portion of the conditional doesn't run either, except for format.js {}, which does run the code in my create.js.erb file (an alert, for the time being).
I'm working with Rails 4.2.5. Can someone help me to understand why the redirect and the alert are not working? Thank you!
EDITING TO SHOW SOLUTION
Based on Rich's answer, here's the solution that I came up with:
Controller:
def create
#store = current_user.stores.new(store_params)
flash.now[:alert] = "Save failed! #{#store.errors.full_messages.join(";")}" unless #store.save
respond_to do |format|
format.js
end
if #store.save
flash[:notice] = "New store created"
end
end
create.js.erb
<% if flash.now[:alert] %>
$("#alert_holder").empty();
$("#alert_holder").append("<%= j flash.now[:alert] %>");
<% else %>
window.location.href = "<%= root_url %>";
<% end %>
Note that I needed to add quotes around the redirect url.
On form success, the page redirects to root. On failure, the error message flashes but the form is not refreshed - any answers the user has entered remain.
remote: true is an ajax request.
Ajax is javascript, and as such will invoke the format.js method:
def create
#store = current_user.stores.new store_params
respond_to do |format|
if #store.save
format.js
format.html { redirect_to root_path }
else
format.js
format.html { flash[:alert] = "Save failed! #{#store.errors.full_messages.join(";")}"
render "new" }
end
end
end
The format.js method will call the /app/views/[:controller]/[:action].js.erb file, which will fire any of the JS you have inside it.
If you don't want to have the js format handling the response, you'll have to do away with respond_to and just have what you'd like to return (redirect_to won't work).
Ajax
There are several stipulations you need to appreciate with this:
Ajax cannot "redirect" (on its own)
Ajax will be treated as JS in your Rails controller
You have to "hack" the flash to get it working through JS
If you don't have experience with Ajax, the simple explanation is that it's a "pseudo-request"; it sends an HTTP request without having to reload the browser.
The pattern for Ajax is simple: Ajax request > server > Ajax response
You cannot "redirect" via Ajax unless you parse the response with javascript. As the Ajax acronym (Asynchronous Javascript And XML) suggests, the response is expected to be XML (IE no functionality).
--
To answer your question, you'll need to use flash.now for the "flash" message, and handle the response with your .js.erb file:
def create
#store = current_user.stores.new store_params
flash.now[:alert] = "Save failed! #{#store.errors.full_messages.join(";")}" unless #store.save
respond_to do |format|
format.js
format.html
end
end
This will allow you to call...
#app/views/stores/create.js.erb
<% if flash.now[:alert] %> alert("<%=j flash.now[:alert] %>"); <% end %>
window.location.href = <%= root_url %>;
Ref
Your new code can be improved a little :
def create
#store = current_user.stores.new store_params
if #store.save
flash[:notice] = "New store created"
else
flash.now[:alert] = "Save failed! #{#store.errors.full_messages.join(";")}"
end
respond_to do |format|
format.js
end
end
If you wanted to DRY up your code even more, you'll want to look at the responders gem:
#app/controllers/stores_controller.rb
class StoresController < ApplicationController
respond_to :js, only: :create
def create
#store = ...
respond_with #store if #store.save
end
end
If you have remote: true in your form, the format that is detected by the controller will be format.js, which is not present in your successful #store.save section.
2 options:
Default to normal form submit (by removing remote: true)
Load another js.erb file by adding format.js just like in the else clause then do the error handling there via some javascript.
I have one js file show.js that is renderd for the action def show:
def show
....
respond_to do |format|
format.html
format.js
end
end
My question is how can I change the respond_to block, so that it does not respond with show.js but for example with newshow.js? I ask because I would like to render different js dependent on the params! Thanks! I use Rails 4.
I believe that this one would work:
respond_to do |format|
format.html
format.js { render :newshow }
end
I'm trying to call a javascript function (actually coffeescript) from a controller in a Rails 3.2 app.
I'm getting a Render and/or redirect were called multiple times in this action error.
My code looks like this:
#Model.controller
def index
#models = Model.all
my_action if current_user.name == "Bob" #or some other general conditional
...and some stuff
respond_to do |format|
format.html
format.js #this is needed to handle ajaxified pagination
end
end
def my_action
respond_to do |format|
format.js { render :js => "my_function();" } #this is the second time format.js has been called in this controller!
end
end
#functions.js.coffee.erb
window.my_function = ->
i = xy
return something_amazing
What is the correct way to call a js function from the controller?
Man, you missed argument for block. Primary mistake.
def my_action
#respond_to do # This line should be
respond_to do |format|
format.js { render :js => "my_function();" }
end
end
And MrYoshiji's point is right. But your error was on server side, had not reached client side yet.
For the style, I think that's okay if the js code is one function call only. If more JS code, it's better to render js template
# controller
format.js
# app/views/my_controller/my_action.js.erb
my_function();
// and some more functions.
Update: How to fix double rendering problem
You must have your #index return if condition met, or the method will continue to execute and cause rendering twice or more. Fix it like this:
def index
#models = Model.all
if current_user.name == "Bob"
return my_action
else
# ...and some stuff
respond_to do |format|
format.html
format.js #this is needed to handle ajaxified pagination
end
end
I am an experienced JAVA and C++ developer and I am trying to understand how rails works.
I got this code below:
respond_to do |format|
if #line_item.save
format.html { redirect_to store_url }
format.js { render :json => #line_item, :mime_type => Mime::Type.lookup('application/json'),
:callback => 'javascriptFunction' }
and I've been searching the api that defines what I can pass inside the format.js {} but I could not find..
first of all: what kind of statement is format.js, is that a variable?
and most important: what attributes can I pass into format.js {} ? can you pass the direct link? I've searched over the http://api.rubyonrails.org/
respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
end
js here specifies a mime-type that the controller method would send back as a response;
Default Rails mime-types.
If you try also with format.yaml:
respond_to do |format|
format.js
format.yaml
end
that will mean that your controller will return yml or js depending on what the client-side is asking;
{} in terms of ruby is a block;
If you don't specify any rails will try to render a default file from app/views/[contoller name]/[controller method name].[html/js/...]
# app/controllers/some_controller.rb
def hello
respond_to do |format|
format.js
end
end
will look for /app/views/some/hello.js.erb; // at least in Rails v. 2.3.
If you do specify block:
respond_to do |format|
# that will mean to send a javascript code to client-side;
format.js { render
# raw javascript to be executed on client-side
"alert('Hello Rails');",
# send HTTP response code on header
:status => 404, # page not found
# load /app/views/your-controller/different_action.js.erb
:action => "different_action",
# send json file with #line_item variable as json
:json => #line_item,
:file => filename,
:text => "OK",
# the :location option to set the HTTP Location header
:location => path_to_controller_method_url(argument)
}
end
I believe this was the url you were looking for:
https://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to
This might also be helpful to some, to see that you can actually render js directly within the format.js method, if you for example only have a small one line js statement you want to return, and you don't want to defer to a RJS file like controller_action_name.js.erb:
respond_to do |format|
format.html { redirect_to new_admin_session_path }
format.js { render :js => "window.location='#{ new_admin_session_path }'" }
end