Using Javascript with Rails to display alert dialogs using Bootbox - javascript

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>

Related

rails change the background of my like button when clicks on it :

I'm in the last step of my rails application (instagram-clone ) , and the issue is when i click on heart logo the count of number of likes upgraded from 0 to 1 but , i can't find the solution to change the background color of my logo to "red" when i click on it, this is my logo image
this is my vote.js.erb:
<% if current_user.liked? #post %>
$(".like-button").addClass("liked");
<% else %>
$(".like-button").removeClass("like-button");
<% end %>
$(".likes-count").html(" <%= #post.get_upvotes.size%> ")
#i want to modify this lines to change the background color of my heart logo to red when the count of likes was upgraded from 0 to 1 and thanks a lot
this i s my like button code lines :
<%= link_to like_post_path(post), class:"like-button", method: :put, remote: :true do %>
<div>
<i class="fas fa-heart fa-2x"></i>
</div>
<% end %>
<span class="likes-count"><%= post.get_upvotes.size %></span>
Ok here is your option.
There could be many stories/photos you might be looking and scrolling through the list.
Here is the fix that suit this kind of scenarios.
Some changes in vote.js.erb:
<% if current_user.liked? #post %>
$(".like-button-<%= #post.id %> .fas").addClass("liked");
<% else %>
$(".like-button-<%= #post.id %> .fas").removeClass("liked");
<% end %>
$(".likes-count").html(" <%= #post.get_upvotes.size%> ")
As you are using icon, Somewhere in the style add css similar to below.
.liked {
color: red;
}
And some changes in your html button
<%= link_to like_post_path(post), class: "like-button-#{post.id}", method: :put, remote: :true do %>
<div>
<i class="fas fa-heart fa-2x <%= 'liked' if current_user.liked?(post) %>"></i>
</div>
<% end %>

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 } ) %>")

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

ajax form and partials

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

dynamic page caching in rails

How to add dynamic caching to time or I should use fragment caching?
I tried to follow RailsCasts but nothing works.
_feed.html.rb
<% cache feed do %>
<div class="feed">
<div id="time">
<%= render 'shared/time' unless #page_caching %>
</div>
<p class="pull-right grey"><%= time_ago_in_words(feed.posted_at) %></p>
<div class="clearfix">
<p class="grey"><%= image_tag feed.profile_pic, :class => 'pic', :size => '15x15' %> #<%= feed.name %></p>
</div>
<p class="content"><%= raw auto_link(feed.content, :username_include_symbol => true, :target => '_blank') %></p>
</div>
<% end %>
_time.html.rb
<p class="pull-right grey"><%= time_ago_in_words(feed.posted_at) %></p>
index.js.rb
$('#feeds').append('<%= j render(#feeds) %>');
<% if #feeds.next_page %>
$('.pagination').replaceWith('<%= j will_paginate(#feeds) %>');
<% else %>
$('.pagination').remove();
<% end %>
$('#time').prepend('<%= j render("shared/time") %>');
feeds_cotroller.rb
def index
#page_caching = true
#feeds = Feed.page(params[:page]).per_page(12)
end
using helpers that changes over time should not be used inside a cache block. The best solution to this is to use a js plugin that will insert the time string for you. google for timeago js plugin and you'll get a bunch of useful results. The first result there is in http://timeago.yarp.com/. Using that plugin, your code should look like the following (i've inserted a script which should insert the time string)
<% cache feed do %>
<div class="feed">
<div id="time">
<%= render 'shared/time' unless #page_caching %>
</div>
<p class="pull-right grey timeago" title="<%= feed.posted_at %>"></p>
<script>
jQuery(document).ready(function() { jQuery("p.timeago").timeago() })
</script>
<div class="clearfix">
<p class="grey">
<%= image_tag feed.profile_pic, :class => 'pic', :size => '15x15' %> #<%= feed.name %>
</p>
</div>
<p class="content"><%= raw auto_link(feed.content, :username_include_symbol => true, :target => '_blank') %></p>
</div>
<% end %>
This is a simple implementation. You probably want to move the js call to an asset file so you dont have to call it inside the cache. Anyway, this should give you an idea.

Categories