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>   <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>   <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>   <%= 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 } ) %>")
Related
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
I'm new to Rails and have been trying to display a success message when signing successfully to a website. I've been trying to use bootbox.js to display messages that are stored within a ruby hash once sign in is successful - unfortunately I am even newer to Javascript and when I create a successful sign in I can't get any of the bootbox content to display. The code below shows where I want to display the message.
<div class="sidebar pull-left">
<!-- sidebar -->
<div class="col-xs-6 col-sm-3 sidebar-offcanvas" id="sidebar" role="navigation">
<div class="list-group">
<span class="fa-stack fa-lg">
<i class="fa fa-square-o fa-stack-2x"></i>
<%= link_to '', root_path, class: "fa fa-home fa-fw fa-stack-1x" %>
</span>
<span class="fa-stack fa-lg">
<i class="fa fa-square-o fa-stack-2x"></i>
<%= link_to '', help_path, class: "fa fa-question fa-fw fa-stack-1x" %>
</span>
</div>
</div>
</div>
<div class="main-content">
<%= content_tag :div, class: "flash_messages", data: {flash: flash} do %>
<% end %>
<% content_for :alert do %>
<script type="text/javascript">
<%= render 'users/show_flash_messages.js' %>
</script>
<% end %>
<% flash.each do |key, value| %>
<%= yield :alert %>
<% end %>
<%= yield %>
</div>
I use
<%= content_tag :div, class: "flash_messages", data: {flash: flash} do %>
<% end %>
to pass the data inside the hash to a javascript array on the client.
The ruby hash is initialised in the controller here:
def create
#user = User.new(user_params)
if #user.save
# sign_in #user
flash[:success] = "Welcome!"
redirect_to #user
else
render 'new'
end
end
I then created a method in users.js.coffee which I hoped would display the alert using the bootbox alert dialog by taking the required information from the js array:
Messages = flashMessage: (flash) ->
flash_message = flash[1]
bootbox.alert flash_message
return
I wrote this in javascript and then used a converter to convert it to coffeescript (should this work?). I then have a rails javascript file named _show_flash_messages.js.erb where I call into the flashMessage function.
$(function() {
messages = $('.flash_messages').data('flash');
Messages.flashMessage(messages);
});
I've been able to display the information in a bootstrap alert however my preference is to use these bootbox dialogs to display the information. Like I said I'm new to Rails and this is my first attempt at properly integrating javascript so it is likely that I am missing something obvious.
For reference this is the HTML for the page that the dialog will hopefully be displayed on top of:
<% provide(:title, #user.name) %>
<div class="center hero-unit">
<div class="user-profile">
<span class="user-header">
<%= gravatar_for #user %>
<h2>
<%= #user.name %>
</h2>
</span>
<span id="page-content">
<p>
This is where a short biography will go.
</p>
</span>
</div>
</div>
I have successfully added comments to public activity i.e after i followed this tutorial on public activity #406 Public Activity and i will like the comments to be submitted by ajax, i have tried every tutorial out and does not work my codes so far includes
for the comments controller this is what its like
def create
#activity = Activity.find(params[:activity_id])
#comment = #activity.comments.create!(comment_params)
#comment.user = current_user
#users= User.joins(:comments).where(talks: {id: #activity.talk_ids}).push(#comment.user).reject {|user| user == #comment.user }.uniq
#users.each do |user|
#comment.create_activity :create, owner: user
end
respond_to do |format|
format.html { redirect_to user_path(current_user), notice: 'Comment created.' }
format.js
end
end
end
for the partial i created for each activity is like this e.g
<div class="media social-box">
<a class="pull-left social-users-avatars" href="#">
<%= link_to image_tag(activity.user.image.url(:small)) ,activity.user%>
<p><%= link_to activity.user.username, activity.user if feed.activity %>
<span style="font-size: 11px; color:#4edee1;">Added this item </span> </p>
</a>
<ul class="unstyled custumer_say">
<li class="clearfix" style="list-style: none">
<%= link_to image_tag(sell.image.url,:style=> "width: 40%; padding-right: 10px;", :class=> "pull-left img_client"), sell%>
<div class="entry-content">
<header>
<span class="entry-date">— <%="#{time_ago_in_words(sell.created_at)} ago "%> </span>
</header>
</div>
</li>
</ul>
<div class="media-body social-body">
<div class="social-footer">
<div class="social-info-users">
<strong><%= pluralize(activity.comments.size, "Comment") %></strong>
</div>
<div class="social-comments">
<ul id="chat">
<%= render activity.comments %>
</ul>
<% if current_user.friends.present? %>
<div class="media">
<a class="pull-left" href="#">
<%= image_tag(current_user.image.url(:tiny),:style=> "width: 100%;")%>
</a>
<div class="media-body">
<%= form_for([activity, activity.comments.build],:remote => true) do |f| %>
<%= f.text_field :details, :class=>"input-block-level", :placeholder=>"write a comment" %>
<% end%>
</div>
</div>
<% end %>
</div>
</div>
</div>
</div>
all i want to achieve is update this css id
<ul id="chat">
<%= render activity.comments %>
</ul>
also my create.js.erb is something like this
$("#chat").append('<%= j render(activity.comments) %>');
$("#new_comment")[0].reset();
note, for some reasons this is how my partial is rendered out
<%= render activity.comments %> instead of the famous `<%= render #activity.comments %>`
which the other is working properly, and also the whole code is displayed on the current_users showpage e.g users/1 page
Several issues:
#comment.user = current_user
Where does #comment get initialized? It looks like you're calling a variable which doesn't exist, unless you've called it in a before_action callback?
Are you getting any errors? It's hard to go through masses of code without any guidance on what the issue may be. You need to post up some responses / logs from your app to show us how it's dealing with the requests
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.
1) This is my Login page:
<% provide(:title, 'Sign In') %>
<div data-role="page" data-url="/signin/">
<h1>Sign In</h1>
<%= form_for(:session, url: sessions_path) do |f| %>
<div>
<%= f.text_field :username_or_email, placeholder: "username or email", autofocus: true %>
</div>
<div>
<%= f.password_field :password, placeholder: "password" %>
</div>
<div>
<%= f.submit "Sign In", rel: "external" %>
</div>
<% end %>
</div>
2) This is my Home page after login:
<% provide(:title, #user.name) %>
<div data-role="page" id="home" data-url="/users/<%= #user.id %>/" >
<div data-role="header">
Menu
<h4>Home</h4>
<%= link_to 'New', new_pin_path, rel: "external" %>
</div>
<% if !#user.pins.any? %>
<h3>Welcome to Pins!... Enter your first pin.</h3>
<% end %>
<%= render #user.pins %>
</div>
<div data-role="page" id="menu">
<div class="ui-grid-a center">
<div class="ui-block-a menublock">
Home
</div>
<div class="ui-block-b menublock">
<%= link_to 'Friends Pins', pins_path %>
</div>
<div class="ui-block-a menublock">
<%= link_to 'Settings', edit_user_path(current_user) %>
</div>
<div class="ui-block-b menublock">
<%= link_to "Sign Out", signout_path, method: "delete" %>
</div>
</div>
</div>
So basically, after I log in and try clicking on Menu I get no response (unless I refresh the page).
3) This is how my session login works:
I was going to paste it but it's super long, I basically used the same thing that is going on here:
http://ruby.railstutorial.org/chapters/sign-in-sign-out#top
4) Trailing slashes (this is a requirement by jQuery Mobile): I thought my problem may be because I did not have trailing slashes set on all the urls, so I added this to my application.rb: config.action_controller.default_url_options = { :trailing_slash => true } And although it fixed a lot of the navigation between pages, it does not fix the issue after my session log in.
5) Also note that when I refresh the home page after login, the navbar does work correctly.
You are missing a "data-rel" tag. Try the following:
Menu