Rails Ajax/Controller not properly updating my partial - javascript

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.

Related

How to render only js without html (template, layout) in Rails

I have controller Message_Controller and this Controller has method "message" in this method i wanna render .js.erb file i need call js function from rails controller.I need reneder it without html-template(layout) just only js-code in this code i will call js-function with args .How to make it ??
My routes:
post 'chat_bot/message', to: 'chat_bot#message'
My controller:
class ChatBotController < ApplicationController
layout false
def message
#gon.watch.message = params[:text]
#message = params[:text]
puts #message
render partial: 'message.js.erb', layout: false
end
end
my message.js.erb file
alert('<%=#message %>');
With
render partial: 'message.js.erb', layout: false
Rails is going to look for a partial called _message.js.erb right in the folder responding to that controller.
You can use respond_to and there specify the format and what to render:
def message
respond_to do |format|
format.html { render partial: 'message.js.erb' }
end
end
You can skip the instance variable assignation if you prefer, as you have access to the params within the request.
If your idea is to "evaluate" the alert, then it still should be inside a script tag:
<script>
alert("<%= params[:text] %>");
</script>
just update it with
def message
#message = params[:text]
respond_to do |format|
format.js
end
end

Controller not rendering show.js.haml during AJAX

I'm making a simple AJAX call from a from_tag (search box) and want to show the results without refreshing page. The issue is that even though I can see in server console that the show action is being processed as JS, it still renders the HTML and not the js.haml file. The only way I'm getting controller to render js is by changing name to show.js . It then works as it should. show.js.erb doesn't work either. I've also tried format.js {render layout: false} without any luck. It seem to be an problem on the controller side but I might be wrong here. Any ideas appreciated!
Edit:
The controller action is working using the render "show.js.haml" option. The other issue is that escape_javascript doesn't do anything in below js.haml file.
show.js.haml
$("#main").html("#{escape_javascript(render 'artists/show', locals: {artist: #artist, updates, #updates, reach: #reach, reach_diff: #reach_diff})}");
controller
class ArtistsController < ApplicationController
def index
if params[:search]
#artist=Artist.find_by(name: params[:search])
redirect_to action: "show", id: #artist.id
else
#artists= Artist.all
end
end
def show
#artist= Artist.find(params[:id])
#updates = #artist.updates.order(created_at: :desc)
#reach = #artist.reachupdates.order(created_at: :desc)
#reach_diff= Reachupdate.last_week_diff(#artist.id)
respond_to do |format|
format.html
format.js {render "show.js.haml", layout: false}
end
end
end
You need to change render layout: false to render 'show.js.haml', layout: false
def show
#artist= Artist.find(params[:id])
#updates = #artist.updates.order(created_at: :desc)
#reach = #artist.reachupdates.order(created_at: :desc)
#reach_diff= Reachupdate.last_week_diff(#artist.id)
respond_to do |format|
format.html
format.js {render 'show.js.haml', layout: false}
end
end
Update:
The next issue I'm having is to insert ruby objects to the js file
If the file 'articles/show' is a partial file then the problem is the locals keyword should be used along with partial keyword in order to work. Try changing this
$("#main").html("#{escape_javascript(render 'artists/show', locals: {artist: #artist, updates, #updates, reach: #reach, reach_diff: #reach_diff})}");
to
$("#main").html("#{escape_javascript(render partial: 'artists/show', locals: {artist: #artist, updates, #updates, reach: #reach, reach_diff: #reach_diff})}");
Or
Just remove locals
$("#main").html("#{escape_javascript(render 'artists/show', artist: #artist, updates, #updates, reach: #reach, reach_diff: #reach_diff)}");

Rails - delete li element with Ajax

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();

RoR 4 form_tag AJAX request issue

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.

Rails flash notice via ajax

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

Categories