I have my jquery ajax success as
success: function(data) {
$('#someId').html(data);
}
I have a partial file in the name of _information.html.erb
How do i render my ajax success response to rails partial view(information).
Most of the resources showing something like this
$('#holderDiv').empty().append('<ul> <%= j render #comments %> </li>')
But i didn't feel comfortable with it. Any other way to solve it.
UPDATE
Here's some more info in response to your comments.
First please read this Rails Guide on Javascript for more info.
update.js.erb is your view. Instead of having an update.html.erb file for your view, the respond_to block with format.js in your controller will send update.js.erb (formatted as javascript code) back to your jquery function.
update.js.erb could contain pure javascript. However it is processed by the server before being converted to javascript, so you can embed any ruby code you want. That ruby code gets converted into javascript.
If you use chrome developer tools, you can look in the "network" tab after your jquery call runs. You'll see a new entry appear for the AJAX call you just made. If you click on the entry, you'll see the javascript that was returned.
I've updated the update.js.erb file below slightly to show how you can put regular javascript code in the .js.erb file. The first line is javascript. The second line is ruby code which the server converts into javascript. So by the time that it gets to your browser, the entire update.js.erb file has been converted into javascript.
Hope that helps...
Original Answer Below:
Option 1:
Assuming that your jQuery success function is tied to the successful completion of a controller action (I'll use the edit action for my example), you would create a view called update.js.erb which will be called after a successful edit.
Controller:
if #user.update_attributes(params[:user])
respond_to do |format|
format.html { redirect_to #user, notice: "Successfully updated user." }
format.js
end
else
# ...
end
Because this is being called from javascript and you have format.js in the respond_to block, update.js.erb will automatically be called.
update.js.erb:
console.log('see... this is a regular javascript call.');
<%= render partial: 'information', format: 'js' %>
Option 2
The snippet you included:
$('#holderDiv').empty().append('<ul> <%= j render #comments %> </li>')
will only work in a js.erb file, where embedded ruby code is first processed then converted into javascript code. That would work in a situation such as:
Controller:
def create
user = User.new(params[:user])
respond_to do |format|
if #user.save
#comments = 'some comments to display!'
format.js
else
# ...
end
end
end
create.js.erb:
$('#holderDiv').empty().append('<%= j render #comments %>')
Related
Say, I have users list on the '/users' page and 2 actions for the 'user' entity: 'index' (with using of Ajax) and 'destroy'.
def index
...
respond_to do |format|
format.html
format.js
end
end
def destroy
...
redirect_to users_url
end
I want to destroy a user (right from the '/users' page) and use Ajax of the 'index' action after that ('index.js.erb' file) in order to render only a part of the opened '/users' page.
Is it possible to do that?
My current solution right now is to use Ajax for 'destroy' action (a separate 'destroy.js.erb' file) and duplicate needed changes for 'index' page there. But, first of all, it's a code duplication, and second, in this case my pagination links are broken (I use 'Kaminari' gem and looks like it works fine only with 'get' requests, at least by default).
There is a 'view' part of updating with Ajax, if necessary:
<div id="users_table">
<table class="table table-hover table-borderless">
...
<tbody>
<%= render #users %>
</tbody>
</table>
<div><%= paginate #users, remote: true %></div>
</div>
If you want the destroy action to render the index.js.erb:
def destroy
...
respond_to do |format|
format.js { render action: :index}
format.html { redirect_to users_url}
end
end
But, to render index.js you will need to, in your destroy action, rebuild the #users object and ensure you're rebuilding it for the correct page. So, when you call the destroy action you'll need to pass the ID(s) of the user(s) you want to destroy, as well as the page you are on.
Your destroy.js.erb should (on successful destruction) remove the destroyed element from the index by deleting a part of the HTML. I don’t expect that the code to do that duplicates the code you have in the index view.
Post your current destroy.js.erb as well as the relevant part of index.html.erb for more help though.
You can also use redirect within a respond_to so your HTML call will redirect while the Ajax uses destroy.js.erb
respond_to do |format|
format.js
format.html { redirect_to users_url}
You could also hack your way to your answer by calling render :index for the js response. But, if you were to try to render the index view here you’ll definitely get duplication of code, along with an extra DB call and probably some broken pagination. So, I’d recommend that you take the approach I first suggested (use destroy.js.erb to remove that user from the HTML)
Finally, more generally, when you’re trying to avoid duplication of view code; a partial might be the answer
I have table that is filled with data from an instance variable. How would I use Ajax to make a request and update the data within the table to reflect the new data for the instance variable?
As a general answer, Rails comes with some great helpers to make working with Ajax quite simple. I suggest reading up on the Rails Guides for in depth coverage on this topic.
To trigger a specific controller action via Ajax, you can do something like this:
Somewhere in your table view, where appropriate:
<%= button_to "Do Something!", [:your_action, #example], remote: true %>
Then in your target controller:
def your_action
#Do whatever you wish here
respond_to do |format|
format.html { redirect_to #example, notice: 'Action successfully performed.' }
format.js {}
end
end
The format.js in the respond_to block allows the controller to respond to the Ajax request. You can then create a respective app/views/examples/your_action.js.erb file that generates the JS that will be sent/executed on the client side:
$("<%= escape_javascript(render #example) %>").appendTo("#your-table-element");
I've just upgraded to Rails 4.1.
I previously had the following in a controller action, which worked perfectly.
respond_to do |format|
format.html { render html: #user, layout: "fullscreen" }
end
This is not working in Rails 4.1, and the page simply renders the object #<User:0x007fb087429a70>
Edit the controller as follows fixes this error.
respond_to do |format|
format.html
end
What is the correct way to set the layout in Rails 4.1. I'm having trouble finding this in the docs.
html option was added in render method in Rails version 4.1. See the issue listed here
When you tried
def action_name
## ...
respond_to do |format|
format.html { render html: #user, layout: "fullscreen" }
end
end
in a Rails version prior to v4.1, what really happened was render ignored the html option, picked up the layout and went ahead to look for a view named action_name.html.***(where *** refers to template handler like erb, haml, etc). It found the view and rendered it. If the view didn't exist then you would have received a Missing template error
And when you use the same code in Rails 4.1, as the html option is allowed in render method it will definitely be processed. Now, first you need to understand what the html option actually does:
You can send a HTML string back to the browser by using the :html
option to render:
render html: "<strong>Not Found</strong>".html_safe
You use this when you don't want to write an html file for your action and wish to simply render a HTML string.
Which is the reason when this particular action is called you now see an html page with object #<User:0x007fb087429a70> because you passed the value to html option as #user.
Edit the controller as follows fixes this error.
respond_to do |format|
format.html
end
Firstly, it was not an error. You misinterpreted what html option does. I am pretty sure you do have a view corresponding to your action which is what you expected to be rendered. The above code does that for you.
I suppose you simply wish to specify layout for your view. All you need to do is:
respond_to do |format|
format.html { render layout: "fullscreen" }
end
Using rails and .js.erb to make an AJAX request (and append values to a div), how do you prevent rendering a new layout? In other words, stay on the same page without going anywhere and just append the fresh data from the server in a div. No reloading the same page, no redirecting.
At the moment my controller looks like this
def update_shipping
#order = Order.find(params[:id])
#order.shipping_option_id = params[:shipping_options]
#order.save!
respond_to do |format|
format.js
format.html
end
end
and my form like zisss:
<%= form_tag update_shipping_order_path(#order), method: :put, remote: true do %>
<%= select_tag 'shipping_options', #options_for_select, onchange: 'this.form.submit()' %>
<% end %>
and my routes look like a so:
resources :orders do
member do
put :update_shipping
end
end
But I get a 'Template is Missing' error
Please help!!
You need to add a update_shipping.js.erb file under app/views/your_controller/ directory. Note the name of the javascript file should be same as the action. Since you have a remote:true in your form so rails will try to render a javascript template in your case update_shipping.js.erb.
Now in your update_shipping.js.erb file write some basic javascript to update the page elements like
#update_shipping.js.erb
$('.some-div').html(<%=j #model.some_value' %>)
Try this:-
respond_to do |format|
format.js { render :nothing => true }
format.html
end
If you don't want to render a layout, you can use !request.xhr? like so:
respond_to do |format|
format.html { layout: !request.xhr? }
format.js
end
If you're looking to get your ajax-powered JS to fire, you just need to call your .js.erb file the same as your view:
#app/views/controller/update_shipping.js.erb
alert("This JS is returned & fired after the Ajax request");
You'll be best doing this in your routes.rb too:
resources :orders do
put :update_shipping
end
A little late, I came across this searching for the same issue. It must of slipped out of my mind at some point while working with action cable, but what is needed is a http response code of no_content. Http response codes tell the browser how to act when a request is returned. Here is a link to a list of them, and their symbols in rails. More on 204 no content
Here is how it would look:
def update_shipping
#order = Order.find(params[:id])
#order.shipping_option_id = params[:shipping_options]
#order.save!
head :no_content #or head 204
end
edit: what solved the solution for me was a link provided by William Denniss in this stack overflow question
I have a CRUD application set up in Ruby on Rails 3 - its working as is. I need to add some ajax here. My first requirement is to retrieve a customised form when clicking on a New Form link. This is the link I have at this point:
<%= link_to 'New Book', new_book_path(:subject_id=>#subject.id), :remote=>true %>
For my controller I've made the following adjustment to the new book action:
def new
#book = Book.new
if params[:subject_id].to_i >0 then
#book.subject_id = params[:subject_id]
end
if request.xhr?
respond_to do |format|
format.html # new.html.erb
format.json { render json: #book }
render :layout => false, :file=>'app/views/books/_form'
return false
end
else
respond_to do |format|
format.html # new.html.erb
format.json { render json: #book }
end
end
end
I checked in firebug and clicking on the link generated returns the form html however I have no idea how to handle the response? Please do help.
Instead of responding with HTML respond with .js
Inside your .js.erb file could be something like this
$("#idname").append(<%= render "form" %>)
That way it renders and returns the form HTML but also gives the js code to append the HTML.
You can certainly rely on Rails generated JavaScript, but I always like to have "more control" over my JavaScript code. In e.g. jQuery you could have something like this (untested), if you want to insert the partial (html) rendered by your controller into the site:
$("#new-book-button").click( function () {
$.get('books/new', function(data) {
$('#some-form-container').html(data);
});
}