Following users on Ruby on Rails - 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| %>

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 %>

undefined method `comments'

I'm working on ROR project and created the partial form for the comments but i get the error in show.html.rb "undefined method `comments'".I have tried to find what's long but no luck.The highlight of the error is on this image
Image
here is my _form.html.erb
<%= simple_form_for ([#message, #message.comments.build]) do |f| %>
<%= f.input :content , label: "Comments" %>
<%= f.button :submit, :class => "btn-custom" %>
<% end %>
class CommentsController < ApplicationController
def create
#message = Message.find(params[:message_id])
#comment = #message.comments.create(comment_params)
#comment.user_id = current_user.user_id
if #comment.save
redirect_to message_path(#message)
else
render 'new'
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
And this is my show.html.rb
<div class="col-md-10 col-md-offset-1">
<div class="message-show">
<h2><%=#message.title %></h2>
<p class="message-posted-by"><%= time_ago_in_words(#message.created_at) %>
ago </p>
<p class="message-desc"><%= #message.description %></p>
<h3 class="comment-section-header">Discussion:</h3>
<p><%= render #message.comments %></p>
<h3 class="reply-to-msg">Reply</h3>
<%= render 'comments/form' %>
<div class="links btn-group">
<%= link_to "Back", root_path, class: "btn btn-default" %>
<%= link_to "Edit", edit_message_path, class: "btn btn-primary" %>
<%= link_to "Delete",message_path(#message), method: :delete,data: {confirm:"Are you sure?"} , class: "btn btn-danger" %>
</div>
</div>
</div>
Seems like your Message model is missing an association to comments:
# in app/models/message.rb
has_many :comments

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.

Why won't my edit and delete links work on my index page?

I have a list of post titles sorted under an alphabetical letter but my edit links and delete links aren't working on my index page. They do work when i add them to the show page. I thought i had this working before but get the error "undefined local variable posts" I have tried this.
edit_post_path(posts)
edit_post_path(#post)
edit_post_path(#posts)
posts controller
def index
#posts = current_user.posts.all.group_by {|post| ('a'..'z').include?(post.title.downcase[0]) ? post.title.downcase[0] : '#' }
end
def edit
#post = current_user.posts.find(params[:id])
end
def update
#post = current_user.posts.find(params[:id])
if #post.update_attributes(post_params)
redirect_to action: "index"
flash[:success] = "Post Updated"
else
render 'edit'
end
end
def destroy
#post = current_user.posts.find(params[:id])
#post.destroy
redirect_to action: "index"
flash[:success] = "Post Deleted"
end
index.html.erb
<% #posts.keys.sort.each do |key| %>
<div class= "posts-letter"><%= key.upcase %></div>
<% #posts[key].each do |t| %>
<div class="post">
<div class="post-title"><%= t.title %></div>
<div class="action-buttons">
<%= link_to edit_post_path(post), class: "edit-button" do %>
<i class="fa fa-pencil"></i>
<% end %>
<%= link_to post, method: :delete, data: { confirm: "You sure?" }, class: "delete-button" do %>
<i class="fa fa-trash"></i>
<% end %>
</div>
</div>
<% end %>
<% end %>
It appears that t is your post object inside the each. So you would pass that to edit_post_path. Or you could name it post instead of t.
<% #posts[key].each do |post| %>
<div class="post">
<div class="post-title"><%= post.title %></div>
<div class="action-buttons">
<%= link_to edit_post_path(post), class: "edit-button" do %>
<i class="fa fa-pencil"></i>
<% end %>
<%= link_to post, method: :delete, data: { confirm: "You sure?" }, class: "delete-button" do %>
<i class="fa fa-trash"></i>
<% end %>
</div>
</div>
<% end %>

Implementing Ajax - Rails App

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

Resources