Rails showing series of objects with form_for and Ajax - javascript

I'm trying to show a list of "Interests" that users can "follow" by clicking on a button associated with the Interest's image. Upon clicking the button to follow an Interest, the Interest (and it's corresponding image) should disappear from the list.
I'm using a hide function in a create.js.erb file called upon by a Relationship controller when the follow button is clicked, but the function will only hide the first Interest in the series of Interests--NOT the Interest the user clicked on that needs to disappear. So there has to be a better way to set this up, but I cannot, for the life of me, figure it out. Here's my current setup:
My Controller
class StaticPagesController < ApplicationController
def home
#user = current_user
#city = request.location.city
#interests = Interest.all
end
The home page
<%= render #interests %>
The partial
<div id="follow_form">
<div class="four columns portfolio-item interests">
<div class="our-work">
<a class="img-overlay">
<%= image_tag interest.image_path %>
<div class="img-overlay-div">
<h4><%= interest.name %></h4>
</br>
<h5>Placeholder
</br>
<%= interest.desc %></h5>
<%= form_for(current_user.relationships.build(followed_id:
interest.id), remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "I'm interested", class: "b-black" %>
<% end %>
</div>
</a>
<h3><%= interest.name %><span>features info</span></h3>
</div>
</div>
</div>
And the create.js.erb that's called upon by a Relationships controller when you click the button:
$("#follow_form").hide();
UPDATE
Here is the Relationships controller for additional clarification
def create
#interest = Interest.find(params[:relationship][:followed_id])
current_user.follow!(#interest)
respond_to do |format|
format.html { redirect_to(root_url) }
format.js
end
end

You need to provide something to differentiate the different "follow_forms" that you have on the same page. Otherwise, jQuery will just select the first element and only remove that one.
One idea of how to do this would be to append the "interest.id" to the end of the follow_form id
Update your partial to be like this (assuming your partial is called and located in /app/views/interests/_follow_form.html.erb:
<div id="follow_form<%="#{interest.id} %>">
<div class="four columns portfolio-item interests">
<div class="our-work">
<a class="img-overlay">
<%= image_tag interest.image_path %>
<div class="img-overlay-div">
<h4><%= interest.name %></h4>
</br>
<h5>Placeholder
</br>
<%= interest.desc %></h5>
<%= form_for(current_user.relationships.build(followed_id:
interest.id), remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "I'm interested", class: "b-black" %>
<% end %>
</div>
</a>
<h3><%= interest.name %><span>features info</span></h3>
</div>
</div>
</div>
This way each follow_form will have a unique ID attached to it. Then you can loop through your interests and call a partial on each one like this:
home page:
<% #interests.each do |interest| %>
<%= render 'interests/follow_form', :interest => interest %>
<% end %>
create.js.erb
$("#follow_form_<%= "#{#interest.id}" %>").hide())
Your controller action can stay the same.

Related

Ruby on Rails on rendering with Ajax

I am working on a simple website which has posts in forms of songs, now I have implemented like and dislike feature, but when I click on like/dislike it renders the numbers of likes/dislikes on all posts. And when I reload the page it returns them to normal. Now I would like it to change only the numbers for that particular post, without affecting the numbers on other posts?
My view for posts:
<div class="col-6">
<% for #s in #songs %>
<div class="card border-secondary mb-1">
<div class="card-header">
<div class="col-1">
<%= image_tag User.find(#s.user_id).user_image.url, :size=>"50x50" %>
</div>
<div class="col-11 text-muted">
<a href="/user/<%= User.find(#s.user_id).username %>" class="info-col">
<%= User.find(#s.user_id).username %>
</a>
- <%= #s.created_at.to_formatted_s(:short) %>
</div>
</div>
<div class="card-body">
<h4 class="card-title">
<%= #s.title %>
</h4>
<p class="card-text"><%= simple_format(#s.content) %></p>
</div>
<div class="card-footer text-muted">
<div class="col-12">
<div class="row">
<div class="col-3" id="song_like">
<%= render '/components/song_like' %>
</div>
<div class="col-3" id="song_dislike">
<%= render '/components/song_dislike' %>
</div>
<div class="col-4" id="song_comment">
<%= render '/components/song_comment' %>
</div>
</div>
</div>
</div>
</div>
<% end %>
</div>
The song_like partial has the following code:
<%= link_to like_song_path(#s.id, like: true), remote: true, method: :post do %>
<i class="fa fa-thumbs-o-up fa-lg" aria-hidden="true"></i> &nbsp <span class="songlikes">
<%= #s.thumbs_up_total %>
</span>
<% end %>
The song_dislike partial has the following code:
<%= link_to like_song_path(#s.id, like: false), method: :post, remote: true do %>
<i class="fa fa-thumbs-o-down fa-lg" aria-hidden="true"></i> &nbsp <span class="songdislikes">
<%= #s.thumbs_down_total %>
</span>
<% end %>
And my 'like' controller is like:
def like
#s = Song.find(params[:id])
#like = Like.create(like: params[:like], user: current_user, song: #s)
respond_to do |format|
if #like.valid?
format.html
format.js
else
format.html
format.js
end
end
end
This is how like.js.erb looks like:
$('.songlikes').html("<%= #s.thumbs_up_total %>");
$('.songdislikes').html("<%= #s.thumbs_down_total %>");
Here is the part of routes.rb file:
resources :songs do
member do
post 'like'
end
end
I am assuming there is some issue on rendering or jquery, but can't figure it out. Do You have any instructions?
EDIT: You should remove the redirect_to in your f.html?
This reloads the page - and the js will therefore not work.
An Ajax call is per definition not reloading the page.
If you remove those lines and try the following:
There's no new data in your jQuery.
You need a global attribute, so the view can find the data from your controller.
For example:
#like = ...
Then in your view you can add a local to be rendered:
$("#song_like").load("<%=j render partial: '/components/song_like', locals: {like: #like} %>");
But, you need to change your partial to be a partial. And change the variable to like so it will be rendered in the right way.
Hope it helps!
UPDATE
If you want to hit a specific song you can render it with each and then assign an id to your post's class
For example:
<% #posts.each do |post| %>
<div class="post-content">
... other stuff ...
<div class="likes like-post-<%= post.id %>">
.. number of likes
</div>
<%= link_to "Like", link_route_path(post) %>
</div>
<% end %>
# controller
# So you can use the id in your js view
#id = params[:id]
# view.js
$(".like-post-" + "<%= #id %>").html("<%= #s.thumbs_up_total %>");
Hope the idea helps.
change rendering like this:
<div class="col-3" id="song_like">
<%= render partial: '/components/song_like', locals: {s: #s, like: true} %>
</div>
then in partial:
<%= link_to like_song_path(s.id, like: like), method: :post, remote: true do %>
<i class="fa fa-thumbs-o-up fa-lg" aria-hidden="true"></i> &nbsp <%= s.thumbs_up_total %>
<% end %>
and in controller of like_song
should define
#s= Song.find(params[:id])
like = Like.create(like: params[:like], user: current_user, song: #song)
#like = !like.like # opposite to your current status
rest of the things good and then in like.js.erb
$('#songs_like').html("<%= escape_javascript(render partial: '/components/song_like', locals: { s: #s, like: #like } ) %>")

JQuery Input Rails Form

I have a search form on my page with two buttons - "news" and "events".
I can get the Rails search function to work correctly but I don't want a search form, I want the user to press one of the two buttons and the search to be executed.
I figure this probably has to be done with JQuery so when a button is clicked, either "news" or "events" are added to the rails input form and it submits the form. Please appreciate where I'm going wrong here as the form won't submit and the search won't execute.
Application.js
$(document).on('ready page:load', function () {
$(".news-button").click(function(){
$("#search").val("news");
$("#news-search").submit();
});
$(".events-button").click(function(){
$("#search").val("event");
$("#news-search").submit();
});
});
Index.html.erb
<%= form_tag news_index_path, :method => 'get', :id => "news_search" do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>
<div class="col-sm-3 sort-buttons">
<%= link_to "News", "", class: "btn btn-standard news-button" %>
<%= link_to "Events", "", class: "btn btn-standard events-button" %>
</div>
<div class="row">
<% #news.each do |n| %>
<div class="col-sm-4">
<div class="news-wrap">
<%= image_tag("#{n.image}", class: "img-responsive", alt: "Event/News Postings") %>
</div>
</div>
<% end %>
</div>
News.rb
class News < ApplicationRecord
if Rails.env.development?
def self.search(search)
if search
where('category LIKE ?', "%#{search}%")
else
scoped
end
end
end
end
News Controller:
def index
if params[:search]
#news = News.search(params[:search]).page(params[:page]).per_page(10)
else
#news = News.all.page(params[:page]).per_page(10)
end
end

remove comment from view using AJAX rails

I have a directory app that has comments. I add and delete comments with remote: true and I want to fade them out in my view with Jquery.
How do I go about getting a reference to the comment I want to fade out in the view? I can delete the comment just fine, but I don't know how to fade the comment out in my view
Here is my controller:
class CommentsController < ApplicationController
def create
business = Business.find(params[:business_id])
new_comment = business.comments.create
new_comment.comment = params[:comment_text]
new_comment.save
respond_to do |format|
format.html {redirect_to business}
format.js
end
end
def destroy
business = Business.find(params[:business])
comment = Comment.find(params[:id])
comment.destroy!
params[:id] = business.id
respond_to do |format|
format.html {redirect_to business_url(id: params[:id])}
format.js
end
end
end
Comments are rendered in my business view like this:
<aside class="comment-section">
<h4 class="thin-grey-underline"><span class="glyphicon glyphicon-comment glyphicon-left-space"></span> Reviews </h4>
<% if !#business.comments.empty? %>
<% #business.comments.each do |comment| %>
<div id="comments">
<%= render partial: 'comment', locals: {comment: comment, business: #business} %>
</div>
<% end %>
<% else %>
<p> No reviews yet... </p>
<% end %>
<%= render partial: 'comments_form' %>
</aside>
my single comment partial:
<div class="row single-comment vertical-align">
<div class="col-sm-12 col-md-3">
<div class="profile-image" style="background: url('<%= business.profile_image_url(:thumb).to_s %>') no-repeat; background-position:center"></div>
</div>
<div class="col-sm-12 col-md-9">
<h5><%= comment.title %></h5>
<p><%= comment.comment %></p>
<%= button_to(business_comment_path(#business.id,comment.id), {method: :delete, remote: true, class:"btn btn-danger delete-comment-button pull-right", params:{id: comment.id, business: business.id}} ) do%>
<i class="glyphicon glyphicon-trash"></i>
<% end %>
</div>
</div>
the form partial to create a new comment:
<div class="row">
<div class="col-sm-12 col-md-12">
<div class="comments-form">
<%= form_tag(business_comments_path(#business), html: { id: "comment-form" }, method: 'post', remote: true) do %>
<h5 class="thin-grey-underline"><span class="glyphicon glyphicon-pencil glyphicon-left-space"></span> Write a Review </h5>
<%= text_area_tag(:comment_text,nil, class: "comment-form-input")%>
<%= hidden_field_tag 'business_id', params[:id] %>
<%= submit_tag("Comment", class:"btn btn-primary") %>
<% end %>
</div>
</div>
</div>
If I have a list of comments, how do I delete a specific comment by clicking on the delete link and also have it removed from my view in a fadeout manner?
I have a destroy.js.erb file that gets called, but I don't know how to get a reference to fade out the specific comment.. not sure if I am explaining myself clearly here
You could try something like this:
In your comment partial:
<div id="comment_<%= comment.id %>" class="row single-comment vertical-align">
destroy.js.erb:
$('#comment_<%= #comment.id %>').remove();
Knockoutjs can do that The "if" binding
First step is to make sure that the thing you want to delete has a unique id, and that this id is easy to generate. I patched AR::Base with an instance method called dom_id for this, which is like so:
def dom_id
"#{self.class.name.underscore}-#{self.id}"
end
which means if i'm rendering out a list of Foo objects i can do something like
<%= render :partial => "foos/foo", :collection => #foos %>
and in the partial do this
<li id="<%= foo.dom_id %>">
....
</li>
and the id will be something like "foo-123".
Now, in my destroy.js.erb action, after deleting a foo object, i know that it's dom id on the page can be got with #foo.dom_id. To fade it out and delete it i would then do
page << "$('##{#foo.dom_id}').fadeOut('slow', function(){$(this).remove();});"
You can use helper dom_id method (docs):
Change <div id="comments"> to <div id="<%= dom_id comment %>"> or add id attribute to div.single-comment
In js response do $('#<%= dom_id #comment %>').fadeOut();
Another option is to bind to jQuery event like this:
$('body').on('ajax:success', '.delete-comment-button', function(event) {
$(event.original_target).closest('.single-comment').fadeOut();
})
Then you can just return status 2XX for the delete request

Rendering a partial to an edit form inside a popover in rails 4

Hi guys I really need help here.
I'm making a todo app and displaying each task through an iteration. Next to each task I have a pencil glyphicon.
When I click on it, I want there to be a popover containing an edit form and edit the task on the spot. I'm having a ton of troubling rendering that form.
***** UPDATE *****
Clark helped me get the popover to work. But The form inside the popover is acting like a link instead of a form so I can't type in the text area.
This is my index.html.erb
<div id='user_tasks'>
<% #tasks.each do |task| %>
<ul>
<li>
<%= task.description %>
<%= link_to edit_task_path(task), :rel => 'popover', method: 'get', remote: 'true' do %>
<span class = 'edit_task_<%=task.id%> glyphicon glyphicon-pencil'> </span>
<% end %>
</li>
</ul>
<% end %>
</div>
This is the edit.js.erb
$(function(){
$('.edit_task_<%=#task.id%>').popover({
html: true,
title: 'edit',
content: <%= escape_javascript render 'edit_form', task:#task %>
}).popover('show'); });
and my controllers look like this:
def index
#new_task= Task.new
#tasks= Task.all
end
def create
#new_task= Task.new(task_params)
#task.save
redirect_to :back
end
def edit
#task= Task.find(params[:id])
end
_edit_form.html.erb looks like this: This isn't the edit form that I plan to use. Its just a copy of the create task form. I plan to fix it once I get the popover working.
<%= form_for task, :html=>{:class=> 'form-inline'} do |f| %>
<div class='form-group'>
<%= f.text_field :description, placeholder: 'create a task' %>
<%= button_tag(type:'submit', class:"btn btn-default btn-xs") do %>
<span class='glyphicon glyphicon-plus'></span>
<% end %>
</div>
<% end %>

Follow button using AJAX only updates first div

I have a _user.html.erb partial that I am rendering on my Users#Index action with a form embedded to allow following and unfollowing of each user. I also have accompanying create.js.erb and destroy.js.erb files in my relationships controller to handle the AJAX. Right now I have to refresh the page in order to see the changes made by clicking the "follow/unfollow" button next to a users name except the first user's record behaves correctly.
_user.html.erb
<div id ="follow_form">
<% if current_user.following?(user) %>
<%= form_for(current_user.relationships.find_by(followed_id: user.id),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
<% else %>
<%= form_for(current_user.relationships.build(followed_id: user.id),
remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= #user.followers.count %>')
destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= #user.followers.count %>')
here is a link to my users_controller.rb https://gist.github.com/anonymous/9608208 and my relationships_controller.rb https://gist.github.com/anonymous/9608284
I've tried changing the div to something dynamic like
<div id ="follow_form_<%= user.id %>">
But when I make the same change to the javascript like this
$("#follow_form_<%= user.id %>").find.html("<%= escape_javascript(render('users/unfollow')) %>")
it doesn't seem to work.
I've been trying to figure out how to pass the user.id attribute into the javascript but am falling flat.
It turns out the problem was in my _follow_form.html.erb partial.
I had to change
<div id="follow_form">
to
<div id="follow_form_<%= #user.id %>">
I thought I only needed to make the change in the _user.html.erb partial but I was wrong. My current user partial uses the same div id to contain the button in the Users#Index view
<div id ="follow_form_<%= user.id %>">

Categories