rails - Handling Layout content_for with AJAX - ruby-on-rails

I have a an application layout template with:
<%= yield(:railed) %>
To handle contact in the right rail (right column 300px). In the actualy DEF SHOW page I use:
<%- content_for(:railed) do -%>
HTML STUFF goes here
<%- end -%>
The issue I'm having now is that for one of my controllers, Im using AJAX to hit DEF Show, and inject the content into the page. This work fine expect for it doesn't get the railed content as the layout template isn't being used in the format.js response.
So what's a smart way I can get the railed contet display with the AJAX request, and not have to write to separate pages for AJAX & Non-AJAX (direct URL).
Thoughts? I know some Rails genius has figured this out already :)
My controller:
def show
#thing = Thing.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.js
end
end
show.js.erb:
<%= render :partial =>"thing/show" %>

It's a bit of a hack but this is how I did it in rails 3.1 with haml and jquery:
show.html.haml:
- if request.xhr?
#content_for_sidebar.hidden
=#view_flow.get(:sidebar)
ajax_callbacks.js:
$("#nav a[data-remote]").live('ajax:complete', function(status, xhr) {
$($(this).attr('rel')).html(xhr.responseText);
$('#sidebar').html($("#content_for_sidebar").html());
$("#content_for_sidebar").remove();
});

Related

Rails form_tag remote example

I have this incredible simple form:
<%= form_tag("/portal/search", method: 'get', remote: true ) do %>
<%= label_tag(:query, 'Search for:') %>
<%= text_field_tag(:query) %>
<%= submit_tag("Find") %>
<% end %>
<div id="results"></div>
I know from the documentation, I can use AJAX through the remote option:
<%= form_tag("/portal/search", method: 'get', remote: true ) do %>
Then I get stuck. I know how to generate results in a view/partial, but how do I get that partial inside the div element? I know a bit of JQuery, so I can select the element. I found a lot of results, but they seem to miss that lightbulb moment for me. I am using Rails 4.1.6
My results are just simple records from a model, like Book (title, author)
Thank you for helping!
EDIT
I've won the cup for missing the point by a long shot. I had to add the search.js.erb inside the view folder instead of assets.
Let's say you get #results out of your search method.
In the controller, search method:
respond_to do |format|
format.html {render or redirect_to wherever you need it}
format.js
end
Then all you need is a file named search.js.erb to run the required js at the end of your request. It might look something like:
$('#results_div').html("<%= j #results.pluck(:title).join('<br/>') %>")
When you add remote: true jquery-ujs will provide you the ajax request (by default this javascript lib is required in app/assets/javascripts/application.js).
The ajax call will request a 'text/javascript' response. for that reason your server code should reply with:
# action
def search_query
respond_to do |format|
format.js {
# additional code
}
end
end
If in your view (search_query.js.erb) you provide javascript, it will be executed. That is why everyone is replying you with a $('#my_div_id').html('my html text') suggestion, which when executed will replace your div content with the new HTML.
If for some reason you want to return a json data structure, then you should provide a different data-type:
form_tag("/jquery_ujs/search_query", remote: true, 'data-type' => :json) do
# ....
end
And you should reply with:
# action
def search_query
respond_to do |format|
format.json { render json: #my_object }
end
end
And handle the success event:
<script>
$(document).ready(function(){
$("form#my_form").on('ajax:success', function(event, data, status, xhr) {
console.log("Great!");
// use data to access to your json data structure
});
$("form#my_form").on('ajax:error', function(event, xhr, status, error) {
console.log("sorry mate!");
});
// ....
})
</script>
You can also request a html response (in case you want to return a table, for instance), with :'data-type' => :html and format.html { render layout: false }
Ajax
Firstly, the Rails UJS (unobtrusive javascript) driver just gives you a "canned" way to send an ajax request to your browser. To avoid confusion, it's best to appreciate that you will be sending Ajax requests regardless of whether you use Rails UJS or the standard Ajax method
This means that the process of capturing the response from your Ajax is still the same - you need to make sure you have to catch the response from the system
Either :-
#app/assets/javascripts/application.js
$(document).on("ajax:success", ".element", function(status, data, xhr) {
// do something here
});
or
#app/controllers/portal_controller.rb
class PortalController < ApplicationController
def search
respond_to do |format|
format.js #-> app/views/portal/search.js.erb
format.html
end
end
end
#app/views/portal/search.js.erb
//something here
Fix
how do I get that partial inside the div element
You'll be able to use JS:
#app/controllers/portal_controller.rb
class PortalController < ApplicationController
def search
#results = ...
respond_to do |format|
format.js
format.html
end
end
end
#app/views/portal/search.js.erb
$(".div").html("<%=j render #results %>");

Render partial in rails controller called using ajax

I have rails application where I have part of views as partials and I re-factored couple of views as SPA. I have problem with one functionality. In one place I was rendering partial without calling controller like following:
def create
school_service.update_preview
#user = get_user
#result = prepare_result
render 'school/result/show', locals: {
pupil: #user,
result: #result
}
end
I was calling this method using form. Now I call this from JS using AJAX. Is it possible to render that view in the same way? I wouldn't like to rewrite 'school/result/show' to SPA. Thanks for all answers.
Your question says I was calling this method using form. Now I call this using AJAX. Is it possible to render that view in the same way?
Since you are using AJAX i assume you'll have something remote: true in your form something like:
<%= form_for(#user, remote: true) do |f| %>
# your fields
<% end %>
This will take you to the create action in your controller and you can have a respond_to block in your controller to handle your js format
def create
#user = get_user
#result = prepare_result
respond_to do |format|
format.js {}
end
end
This will allow you to have create.js.erb file in your views where you can write your js to render your partial
$(".your_parent_element_class").html("<%=j render partial: "school/result/show",locals:{pupil: #user, result: #result} %>")
For more details checkout working with javascript in rails

Rails AJAX - don't redirect or render

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

jquery ajax render partial with rails view

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 %>')

Rendering js.erb Layout but html.erb view file

When app gets javascript request it renders application.js.erb and index.js.erb by default, but i want to use index.html.erb and application.js.erb. How can i achieve that?
I want to use :
Application.js.erb + index.html.erb instead of
Application.js.erb + index.js.erb
add .html to end of partial name you want to render.
Example:
<%= render :partial=>'some_partial.html' %>
Instead of:
<%= render :partial=>'some_partial' %>
In your controller code you could
def index
#get records and whatnot
respond_to do |format|
format.html # index.html.erb
format.js { render :action=>:application }
end
end
Note: I don't know why you are doing this, but this will work. I recommend working within the rails standards.

Resources