Long story short, I have a button. On clicking it, I want an ajax request to be triggered which gets flash[:notice] and displays it in a div in$
Here is my shortened view:
<input type="button" id="search" value="display"/>
<div id="notice">
</div>
My ajax request in the view:
$("#search").submit(function(){
$.ajax({
type: "POST",
url: //url to my show action
success: function(data){
/*$("#notice").html("<%= flash[:notice] %>");
$("#content").html(data);*/
}
});
return false;
});
My controller:
def HomeController < ActionController::Base
def index
end
def show
respond_to do |format|
format.js { flash[:notice] = "" + count.to_s + " results found for " + params[:query][:search_key] + "" }
end
#render :partial => 'search'
end
end
My show.js.erb
#app/views/dashboard_home/show.js.erb
$("#notice").html("<%=j flash[:notice] %>");
$("#content").html("<%=j render partial: "search" %>");
The problem is when I click on button, the notice is displayed fine. But the same notice persists on the next clicks too. The search partial contains the table Please help!
Here is an example that I got working, thanks to Rich Peck's answer. I needed to use flash.now to make sure the flash notice didn't persist.
AJAX trigger in the view:
<%= link_to "Email report", users_path, remote: true %>
Controller:
# app/controllers/users_controller
class UsersController < ApplicationController
def index
# do some things here
respond_to do |format|
format.js { flash.now[:notice] = "Here is my flash notice" }
end
end
end
Rendered view:
# app/views/users/index.js.erb
$("#flash").html('<%= j render partial: "shared/notice_banner" %>');
where the flash notice is displayed in the layout:
# app/views/layouts/application.html.erb
<div id="flash">
<% if notice.present? %>
<%= render partial: "shared/notice_banner" %>
<% end %>
</div>
# app/views/shared/_notice_banner.html.erb
<div data-alert class="alert-box">
<%= notice %>
×
</div>
Sessions
the same notice persists on the next clicks too
This is caused by the flash being stored in the session variable of Rails:
The flash is a special part of the session which is cleared with each
request. This means that values stored there will only be available in
the next request, which is useful for passing error messages etc.
The problem you have is that since I don't think ajax counts as a new request (need reference for this), the data will persist into the next time you request via HTTP.
--
Fix
I would initially try this:
def show
respond_to do |format|
format.js { flash[:notice] = "my secret number "+rand(0,5)+" !" }
end
end
The main problem you have is you're processing the flash variable in your JS using the ERB preprocessor. This is an issue as it means you won't be able to use asset precompile to help it work.
After looking at this question, why not try using the after_filter callback, like this:
#app/controllers/home_controller.rb
Class Home < ActionController::Base
after_filter { flash.discard if request.xhr? }, only: :show
def show
respond_to do |format|
format.js { flash[:notice] = "my secret number "+rand(0,5)+" !" }
end
end
end
--
Update
You should include the success functionality in your show.js.erb:
#app/views/home/show.js.erb
$("#notice").html("<%= flash[:notice] %>");
This means you can remove the whole ajax call from the application.js, and replace with the remote: true for your search form:
#app/views/search/index.html.erb
<%= form_tag home_show_path, remote: true %>
The reason this works is because when you use the format.js respond block, Rails will load the [action].js.erb file in your views. Considering this only happens after the action has been completed, it's equivalent to the success function of your ajax.
By doing this, you'll be able to remove the entire ajax function from your application.js, and replace with the UJS version, as described above
Related
i'm working through a tutorial to get a rails partial to display stock information using ajax. Everything is working properly and in the console I can see that the div has been updated properly, but it isn't being displayed. Here's the relevant code.
CONTROLLER
class StocksController < ApplicationController
def search
if params[:stock].present?
#stock = Stock.new_from_lookup(params[:stock])
if #stock
puts "should be working"
respond_to do |format|
format.js { render partial: 'users/result' }
end
else
puts "incorrect symbol"
flash[:danger] = "You have entered an incorrect symbol."
redirect_to my_portfolio_path
end
else
puts "nothing"
flash[:danger] = "You need to type something, what did you expect to happen?"
redirect_to my_portfolio_path
end
end
end
AJAX JS ERB
$('#results").html("<%=j (render 'users/result.html')%>")
The result of the partial is
<%if #stock%>
<div class = "well results-block">
<strong>Symbol:</strong><%= #stock.ticker%>
<strong>Name:</strong><%= #stock.name%>
<strong>Last Price:</strong><%= #stock.last_price%>
</div>
<%end%>
Let me know if there's more info you need. I'm using Rails 6.
You might want to check https://guides.rubyonrails.org/layouts_and_rendering.html#partial-layouts . You should try dropping 'partial' or add 'locals' or 'object' to render method.
all of the following render calls would all render the edit.html.erb template in the views/books directory:
render :edit
render action: :edit
render "edit"
render action: "edit"
render "books/edit"
render template: "books/edit"
You can pass an object in to this local variable via the :object option:
<%= render partial: "customer", object: #new_customer %>
In your case,
format.js { render 'users/result' }
Instead of using
$('#results").html("<%=j (render 'users/result.html')%>")
Did you try to use
document.querySelector('#results').innerHTML = '<%= j render 'users/result.html' %>'
This works fine for me.
I've a users list and I want to delete elements on click of a "delete" link on the same line.
Views:
# users/index.html.erb
<ul class="users">
<%= render #users %>
</ul>
# users/_user.html.erb
<li id="user-<%= user.id %>">
<%= link_to user.email, user %>
<% if current_user.admin? %>
<%= link_to "delete", user, remote: true, method: :delete, data: { confirm: "You sure?" } %>
<% end %>
</li>
Users Controller:
# users_controller.rb
def destroy
User.find(params[:id]).destroy
flash[:success] = "User deleted"
respond_to do |format|
format.html { redirect_to users_url }
format.js
end
end
The javascript to delete the list element is:
# users/destroy.js.erb
$("li#<%= user.id %>").remove();
On click nothing happen, but on page refresh the resource is correctly destroyed. Checking server's LOG I see the following error:
Completed 500 Internal Server Error in 40ms (ActiveRecord: 5.0ms)
ActionView::Template::Error (undefined local variable or method user'
for #<#<Class:0x0000000851d300>:0x00000008e8e7e0>):
1: $("li#<%= user.id %>").remove(); app/views/users/destroy.js.erb:1:in
_app_views_users_destroy_js_erb___2066095411338793994_74738360'
app/controllers/users_controller.rb:46:in `destroy'
Can you pls help me to understand where the error is and why 'user' is undefined? Thanks
edit
I know there are many q&a similar to this question, and I actually build my code consulting these questions. Still, I'm stuck and I need support. Pls do not mark the question as duplicate.
your destroy.js.erb template is not getting the user variable, as it is undefined. try:
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.js
end
end
and
$("li#<%= #user.id %>").remove();
the reason this works is because rails passes data from controller to view by setting variables with # prefix. so you set #user to an instance of the model you grabbed from the database, then you called .destroy on that model, and it got deleted, and then you rendered your destroy.js template which had #user in it as well, and you deleted the list item matching the 'li#233' selector or whatever the id integer was
You're not defining an user variable.
You would save your #user_id in a variable to be accessible in your js.erb. Like that:
def destroy
#user_id = params[:id]
...
end
And then:
$("li#<%= #user_id %>").remove();
I'm trying to render boxes_list by clicking Link_to. Don't know why its not working.
# Routes.rb
resources :modifications do
collection do
get 'refresh'
end
end
# ModificationsController
def refresh
respond_to do |format|
format.js {}
end
end
# link in /views/modifications/_boxes_list.html.erb that should refresh boxes_list
<%= link_to "refresh", refresh_modifications_path(#modification), remote: true, method: :refresh %>
# JS responce in /views/modifications/refresh.js.erb
$('#boxes_count').html("<%= escape_javascript(render( :partial => 'boxes_list' )).html_safe %>");
In server console I see nothing when press this link. Link is on Modifications show page under regular show action. Rails 4!
You firstly should remove method: :refresh from your link_to (you don't need it):
<%= link_to "refresh", refresh_modifications_path, remote: true %>
You also don't need to provide an object if you're using collection routes. If you used a member route, you'd have to pass the object.
--
To save the hassle of trying to pick through the code, here's what you should have:
#config/routes.rb
resources :modifications do
get :refresh, on: :member #-> url.com/modifications/:id/refresh
end
#app/controllers/modifications_controller.rb
class ModificationsController < ApplicationController
respond_to :js, only: :refresh
def refresh
end
end
#app/views/modifications/refresh.js.erb
$('#boxes_count').html("<%=j render partial: 'boxes_list' %>");
You'd send the request as follows:
<%= link_to "Refresh", refresh_modification_path(#modification), remote: true %>
Why you put the method: :refresh. Remove the method: :refresh from the link. Your route should be
resources :modifications do
member do
get :refresh
end
end
Then your path should be
<%= link_to "refresh", refresh_modification_path(#modification), remote: true %>
And in `refresh' action
def referesh
#modification = Modification.find(params[:id])
respond_to do |format|
format.js{}
end
end
Source Adding More RESTful Actions
So I am trying to do an AJAX request in my form_tag. Basically, a user can enter a song name or an artist's name and I want to simply post what they searched for into a playlist (very simply here)
These are my files:
My form
<%= form_tag({:action => 'capp'}, method:'GET', class: 'ui form', remote: true , id: 'song_form') do %>
<div class="one field">
<div class="field" style="width: 100%">
<%= text_field_tag :query %>
</div>
</div>
<%= submit_tag("Search Song" , class: 'ui large green button') %>
<% end %>
Where I am trying to put the query entered
<div id="query"></div>
My 'app' Controller which has that action
class AppController < ApplicationController
respond_to :html, :js
def create
passcode = params[:passcode]
if passcode != nil && passcode.length > 1
redirect_to :controller => app, :action => capp, :passcode => passcode
end
end
def capp
#passcode = params[:passcode]
#query = params[:query] <-- I used pry and the query was being updated but the view itself was not.
if #query != nil
respond_to do |format|
format.html
format.js {}
end
end
end
end
My capp.js.erb file
addSongToPlaylist("<%= #query %>");
// For the record. I tried to also do this:
// addSongToPlaylist("<%= j render #query %>"); <-- But the app errored out saying render was an undefined method name...and all the online tutorials have their function rendering for some reason.
My capp.js file
function addSongToPlaylist(query) {
var c = "</br>" + query;
$("#query").append(c);
}
All I am hoping for is that the query I entered in the form above be placed in the
location below. But the as soon as I hit submit, the application doesn't do anything. the request goes through (I can see the server sending the GET request) but the view doesnt update. Please help!
I followed the tutorial on doing AJAX calls and for some reason it's still not working
Firstly, why aren't you using a path helper for your form_tag?
You'd benefit from using the likes of:
#config/routes.rb
get "/search/:query", to: "application#search", as: :search
This will allow you to use the following:
<%= form_tag search_path, remote: true, method: :get %>
<%= text_field_tag :query %>
<%= submit_tag "Search" %>
<% end %>
This will send a get request to your /search/:query path, which you'll then be able to process with your JS (explained in a second):
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
respond_to :html, :js
def search
#passcode = params[:passcode]
#query = params[:query]
end
end
This should handle the request for you, looking to open app/views/application/search.js.erb
--
JS
For sake of clarity, let's just put the function into your called JS file:
#app/views/application/search.js.erb
$("#query").append("<br> <%=j #query %>");
This will do what your addSongToPlaylist function is doing.
Considering you've populated the #query variable, and are passing the ajax properly, this should work.
Debug
One of the main problems you'll have is that you're not debugging your application.
In this instance, there are a number of potential issues which could prevent your Ajax from firing:
Your ajax isn't being passed (IE JQuery is not loaded)
Your path is incorrect
Your controller isn't handling the request properly
You're not handling the JS correctly
The way to initially test is to look at the network tab of your browser's developer console:
To access it, right-click, inspect element, then select network. This will give you a list of all the requests you've sent to your server, and their responses.
When you click your "form submit" button - check to see whether a new request is invoked. If not, it will generally mean you don't have jquery in your app (which is required by the Rails UJS).
--
Next, you need to check your Rails console to see if you're getting any requests. If not, it will not show anything coming through.
What you're expecting is to see a new set of commands triggered when you submit your "search" form. This will show you which controller#action has been triggered. If it's right, move forward.
--
Finally, you need to check your JS.
You can do this by using alerts:
#app/views/application/search.js.erb
alert("<%=j #query %>");
$("#query").append("<br> <%=j #query %>");
If the alert fires positively, you've got a hit.
So I have a link/button that looks like this in my helper class:
link_to "UnFav", unfavorite_node_path(node), class: "btn btn-success favorite", method: :post, remote: true, data: { toggle_text: 'Fav', toggle_href: favorite_node_path(node), id: node.id }
That calls these methods in my controller:
def favorite
#node.liked_by current_user
if request.xhr?
render json: { count: #node.get_likes.size, id: params[:id] }
else
redirect_to #node
end
end
def unfavorite
#node.unliked_by current_user
if request.xhr?
render json: { count: #node.get_likes.size, id: params[:id] }
else
redirect_to #node
end
end
I am using acts-as-votable.
In my view, I show the number of votes on a particular node like this:
<span class="card-favorite-count">
<i class="icon-heart"></i> <%= node.cached_votes_total %>
</span>
Ideally, what I want to happen is, when one of those links are pressed, and the action is successfully executed, I want to update the count that is already being shown in the DOM.
I tried creating a favorite.js.erb and putting this in it:
$(".card-favorite-count").html('<%= node.cached_votes_total %>');
But I realized that when I favorited & unfavorited an item, in my server logs it never ever called that favorite.js.erb template - so this never gets executed.
I was also looking for a callback on the gem, but I can't find any.
What's the best way to approach this?
To render your file favorite.js.erb you need to do:
def favorite
#node.liked_by current_user
respond_to do |format|
format.js
format.html{ redirect_to #node }
end
end
end
I think the if block would not be necessary still unsure but you can try the above code. It would respond with the js.erb when it is a js request and when it html request it will redirect.