Implementing Ajax - Rails App - ruby-on-rails

I'm trying to implement ajax into when I favorite a place, but the reload/update of the section/ajax functionality doesn't work. Only if I reload the page, then I see the action that has occurred. Would appreciate any tips.
My favorite_places/show.html.erb
<div class="heart">
<p class="text-center">
<% if current_user %>
<%- unless current_user.favorite_places.exists?(id: #place.id) -%>
<%= link_to favorite_places_path(place_id: #place), remote: true, method: :post do %>
<span title="Favorite this Place"><i class="glyphicon glyphicon-heart-empty"></i></span>
<% end %>
<%- else -%>
<%= link_to favorite_place_path(#place), remote: true, method: :delete do %>
<span title="Un-Favorite this Place"><i class="glyphicon glyphicon-heart"></i></span>
<% end %>
<% end %>
<% end %>
</p>
</div>
My favorite_places_controller.rb
def update
#favorite_place.update_attributes[params[:place]]
respond_to do |format|
format.html { redirect_to #place }
format.js
end
end
My update.js.erb
<% if #place.favorited %>
$(' #<%= #place.id %>').html("true");
console.log ("<%= #place.name %> has been favorited.");
<% else %>
$(' #<%= #place.id %>').html("false");
console.log ("<%= #place.name %> is not a favorite.");
<% end %>
My dev console output
DELETE http://0.0.0.0:3000/favorite_places/34 406 (Not Acceptable)
jquery.js?body=1:8716send
jquery.js?body=1:8716jQuery.extend.ajax
jquery.js?body=1:8146$.rails.rails.ajax
jquery_ujs.js?body=1:73$.rails.rails.handleRemote
jquery_ujs.js?body=1:149(anonymous function)
jquery_ujs.js?body=1:299jQuery.event.dispatch
jquery.js?body=1:5108elemData.handle

Related

How to check if the current_user blocks the target user with Acts-as-Follower

I'm unable to check if the current_user is blocking the target user. I'm trying to create a toggle button for the block/unblock feature. I don't know how people were able to do it, unless their solution wasn't AJAX ready. How can I check if the current_user is following the target #user object?
_block_user.html.erb
<% # unless #user == current_user %>
<% **if current_user.blocking?(#user)** %>
<%= link_to(unblock_user_path(#user), :remote => true, :class => 'btn btn-outline-danger') do %>
<i class="fa fa-stop-circle"></i>
Unblock
<% end %>
<% else %>
<%= link_to(block_user_path(#user) ,:remote => true, :class => 'btn btn-outline-primary') do %>
<i class="fa fa-play-circle"></i>
Block
<%end%>
<% end %>
<% # end %>
If it's a button with AJAX you have to have something like that
<% if (!current_user.liked? #user) %>
<%= link_to like_user_path(#user), class:"like-btn", method: :put, remote: true do %>
<i class="fa fa-stop-circle"></i>
<% end %>
<% else %>
<%= link_to like_user_path(#user), class:"like-btn", method: :put, remote: true do %>
<i class="fa fa-play-circle"></i>
<% end %>
<% end %>
like.js.erb
<% if current_user.liked? #user %>
document.getElementsByClassName('like-btn')[0].className = "like-btn liked";
<% else %>
document.getElementsByClassName('like-btn')[0].className = "like-btn disliked";
<% end %>
controller/user
def like
if !current_user.liked? #user
#user.liked_by current_user
elsif current_user.liked? user
#user.unliked_by current_user
end
respond_to do |format|
format.html { redirect_back(fallback_location: root_path) }
format.js
end
end
My approach to finding out if a user is blocked. (tested without the current_user checker)
<% #unless #user == current_user %>
<div id="block_user<%= #user.id %>">
<% if current_user.blocks.include?(#user) %>
<%= link_to(unblock_user_path(#user), :remote => true, :class => 'btn btn-outline-danger') do %>
<i class="fa fa-stop-circle"></i>
Unblock
<% end %>
<% else %>
<%= link_to(block_user_path(#user), :remote => true, :class => 'btn btn-outline-primary') do %>
<i class="fa fa-play-circle"></i>
Block
<% end %>
<% end %>
</div>
<% # end %>

Following users on Ruby on Rails

I decided to upgrade code of https://www.railstutorial.org/book chapter 14 Following users. My code does not work, when current_user goes on another page and open following. current_user sees himself and want to unfollow like original instagram. unfollow button does not work
show_follow.html.erb:
<div class="line-gray-modals"></div>
<% if #users.any? %>
<% #users.each do |user| %>
<ul class="follow-list">
<li><%= image_tag(user.avatar.url(:thumb), :class => "img-cirkle") %></li>
<li >
<div class="modal-follow-ns" > <div class="bold"> <%= link_to user.username, user %></div> <br>
<div class="modal-follow-ns2"><%= link_to truncate(user.status, :length => 50) %></div></div>
</li>
<li class="button-modal">
<% unless user == current_user %>
<div id="follow_form">
<% if current_user.following?(user) %>
<%= form_for(current_user.relationships.find_by(followed_id: user),
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 %>
</div>
<% end %>
<% if user == current_user %>
<%= form_for(#user.relationships.find_by(followed_id: user),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
<% end %>
</li>
<%= will_paginate %>
<li> <div class="line-gray-modals"></div></li>
</ul>
<% end %>
relationships_controller.rb:
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
Terminal:
Completed 500 Internal Server Error in 10ms (ActiveRecord: 1.9ms)
NoMethodError (undefined method `destroy!' for nil:NilClass):
app/models/user.rb:28:in `unfollow!'
app/controllers/relationships_controller.rb:15:in `destroy'
Looking at the code below specially #user is probably nil. changing it to user does not make sense either. since you wanted to unfollow that user.
<%= form_for(#user.relationships.find_by(followed_id: user), html: { method: :delete }, remote: true) do |f| %>
Instead, use current_user
<%= form_for(current_user.relationships.find_by(followed_id: user), html: { method: :delete }, remote: true) do |f| %>

Paginating users with a follow/unfollow button: Ajax runs into problems because of duplicate class names

My users/show.html.erb pages work correctly because there is only one class name displayed on each page. When users are paginated in users/index.html.erb along with follow/unfollow buttons the relationship/js.create.erb and relationship/js.destroy.erb get wacky because there are duplicate class names on the page, (the first paginated user updates regardless of which user is followed/unfollowed and this only fixes itself when the page is refreshed (the actual model still works correctly)).
I did not use the unfollow/follow partials in users/index.html.erb because there is no #user variable in index.html.erb, it paginates #users, so I use user.id.
class RelationshipsController < ApplicationController
before_action :logged_in_user
def create
#user = User.find(params[:followed_id])
current_user.follow(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
end
**relationships/create.js.erb**
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= #user.followers.count %> <br> followers');
**relationships/destroy.js.erb**
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= #user.followers.count %> <br> followers');
**users/index.html.erb**
<div class="row community">
<% #users.in_groups_of(3, false).each do |users| %>
<div class="col-sm-12">
<% users.each do |user| %>
<ul class="name-head">
<% unless current_user == user %>
<div id="follow_form">
<% if current_user.following?(user) %>
<%= form_for(current_user.active_relationships.find_by(followed_id: user.id),
html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-primary" %>
<% end %>
<% else %>
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
<% end %>
</div>
<% end %>
</ul>
<div class="col-xs-12">
<div class="col-xs-4">
<a href="<%= following_user_path(user.id) %>">
<center><strong id="following" class:"stat">
<%= user.following.count %><br>
following
</strong></center>
</a>
</div>
<div class="col-xs-4">
<a href="<%= followers_user_path(user.id) %>">
<center><strong id="followers" class="stat">
<%= user.followers.count %><br>
followers
</strong></center>
</a>
</div>
<div class="col-xs-4">
<center><strong id="photo-count" class="stat">
<%= user.photos.count %><br>
photos shared
</strong></center>
</div>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<%= will_paginate %>
**users/show.html.erb**
.
.
.
<li class="follow">
<%= render 'follow_form' if logged_in? %>
</li>
</ul>
</div>
<div class="col-xs-12">
<div class="col-xs-4">
<a href="<%= following_user_path(#user) %>">
<center><strong id="following" class:"stat">
<%= #user.following.count %><br>
following
</strong></center>
</a>
</div>
<div class="col-xs-4">
<a href="<%= followers_user_path(#user) %>">
<center><strong id="followers" class="stat">
<%= #user.followers.count %><br>
followers
</strong></center>
</a>
</div>
<div class="col-xs-4">
<center><strong id="photo-count" class="stat">
<%= #user.photos.count %><br>
photos shared
</strong></center>
</div>
end
**_follow_form.html.erb**
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
**_follow.html.erb**
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, #user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
**_unfollow.html.erb**
<%= form_for(current_user.active_relationships.find_by(followed_id: #user.id),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-primary" %>
<% end %>
Edit: I thought about passing the user_id into the classes, such as:
<div id="follow_form<%="#{user.id}"%>">
which created <div id="follow3">
However I do not know how I can pass this into the destroy.js.erb and create.js.erb
I have tried many combinations such as:
$("#follow_form<%="#{user.id}"%>").html("<%= escape_javascript(render('users/unfollow')) %>");
and
$("#follow_form<%= #user.id%>").html("<%= escape_javascript(render('users/unfollow')) %>");
however, the code is still does not work and even if it did, it would still need work because changing the create/destroy.js.erb files would break the users/show.html.erb follow/unfollow buttons.
EDIT: I have also found this question which is similar but it does not contain an accepted answer.
Edit for Heroku Logs: This is what I get when I follow/unfollow a user on my users/index.html.erb page:
Started DELETE "/relationships/360" for 184.90.97.154 at 2016-05-13 20:05:17 +0000
Processing by RelationshipsController#destroy as JS
Rendered users/_follow.html.erb (1.6ms)
(1.1ms)[0m [1mSELECT COUNT(*) FROM "users" INNER JOIN "relationships" ON "users"."id" = "relationships"."follower_id" WHERE "relationships"."followed_id" = $1[0m [["followed_id", 1]]
Started POST "/relationships" for 184.90.97.154 at 2016-05-13 20:07:26 +0000
Processing by RelationshipsController#create as JS
[1m[36m (1.5ms)[0m [1mCOMMIT[0m
I've duplicated your code and, after adding the modifications below, it worked perfectly. (i.e. I don't need a page reload for the "Follow/Unfollow" button to change)
Try the following to see if it works:
users/index.html.erb (only the relevant code here, which is the "Follow/"Unfollow" button)
<ul class="name-head">
<% unless current_user == user %>
<%= render partial: 'follow_form', locals: { user: user } %>
<% end %>
</ul>
users/_follow_form.html.erb
<div id="follow_form-<%= user.id %>">
<% if current_user.following?(user) %>
<%= render partial: 'unfollow', locals: { user: user } %>
<% else %>
<%= render partial: 'follow', locals: { user: user } %>
<% end %>
</div>
users/_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: user.id), html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn-default" %>
<% end %>
users/_follow.html.erb
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
<div><%= hidden_field_tag :followed_id, user.id %></div>
<%= f.submit "Follow", class: "btn" %>
<% end %>
relationships/create.js.erb
$("#follow_form-<%= #user.id %>").html("<%= escape_javascript(render(partial: 'users/unfollow', locals: { user: #user })) %>");
relationships/destroy.js.erb
$("#follow_form-<%= #user.id %>").html("<%= escape_javascript(render(partial: 'users/follow', locals: { user: #user })) %>");
Note the use of <%= render partial: "_partial.html.erb", locals: { var_name: var } %>. the optional hash locals: { ....... } allows you to pass in a local variable to a partial you want to render (_partial.html.erb) In this case, you also need to add partial: before the name of the partial you want to render.
This way, your user local variable will become available not only in users/index.html.erb, but also in other files listed above.
The problem is in your relationship/js.create.erb and relationship/js.destroy.erb partials, because with your code you only update the first #follow-form div in your page (that is the #follow-form for first user, as you are reporting).
You should change your users\index.html.erb to
<% unless current_user == user %>
<div id="follow-form-<%= user.id %>">
This way, every user will have its unique div element. Then, just modify relationship/js.create.erb as follows:
$("#follow-form-<%= #user.id %>").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= #user.followers.count %> <br> followers');
and relationship/js.destroy.erb accordingly, then you should have everything working as expected.

Ruby on Rails multiple Buttons

I have the following written:
<% if #document != nil %>
<%= form_for(#document, :html => { :multipart => true }) do |f| %>
<% if #document.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#document.errors.count, "error") %> prohibited this document from being saved:</h2>
<ul>
<% #document.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<% if notice %>
<p id="notice"><%= notice %></p>
<% end %>
<%= render partial: 'documents/resume' %>
<div id="add_buttons">
<%= f.file_field :resume %>
<%= f.submit %>
</div>
<% end %>
<% else %>
<h1>No Document Available</h1>
<% end %>
Sorry about the indenting, copy/paste didn't paste it right. Anyways, this is using paperclip and works fine to upload a document as long as in the resume partial that I have listed I have my delete button commented out. Here is the code for that partial:
<div class='Resume_1'>
<%#= #current_user = session[:user] %>
<%#= #document = #current_user[:document] %>
Current Resume:
<%= render partial: 'documents/resumelink' %>
</div>
<div class='Resume_2'>
<% if (#document != nil) && (#document.resume_file_name != nil) %>
<%= button_to "Delete Resume", #document, method: :delete, data: { confirm: 'Are you sure you wish to delete your resume?' } %>
<% end %>
</div>
If the button_to line is commented out, the update document (f.submit) button works fine. However, if the button_to line is left in, the f.submit button does nothing. And here's the destroy function (which is where the delete method is routed to) since this doesn't actually seem to remove the resume either.
def destroy
#document.resume = nil
respond_to do |format|
format.html { redirect_to welcome_url, notice: 'Resume was successfully deleted.' }
format.json { head :no_content }
end
end
Thanks for any help.
If you look at docs. The html generated by button_to helper is
<%= button_to "New", action: "new" %>
# => "<form method="post" action="/controller/new" class="button_to">
# <div><input value="New" type="submit" /></div>
# </form>"
So when you have a button_to inside a form you basically have a form inside a form and hence your submit button doesn't work.
Fix:
Instead of using a button_to use link_to helper and give bootstrap classes or some custom class to make it look like a button
<%= link_to "Delete Resume", #document, class: "btn btn-default" method: :delete, data: { confirm: 'Are you sure you wish to delete your resume?' } %>

Can't get Ajax to work on follow/unfollow buttons - Following Railstutorial.org, Lesson 11

I can't get Ajax working in my Rails app.
With the magic of Ajax: When I click the "follow" button, it should update the number of followers the user sees in the profile page without having to refresh the page. However, this isn't happening for me in my sample app.
What is happening is that the "follow" button, when clicked, changes to "unfollow" as it should BUT, the number of followers stays the same until I hit the refresh button in the web-browser (tested in FF and IE). I'm following Michael Hartl's railstutorial.org, using Rails 4 and Ruby 2.0.0p195.
This is the console message I get from FireFox:
Empty string passed to getElementById().
This is my code below, the "follow" button in the view corresponds to actions in the relationships controller and they're supposed to hit the create.js.erb and destroy.js.erb partials.
-CONTROLLER-
relationships_controller.rb
def create
#user = User.find(params[:relationship][:followed_id])
current_user.follow!(#user)
# redirect_to #user
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow!(#user)
# redirect_to #user
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
-JAVASCRIPT-
_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 %>');
-VIEWS- are follow_form, with _follow.html.erb and _unfollow.html.erb.
_follow_form.html.erb
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
_follow.html.erb:
<%= 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 %>
_unfollow.html.erb
<%= form_for(current_user.relationships.find_by(followed_id: #user), html: { method: :delete }, remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
Note - I'm using postgreSQL on development instead of SQLlite that is used in the railstutorial.
EDIT in response:
_stats.html.erb
<% #user = #user || current_user %>
<div class="stats">
<a href="<%= following_user_path(#user) %>">
<strong id="following" class="stat">
<%= #user.followed_users.count %>
</strong>
following
</a>
<a href="<%= followers_user_path(#user) %>">
<strong id="following" class="stat">
<%= #user.followers.count %>
</strong>
followers
</a>
</div>
Because in your _stats.html.erb file, you dont have element with id followers. Please see your code
<a href="<%= followers_user_path(#user) %>">
<strong id="following" class="stat">
<%= #user.followers.count %>
</strong>
followers
</a>
It should be
<a href="<%= followers_user_path(#user) %>">
<strong id="followers" class="stat">
<%= #user.followers.count %>
</strong>
followers
</a>
I'll post my fix. in my _follow_form.html.erb file I did not include the id="follow_form" because of my own styling. You need to be sure to include the follow_form ID.
it should be:
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>

Resources