Link_to remote:true not rendering a partial - ruby-on-rails

Trying to get a flash message and render a partial on an ajax call with link_to and remote:true
I have in my controller examples.rb:
def create
* Some stuff happens *
respond_to do |format|
format.js
format.html do
flash[:notice] = "Works!"
redirect_back(fallback_location: root_path)
end
end
end
I have the "link_to" form in _one_partial.html.erb
<%= link_to examples_path(whatever: locals[:whatever]), class: "whatever", method: :post, remote: true do %>
<div class="whatever_vix">
<p> Click Here! </p>
</div>
<% end %>
which is in a view as:
<div id="addhere">
<%= render 'favorites/one_partial', locals: {whatever: #whatever} %>
</div>
and in create.js.erb
$('#addhere').append("<%= j render 'whatever/another_partial' %>")
The ** some stuff happens ** part in my controller obviously works, but the new partial in create.js.erb doesn't show, neither the flash message appears once I add remote:true to the "link_to" form

Related

Rails partial not refreshing with create action

I realize there are dozens of similar questions here on this topic, I have looked through many of them and tried to duplicate the solutions and nothing has worked for me.
I have a list of tasks displayed in the index view as a partial, when the user adds a task I would like list to show the newest task (as well as all the others already there).
Here is the create controller:
def create
#task = current_user.tasks.build(task_params)
if #task.save
flash[:success] = "Task added"
respond_to do |format|
format.js
end
else
flash[:error] = "Task not added"
render 'new'
end
The _new partial:
<%= form_for(#task, method: :post, remote: true) do |f| %>
<%= f.label :comments %>
<%= f.text_field :comments, id: "task-comments" %>
<%= f.submit "Insert" %>
<% end %>
Index.html.erb
<div id="new-task-form">
<%= render 'new' %>
</div>
<div id="current-tasks">
<%= render partial: 'show_list', locals: {tasks: #tasks} %>
</div>
create.js.erb
console.log("create.js.erb called");
document.getElementById("task-comments").value = "";
document.getElementById("current-tasks").html('<%= j(render partial: "show_list") %>');
I have been able to get the console to log the message and even been able to clear the input box but the partial does not render, I have tried this in a few different ways and the script always seems to stop executing when it gets to the escape javascript line.
There are no JS errors, as stated above, the console logs the message when the "submit" button is pressed. There is a warning [Violation] Forced reflow while executing JavaScript took 114ms but I don't think that is relevant to this issue.
Here is the partial that I am trying to render _show_list.html.erb
<% unless #tasks.nil? %>
<ul>
<% tasks.each do |tsk| %>
<li><%= tsk.comments %></li>
<% end %>
</ul>
<% end %>
def create
#task = current_user.tasks.build(task_params)
if #task.save
flash[:success] = "Task added"
#respond_to do |format|
#format.js
#end
else
flash[:error] = "Task not added"
render 'new'
end
end
It's always good practice to use local variable in partial
1) => Index.html.erb
<div id="new-task-form">
<%= render 'new' %>
</div>
<div id="current-tasks">
<%= render partial: 'show_list', locals: {tasks: #tasks} %>
</div>
2) => If you are using jquery (create.js.erb)
console.log("create.js.erb called");
$("#task-comments").val('');
$("#current-tasks").html('<%= j render "show_list", tasks: #tasks) %>');
3) => _show_list.html.erb(Use tasks instead of #tasks)
<% unless tasks.blank? %>
<ul>
<% tasks.each do |tsk| %>
<li><%= tsk.comments %></li>
<% end %>
</ul>
<% end %>
ok you have some problem here with your validation on the show_list partial.
you have this line
<% unless #tasks.nil? %>
try to use something more readable like
<% if #tasks.present? %>
and on your controller create action, you don't fill the #tasks variable, so that's the problem in reality, add on you controller the load for all the tasks after saving the new one.
if #task.save
#tasks = Task.all
flash[:success] = "Task added"
and that will make it work, but I recommend to load just the created one and add just one column to the table and not update the complete list again if you have all the others on the client already.

My Ajax call returns js.erb file as the response in the browser. How do I make it return json contents, but also execute the js.erb file?

I'm new to Ruby on Rails and trying out an application. My application does Ajax calls correctly, but the response is shown as a js.erb file in the browser. How do I show a json response while executing the js.erb file? Is it possible or is there a better way?
Thank you.
My Controller File
def new
#department = Department.new
# respond_to do |format|
# format.html
# format.json {render json: #department}
# end
end
def create
#departments = Department.all
#department = Department.create(department_params)
respond_to do |format|
format.html
format.js {render json: #department}
end
end
Controller
My Form Partial
<div class="modal-dialog">
<div class="modal-content">
<%= form_for #department, remote: true, data: {type: :json} do |f| %>
<div class="modal-body">
<h2> Department: </h2>
<ul class="errors"></ul>
<div class="form-group">
<%= f.label :title, class:"control-label" %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :body, class: "control-label" %>
<%= f.text_field :body, class: "form-control" %>
</div>
</div>
<div class="modal-footer">
<%= f.submit class: "btn btn-primary .departmentCreate" %>
<%= link_to "Cancel", "#", class: "btn", data: {dismiss: "modal"} %>
</div>
<% end %>
</div>
</div>
Form.html.erb
My Json Response if I keep format.js {render json: #department}
Json Response
My Response if I remove render json from controller:
JS response
My new.js.erb File
$("#department-modal").html("<%= escape_javascript(render 'departments/new') %>")
$("#department-modal").modal("show")
My _new.html.erb partial :
<%= render "form" %>
My create.js.erb file:
<%= render 'save' %>
My _save.js.erb partial:
$("ul.errors").html("")
<% if #department.errors.any? %>
<% #department.errors.full_messages.each do |message| %>
$("ul.errors").append($("<li />").html("<%= message.html_safe %>"))
<% end %>
<% else %>
$(".department-index").html("<%= escape_javascript(render 'departments/index') %>")
$("#department-modal").modal("hide")
While rendering the json response in browser, the js.erb file doesn't execute. How can I show json response in browser while js.erb file executes?
Thank you :)
How can I show json response in browser while js.erb file executes?
Thank you :)
If I understood correctly what you are asking, the answer is you can't. Your response's Content-Type will be either an application/json or an application/javascript.
The browser will use this header to handle the response.
The reason your JavaScript is not executing is because you have a block present in your controller that handles the response. So the code will never reach your JavaScript file.
Change the line:
format.js { render json: #department }
to:
format.js
This will tell Rails that you accept JavaScript request, and since no block is specified the template in "app/views/departments/create.js.erb" is used.
If you don't want to render the default template you can specify it in the block like so:
format.js { render: :new } # renders app/views/departments/new.js.erb
or:
format.js { render: 'some/path' } # renders app/views/some/path.js.erb
Instead of nested rendering of js.erb direct render template from controller with full path. assuming full path of _save.js.erb is departments/save
Also #departments should be calculated after create new department so that newly created record will be added with #departments
def create
#department = Department.create(department_params)
#departments = Department.all
render template: 'departments/save'
end
Its always a good practice to pass local variables with partial:_
$("ul.errors").html("")
<% if #department.errors.any? %>
<% #department.errors.full_messages.each do |message| %>
$("ul.errors").append($("<li />").html("<%= message.html_safe %>"))
<% end %>
<% else %>
$(".department-index").html("<%= j render 'departments/index', departments: #departments) %>")
$("#department-modal").modal("hide")
You cannot render both as such, but you can render the partial on the server side, and store the result in the JSON. On the client side, you can process JSON, and extract and use the rendered HTML snippet in JS code.
Syntax in Jbuilder for rendering a partial :
json.some_key json.partial! 'my_partial.js.erb'
So the stack is something like..
Controller
# Render the JSON partial in views
respond_to do |format|
format.json {}
end
View - controller action will call default json builder for action e.g views/departments/new.json.jbuilder
In here render any original JSON you wanted, like #department, but also render the required JS partial and store it in the JSON
json.department #department
json.department_form json.partial! 'new.js.erb'
Then in the client code that receives the JSON, for example as data, the partial will be present under key department_form, and you can assign the rendered form, to an html placeholder element in your original view
//... ajax call to your controller#action
dataType: "json",
success: function(data) {
$("#department_form_placeholder").html(data['department_form'])

render a partial on ajax:success in coffeescript in rails 5

I am trying to render a partial after ajax call using coffee script but could not make it.
Controller which is called on AJAX request
def unfollow
#user = User.find(params[:follow][:followed_id])
current_user.unfollow!(#user)
render json: {result: "success"}
end
partial: User/follow.html.erb
<div id="follow_button">
<%=form_for(:follow,url: follow_users_path,remote:true) do |f| %>
<%= f.hidden_field :followed_id, value: #user.id %>
<%= f.submit "Follow", id: "Follow_button", class: "btn btn-primary" %>
<% end %>
</div>
Ajax:success function
$ ->
$('#unfollow_button').on "ajax:success", (e,data,status,xhr) ->
$('#follow_unfollow_button').html("<%= escape_javascript( render partial: 'users/follow') %>")
HTML which is on That place
<div id="unfollow_button">
<%=form_for(:follow,url: unfollow_users_path,remote:true) do |f| %>
<%= f.hidden_field :followed_id, value: #user.id %>
<%= f.submit "Unfollow", id: "unfollow_button", class: "btn btn-primary" %>
<% end %>
</div>
I am not getting any value from the server I just want to render it when ajax success. But it render like this
<%= escape_javascript( render partial: 'users/follow') %>
How to solve this? what am I missing?
Yeah you can't render an erb partial inside javascript from a json response like that. Here's how to fix
1) remove this line from the controller
render json: {result: "success"}
2) In views/users/ create a file called unfollow.js.coffee with the following code
$('#follow_unfollow_button').html("<%= j render('users/follow') %>")
3) You no longer need to bind to ajax success function so delete this code completely from wherever you had it
$ ->
$('#unfollow_button').on "ajax:success", (e,data,status,xhr) ->
$('#follow_unfollow_button').html("<%= escape_javascript( render partial: 'users/follow') %>")
Don't try to render it from the coffeescript in this case. Instead, render the result from controller and return that as data to ajax.
1) Change controller method to
def unfollow
#user = User.find(params[:follow][:followed_id])
current_user.unfollow!(#user)
render 'users/follow', :layout => false
end
2) Change JS function to
$ ->
$('#unfollow_button').on "ajax:success", (e,data,status,xhr) ->
$('#follow_unfollow_button').html(data)
As your controller will return something (and not an error), the ajax:success will fire up and instead of trying to render it in JS/coffeescript, just render it in controller and that way, you also don't need to render something just for the sake of returning information to client.

can't refresh a rails html div with ajax

the following renders "2" in the div as it should when a form is submitted.
full brands/create.js.erb version 1:
$("#brand_ajax").html("1")
$("#brand_ajax").html("0")
$("#brand_ajax").html("2")
partial brands/show_brands.html.erb
The div I want to refresh
<% for brand in #brands%>
ID: <%= h brand.id %>
<% end %>
partial cars/show.html.erb
The ajax call
<%= form_for([#car, #car.brands.build], **remote: true**) do |f| %>
<%= f.fields_for :brandsdo |a| %>
<%= a.text_field :name, placeholder: "New Manufacturer" %>
<% end %>
<%= f.submit "+", class: "btn inline" %>
<% end %>
**/*The div I want to refresh*/**
<div id="brand_ajax">
<%= render 'brands/show_brands' %>
</div>
The brands controller
respond_to do |format|
if #brand.save
format.html { redirect_to #car }
format.js
else
flash[:notice] = "Error!"
format.html { redirect_to #car }
end
end
the following does not render "2" after submitting a new brands form - does not refresh at all. just shows the old version of
'show_brands'.
full brands/create.js.erb (to illustrate)
$("#brand_ajax").html("1")
$("#brand_ajax").html("<%= escape_javascript render 'show_brands' %>")
$("#brand_ajax").html("2")
any ideas why such a thing should happen?
Try
$("#brand_ajax").html("<%= j render :partial => 'show_brands' %>")

Ruby on Rails: Deleting a post with Ajax in navigation and showing the following

Thanks for reading!
So I'm relatively new to RoR (Rails 5) and I try to render posts of a user in a partial (_posts_panel.html.erb) which contains another partial: the navigation (_posts_navigation.html.erb). I'm using ajax to show the posts when clicked on in the navigation which is working fine.
Now I want to use it for deleting a post. The post is destroyed when I click on the button and I managed to remove it in navigation.
What is not working:
the next post should be shown in the panel after the deletion
when there is no post left I want to reload the panel because another partial (_posts_empty.html.erb) should be rendered
My Code:
_posts_panel.html.erb: (it is rendered in show.html.erb of user)
<% if #user.simple_posts.empty? %>
<%= render 'simple_posts/shared/posts_empty' %>
<% else %>
<div id="post-navigation">
<%= render 'simple_posts/shared/posts_navigation' %>
</div>
<%= simple_posts_edit_button(current_user, #simple_post)%>
<%= simple_posts_delete_button(current_user, #simple_post)%> #button helper
<div id="show_post">
<%= render #simple_post %>
<%= yield %>
</div>
<%end %>
_posts_navigation.html.erb
<div class="bootstrap-vertical-nav">
<ul class="nav flex-column">
<% #user.simple_posts.reverse_each do |post|%>
<li class="nav-item" id="<%= #simple_post.id %>">
<%= link_to post.title, user_simple_post_path(#user, post), remote: true, class:"nav-link text-dark" %>
</li>
<% end %>
</ul>
</div>
<% if #user.id == current_user.id %>
<%= link_to "+ New Post", new_user_simple_post_path(current_user), class: "btn btn-info w-100", role: "button" %>
<% end %>
destroy.js.erb
$('li#<%= #simple_post.id %>').remove();
simple_posts_controller.rb
def destroy
#simple_post.destroy
#simple_post =current_user.simple_posts.first
respond_to do |format|
# format.html { redirect_to simple_posts_url, notice: 'Simple post was successfully destroyed.' }
format.js
end
end
I tried to append in destroy.js.erb the same code from showing the post $('#show_post').html("<%= escape_javascript render #simple_post %>"); but it's not working correctly. When deleting the first post (but only that one) the next one is shown but the post is not removed from the navigation. I also tried $('#post-navigation').html("<%= escape_javascript render partial: 'simple_posts/shared/posts_navigation' %>"); and it nothing happens.
Also I tried to reload the whole panel with $('#post-panel').html("<%= escape_javascript render partial: 'simple_posts/shared/posts_panel' %>");in show.html.erb of user but again: nothing. I'm not sure if I have to specify in which view or partial exactly it has to render the partial.
I don't really know how to approach this further.
Edit 1
ButtonHelper.rb
def simple_posts_delete_button(current_user, simple_post)
if(current_user.id == #user.id)
link_to svg('x-square'), [current_user, simple_post], remote: true, method: :delete, class:"btn"
end
end
Edit 2
show-action from simple_posts_controller.rb
def show
#user = User.find{params[:id]}
#simple_post = SimplePost.find(params[:id])
respond_to do |format|
format.js
format.html # show.html.erb
end
end
show.js.erb
$('#post-actions').html("<%= j render partial: 'simple_posts/shared/posts_actions', locals: {simple_post: #simple_post, user: #user} %>");
$('#show-post').html("<%= j render #simple_post %>");
There are several problems with your partials:
First, to remove the post from your navigation you just need to update the partial, the post is already destroyed/removed at this point.
After destroy, #simple_post in your button helper is not updated with ajax and still comes from the users_controller (where you set it the first time i presume)
You can put your action buttons inside a new partial and specify the locals.
You can also wrap the html inside a main div for the last update (when all the posts are deleted)
_posts_panel.html.erb:
<div id="panel">
<% if #user.simple_posts.empty? %>
<%= render 'simple_posts/shared/posts_empty' %>
<% else %>
<div id="post-navigation">
<%= render partial: 'simple_posts/shared/posts_navigation', locals: { simple_post: #simple_post } %>
</div>
<div id="post-actions"> #<-- new partial
<%= render partial: 'simple_posts/shared/posts_actions', locals: { simple_post: #simple_post } %>
</div>
<div id="show_post">
<%= render #simple_post %>
<%= yield %>
</div>
<% end %>
</div>
_posts_actions.html.erb:
<%= simple_posts_edit_button(current_user, simple_post)%>
<%= simple_posts_delete_button(current_user, simple_post)%>
Note that you are not using the instance variable #simple_post anymore but the local one.
Now you can write your js like this:
destroy.js.erb:
<% if #simple_post %> //<-- check if "#simple_post = current_user.posts.first" still exists after destroy
$('#post-navigation').html("<%= j render partial: 'simple_posts/shared/posts_navigation', locals: { simple_post: #simple_post } %>");
$('#post-actions').html("<%= j render partial: 'simple_posts/shared/posts_actions', locals: { simple_post: #simple_post } %>");
$('#show_post').html("<%= j render #simple_post %>");
<% else %>
$('#panel').html("<%= j render partial: 'simple_posts/shared/posts_empty' %>");
<% end %>

Resources