Can render javascript from controller but can't render .js file - ruby-on-rails

I have a button that submits a form remotely with Ajax using the rails built in helpers:
button_to 'Delete Document', [:proofreader, proofreading_job, proofread_document],
method: :delete,
remote: true,
class: "btn btn-danger btn-sm",
data: { disable_with: "Deleting document..." }
When the form is submitted to the controller I can cause an alert to show as follows:
def destroy
#proofread_document.destroy
respond_to do |format|
format.js { render js: "alert('The username to be displayed is:')"}
end
end
However when I want to render the destroy.js.erb file which has no code in it yet I get the following error in the browser:
def destroy
#proofread_document.destroy
respond_to do |format|
format.js
end
end
Uncaught SyntaxError: Unexpected token <
at processResponse (rails-ujs.self-ed0b535c2816e34ce8dee0346bd17387dffd4873cb347fa9a8b267dae6f7f41b.js?body=1:257)
at rails-ujs.self-ed0b535c2816e34ce8dee0346bd17387dffd4873cb347fa9a8b267dae6f7f41b.js?body=1:186
at XMLHttpRequest.xhr.onreadystatechange (rails-ujs.self-ed0b535c2816e34ce8dee0346bd17387dffd4873cb347fa9a8b267dae6f7f41b.js?body=1:241)
How can I fix this problem its stopped all development on this project.

the < charecter comes from layout file.
You can use layout: false with render.
def destroy
#proofread_document.destroy
respond_to do |format|
format.js {render layout: false}
end
end

Just use layout: false
def destroy
#proofread_document.destroy
respond_to do |format|
format.js { render js: "alert('The username to be displayed is:')", layout: false }
end
end
Worked fine:

Related

After submitting a remote form with Rails, how do I redirect the user to another page?

I’m using Rails 4.2.3. I want to submit a form in a modal dialog, so I have set up my form like so
<%= form_for #my_object, :remote => true do |f| %>
but if the user submits the form successfully, I would like to reload the page that invoked the modal dialog with a notice of “Saved Successfully.” I can’t figure out what I need to put in my “format.js” to make this happen. This is what I have in my controller so far …
def create
#my_object = MyObject.new(my_object_params)
#current_user = User.find(session["user_id"])
#my_object.user = #current_user
respond_to do |format|
if #my_object.save
format.html { redirect_to controller: "users", action: "index", notice: 'Saved successfully.' }
format.js { render action: ‘../users/index’, notice: ‘Saved Successfully’, location: #my_object }
else
format.html { render action: "index" }
format.js { render json: #my_object.errors, status: :unprocessable_entity }
end
end
end
Right now, a successful submission results in a 500 error complaining about missing partials when I try and execute the above. Pretty sure what I have is wrong anyway.
You can do the following:
#app/controllers/redirect.rb
...
format.js { render js: "window.location='#{url.to_s}'" }
...
If you like keeping things separated, just put format.js in your controller and do the javascript redirect in your view (redirect.js.erb)
In both cases, just set flash[:notice] to whatever you need before redirecting.
redirect_to events_path, format: 'js'
For this you will need to have events/index.js.erb in your file structure.
If you are redirecting anyway, you might as well avoid the remote/AJAX call, and just redirect from the create action.
<%= form_for #my_object do |f| %>
and
def create
#my_object = MyObject.new(my_object_params)
...
redirect_to some_path
end
If you have want to redirect it after successfully create/updated and just use .html method. Otherwise just use JS option like in this LINK.
def create
#my_object = MyObject.new(my_object_params.merge(user: User.find(session["user_id"])))
respond_to do |format|
if #my_object.save
format.html { redirect_to controller: "users", action: "index", notice: 'Saved successfully.' }
else
....
end
end
end
That will help you, from your controller
render :js => "window.location = '/jobs/index'"

Rails respond_to redirect not working

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.

Rails: render text gives missingtemplate error

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

serving javascript with rails

I have this code down here. When format.js fires I want to serve to the client a javascript file. How do I do that?
class LineItemsController < ApplicationController
def destroy
#line_item = LineItem.find(params[:id])
#line_item.destroy
respond_to do |format|
format.html { redirect_to line_items_url }
format.js {}
format.json { head :no_content }
end
end
I have a file called destroy.js.erb in the controller, but that doesn't run automatically. I tried many combinations but nothing seems to work...
what do I put inside format.js { ??? } to serve a javascript file I want? I don't want to write vanilla javascript.
To trigger your js-response of your destroy action try:
<%= button_to 'Remove', #line_item, method: :delete, remote: :true %>
For testing purpose make your destroy.js.erb as the following:
alert("Line item with id <%= #line_item.id %> has been removed");
You can leave your format.js w/o bracket (or with empty ones).

Rails 3 app doesn't redirect after AJAX form submission

I have an Authlogic login form with :remote => true that does a little inline validation with an RJS template if the user/password isn't valid. This works fine, but when the credentials are valid, it doesn't properly redirect elsewhere.
Here's the controller that responds to the form input:
class UserSessionsController < ApplicationController
respond_to :html, :js
before_filter :require_no_user, :only => [:new, :create]
before_filter :require_user, :only => :destroy
def new
#user_session = UserSession.new
end
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
flash[:notice] = "Login successful!"
format.html { redirect_to account_url }
else
format.js
end
end
end
def destroy
current_user_session.destroy
flash[:notice] = "Logout successful!"
redirect_to root_path
end
end
The format.js part works but if the user/password are good (format.html), nothing happens. However, if I look a development.log, it is requesting the account_url page. It's just not redirecting you in the browser. I think it's returning the account page via AJAX and I really just want a normal redirect.
The HTML for the form is this:
<%= simple_form_for(
:user_session, #user_session,
:url => { :controller => 'user_sessions', :action => "create" },
:html => { :id => 'login-dropdown' }, :remote => true) do |f| %>
I found a way to fix it. Per http://www.ruby-forum.com/topic/168406#945053, I added the following to my application controller:
def redirect_to(options = {}, response_status = {})
if request.xhr?
render(:update) {|page| page.redirect_to(options)}
else
super(options, response_status)
end
end
This prevents the redirect response from being delivered via xhr. If there's a more "correct" way of doing this in the controller, I'd like to hear it, though.
You can do like below :
in allpication.js
$(document).ready(function(){
$(document).ajaxError( function(e, xhr, options){
if("401" == xhr.responseText)
{
$(location).attr('href','/users/sign_in');
}
});
})
and controller's method has below code:
respond_to do |format|
format.html {redirect_to #new_user_session_url}
format.js { render :text=>'401' ,:status=>401}
end
But I think there is better way to do so....
app
views
user_sessions
create.js.erb(create file this)
in your create action add this code
def create
#user_session = UserSession.new(params[:user_session])
respond_to do |format|
if #user_session.save
flash[:notice] = "Login successful!"
#url = account_url
end
format.js
end
end
in your "create.js.erb"
window.location.replace(<%= #url %>);

Resources