Bug, switch state of boolean field - javascript

I'm using https://gorails.com/forum/switch-state-of-boolean-field as a guide toggle a boolean value. I'm using a partial to display all the objects but only the first object toggles the boolean value. Also, the ajax is not working, I have to refresh the page to show the new boolean value.
Here is posts_controller:
def toggle_confirm
respond_to do |format|
format.html
format.js
end
#post = Post.find_by(params[:id])
#post.toggle!(:confirm)
end
Here is the views/shared/_received_feed partial:
<ol class="posts">
<% #received_feed.each do |feed| %>
<%= render feed %>
<%= link_to "#{ feed.confirm ? 'Confirmed' : 'Disabled' }", toggle_confirm_post_path(feed), method: :patch, remote: :true, class: "btn btn-xs btn-#{ feed.confirm ? 'success' : 'warning' }" %>
<% end %>
</ol>
Here is the views/toggle_confirm.js.erb:
console.log(<%= #post.confirm %>);
<% if #post.confirm == true %>
$(".post-<%= #post.id %> >
a").html('3Confirmed').removeClass('btn-warning').addClass('btn-success')
<% else %>
$(".post-<%= #post.id %> > a").html('Not
Confirmed').removeClass('btn-success').addClass('btn-warning')
<% end %>
$("#post-status-<%= #post.id %>").html("<%=
#post.confirm %>")
Here is the partial for displaying each post views/posts/_posts:
<li id="post-<%= post.id %>">
<span class="user"><%= post.sender.name %></span>
<br>
<span class="image"><%= image_tag post.sender.avatar.url(:thumb) %>
</span>
<br>
<span class="note"><%= post.note %></span>
<br>
</li>

Related

How to use Ajax to show first and only one comment as soon as it is created

At present my application is able to append comments to microposts that already have comments. Below is _micropost.html.erb (simplified):
<li id="micropost-<%= micropost.id %>">
<span class="content">
<%= micropost.content %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
~ <%= link_to "Comment", "#", class: "comment-link", remote: true %>
<% if micropost.comments.any? %>
~ <%= link_to "Show/hide comments", "#", class: "comments-link", remote: true %>
<% end %>
</span>
<% if logged_in? && (current_user == micropost.user || current_user.friend?(micropost.user)) %>
<div class="comment-section">
<%= form_for(current_user.comments.build, remote: true) do |f| %>
<%= f.hidden_field :micropost_id, value: micropost.id %>
<%= f.text_area :content, rows: "1", class: "comment_area" %>
<%= f.submit "Comment", class: "btn btn-primary btn-sm" %>
<% end %>
</div>
<% end %>
<div class="comments-section">
<% if micropost.comments.any? %>
<ol id="comments_micropost-<%= micropost.id %>">
<% micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
</div>
</li>
create.js.erb is:
var comments = $('ol#comments_micropost-<%= #micropost.id %>');
comments.append('<%= escape_javascript(render partial: #comment) %>');
As it is conceived, create.js.erb implies that the comment created is added to other comments, that is that the comment created is not the first one. In this case, var comments is not null and the last line of code append the comment to the list of the other comments.
Also, in case micropost.comments is not nil, the user can use the "Show/hide comments" link to toggle the order list with id="comments_micropost-<%= micropost.id %>"
The problem with this configuration is that in case a user add to any micropost the first comment (that is the user writes his comment when micropost.comments == 0) there is no chance to see the result without refreshing the page.
So I am asking: how can I edit create.js.erb so that the user can see straight away the result of posting the first comment and that the "Show/hide comments" link be added to the page?
I tried the following code but it does not work:
if (comments !== null) {
comments.append('<%= escape_javascript(render partial: #comment) %>');
} else {
$('#micropost-<%= #micropost.id %>').find('.comments-section').append("<ol id='comments_micropost-<%= #micropost.id %>'><%= escape_javascript(render partial: #comment) %></ol>");
$('#micropost-<%= #micropost.id %>').find('.timestamp').append(" ~ <%= link_to 'Show/hide comments', '#', class: 'comments-link', remote: true %>");
};
<li id="micropost-<%= micropost.id %>">
<span class="content">
<%= micropost.content %>
</span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
~ <%= link_to "Comment", "#", class: "comment-link", remote: true %>
<% if micropost.comments.any? %>
~ <%= link_to "Show/hide comments", "#", class: "comments-link", remote: true %>
<% end %>
</span>
<% if logged_in? && (current_user == micropost.user || current_user.friend?(micropost.user)) %>
<div class="comment-section">
<%= form_for(current_user.comments.build, remote: true) do |f| %>
<%= f.hidden_field :micropost_id, value: micropost.id %>
<%= f.text_area :content, rows: "1", class: "comment_area" %>
<%= f.submit "Comment", class: "btn btn-primary btn-sm" %>
<% end %>
</div>
<% end %>
<div class="comments-section">
<%= render partial: comments, micropost: micropost %>
</div>
</li>
And in _comments.html.erb
<% if micropost.comments.any? %>
<ol id="comments_micropost-<%= micropost.id %>">
<% micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
And in create.js.erb
var comments = $('ol#comments_micropost-<%= #micropost.id %>');
if (comments == undefined) {
$('div#comments-section').html('<%= escape_javascript(render partial: comments, micropost: #micropost) %>');
}
else {
comments.append('<%= escape_javascript(render partial: #comment) %>');
};
I solved my issue creating as originally suggested by Minu a app/views/comments/_comments.html.erb file as follows:
<% if #micropost.comments.any? %>
<ol id="comments_micropost-<%= #micropost.id %>">
<% #micropost.comments.each do |comment| %>
<%= render comment %>
<% end %>
</ol>
<% end %>
Without changing partial _micropost.html.erb I edited create.js.erb as follows:
var comments = $('ol#comments_micropost-<%= #micropost.id %>');
if (comments.length == 0) {
$('#micropost-<%= #micropost.id %>').find('.comments-section').html("<%= escape_javascript(render partial: 'comments/comments') %>");
}
else {
comments.append('<%= escape_javascript(render partial: #comment) %>');
};
When micropost.comments.any? is false, var comments is neither null or undefined, but is considered as an empty array, as can be verified by using a web browser console. Hence the use of if (comments.length == 0). See post at Stackoverflow.

Implementing AJAX Creation, Missing Template (Create) Error

I am trying to implement AJAX in my to do type app, but am getting a missing template error (Missing template items/create, application/create with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee]}.) on my create action. There shouldn't be a create.html.erb page because the creation of items happens on a lists#show page:
<div class='new-item'>
<%= render 'items/form' %>
</div>
<div class="js-items">
<% #items.each do |item| %>
<%= div_for(item) do %>
<p><%= link_to "", list_item_path(#list, item), method: :delete, remote: true, class: 'glyphicon glyphicon-ok', style: "margin-right: 10px" %>
<%= item.name %>
<% if item.delegated_to != "" && item.user_id == current_user.id %>
<small>(Delegated to <%= item.delegated_to %>)</small>
<% elsif item.delegated_to != "" && item.user_id != current_user.id %>
<small>(Delegated by <%= item.user_id %>)</small>
<% end %></p>
<% end %>
<% end %>
</div>
And the _form.html.erb partial to which it links:
<div class="row">
<div class="col-xs-12">
<%= form_for [#list, #item], remote: true do |f| %>
<div class="form-group col-sm-6">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control', placeholder: "Enter Item Name" %>
</div>
<div class="form-group col-sm-6">
<%= f.label 'Delegate To (Not Required)' %>
<%= f.text_field :delegated_to, class: 'form-control', placeholder: "Enter an Email Address" %>
</div>
<div class="text-center"><%= f.submit "Add Item to List", class: 'btn btn-primary' %></div>
<% end %>
</div>
</div>
Here's the create method in the items_controller:
def create
#list = List.friendly.find(params[:list_id])
#item = #list.items.new(item_params)
#item.user = current_user
#new_item = Item.new
if #item.save
flash[:notice] = "Item saved successfully."
else
flash[:alert] = "Item failed to save."
end
respond_to do |format| <<<<ERROR CALLED ON THIS LINE
format.html
format.js
end
end
And here's my create.js.erb file:
<% if #item.valid? %>
$('.js-items').prepend("<%= escape_javascript(render(#item)) %>");
$('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: { list: #list, item: #new_item }) %>");
<% else %>
$('.flash').prepend("<div class='alert alert-danger'><button type='button' class='close' data-dismiss='alert'>×</button><%= flash.now[:alert] %></div>");
$('.new-item').html("<%= escape_javascript(render partial: 'items/form', locals: { list: #list, item: #item }) %>");
<% end %>
Anyone have any ideas why I am getting this? I tried removing the format.html line from the items_controller but I got an unrecognizable format error.
You can force the form submission to use a JS format, instead of the default HTML format, so that your respond_to block will render the create.js.erb view instead of the create.html.erb view.
<%= form_for([#list, #item], format: :js, remote: true) do |f| %>
Typically, Rails will detect your remote: true option via "unobtrusive JavaScript (ujs)", which will effectively handle the format: :js option for you. There is something unique in your setup that we have not identified, which is requiring you to enforce the format option.
To see that your create.js.erb is working, you can change the line that renders your item partial:
$('.js-items').prepend("<%= escape_javascript(render(#item)) %>");
To render a the item's name, wrapped in a <p> tag:
$('.js-items').prepend("<p>" + <%= #item.name %> + "</p>");
You can customize that line to generate the html that you want to appear for your new list item. Based on your code above, this looks like it will work out for you.
As you finish your to-do app, you can create a partial for your item, and then change that line again so that your partial will be appended to your list of items.

Counter span on my like button not updating with ajax

I have followed the answers suggested on other questions on SO (this question and this question ), but for some reason I can't get my like button counter to work properly with ajax. My counter changes only after a refresh, any help is appreciated thanks!
meals_controller.rb
def upvote
#meal.upvote_from current_user
if request.xhr?
render json: { count: #meal.get_upvotes.size, id: params[:id] }
else
redirect_to meals_path
end
end
def unlike
#meal.unliked_by current_user
redirect_to meals_path
end
routes.rb
Rails.application.routes.draw do
devise_for :users
root 'home#index'
resources :meals do
member do
put "like" => "meals#upvote"
put "unlike" => "meals#unlike"
end
end
#upvote.coffee
$(document).on 'ajax:success', 'a.vote', (status,data,xhr)->
$(".votes-count[data-id=#{data.id}]").text data.count
return
#index.html.erb
<p id="notice"><%= notice %></p>
<h1>Listing Meals</h1>
<% #meals.each do |meal| %>
<%= meal.title %>
<br>
<%= meal.descriptionttext %>
<%= link_to like_meal_path(meal), class: "vote", method: :put, remote: true do %>
<button>
<span class="votes-count" data-id="<% meal.id %>"><%= meal.get_likes.size %></span>
</button>
<% end %>
<%= link_to unlike_meal_path(meal), method: :put do %>
<button type="button">
<span><%= meal.get_upvotes.size%></span>
</button>
<% end %>
<br>
<% end %>
<br>

ajax call not updating content on rails

Im trying to implement a bit a Ajax into my app seems to work correctly but it isnt updating the page after the action is executed .
I added Ajax to my Destroy method
def destroy
#item = Item.find(params[:id])
#item.user = current_user
if #item.destroy
flash[:notice] = "Item Completed"
else
flash[:alert] = "Item was unable to be marked completed "
end
respond_to do |format|
format.html
format.js
end
end
i have update my _item.html.erb and _form.html.erb partials with remote: true
<%= content_tag :div, class: 'media', id: "item-#{item.id}" do %>
<div class="media">
<div class="media-body">
<small>
<%= item.name.titleize %>
| submitted <%= time_ago_in_words(item.created_at) %>
<% if current_user == #user %>
<%= link_to "Completed ", [#user, item], method: :delete,remote: true, class: 'glyphicon glyphicon-ok' %><br>
<% end %>
</small>
</div>
</div>
<% end %>
_from.html.erb
<%= form_for [#user, item ], remote: true do |f|%>
<div class="form-group">
<%= f.label :name, class: 'sr-only' %>
<%= f.text_field :name , class: 'form-control', placeholder: "Enter a new item " %>
</div>
<%= f.submit "Submit Item", class: 'btn btn-primary pull-right' %>
<% end %>
User#show view <div class='new_item'>
<%= render :partial => 'items/form', :locals =>{:item => Item.new} %>
</div>
<% end %>
<div class='js-items'>
<% #user.items.order('created_at DESC').each do |item| %>
<%= render :partial => 'items/item' , :locals => {:item => item } %>
</div>
destroy.js.erb
$('#item-<%= #item.id %>').hide();
Like I said before, the item is deleted when i click the delete button but i need to refresh the page in order to see the updated page. Any ideas what i might be doing wrong, any push to the right direction would be greatly appreciated!
Try rendering the java script in the method itself and check,
def destroy
#item = Item.find(params[:id])
#item.user = current_user
if #item.destroy
flash[:notice] = "Item Completed"
else
flash[:alert] = "Item was unable to be marked completed "
end
respond_to do |format|
format.html
format.js { render
$('#item-<%= #item.id %>').hide();
}
end
end

Button doesn't update in Ajax on Users Index page - Rails Tutorial 4

TLDR: Trying to add a follow/unfollow button to the Users#Index action but when clicking on the button nothing happens.
I have followed Michael Hartl's Rails Tutorial app and now that it's complete I want to add extra functionality for the Follow/Unfollow button. Currently, you can only follow/unfollow a user after visiting their profile page thru the Users Show action. I've attempted to expand this functionality to the Index page of the Users controller so that instead of having to visit each user's profile page in order to follow/unfollow them, a follow button will also appear next to their name in the Index view.
The code that works initially for the follow/unfollow button on the Users Show action:
users_controller.rb
https://gist.github.com/anonymous/9602598
show.htlm.erb for users view
https://gist.github.com/anonymous/9602616
_follow_form.htlm.erb partial for users view
<% unless current_user?(#user) %>
<div id="follow_form">
<% if current_user.following?(#user) %>
<%= render 'unfollow' %>
<% else %>
<%= render 'follow' %>
<% end %>
</div>
<% end %>
_follow.html.erb partial for users view
<%= 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 partial for users view
<%= 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 %>
create.js.erb inside of my relationships view
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= #user.followers.count %>')
destroy.js.erb inside of my relationships view
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= #user.followers.count %>')
index.html.erb inside of the users view
<%= render #users %>
_user.html.erb partial inside of users view
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
I've tried a few different approaches that so far have been fruitless
First I tried simply rendering the follow_form partial inside of the _user partial just like it's done for the User Show view
_user.html.erb partial inside of users view
<%= render 'follow_form' if signed_in? %>
this resulted in the following error: NoMethodError in Users#index "undefined method `id' for nil:NilClass" and it hilights the following line of code inside of the follow_form partial
<% if current_user.following?(#user) %>
After mucking around with the variables and the controller for a few hours I finally managed to get the buttons to show properly on the index page with the following code inside of the _user.html.erb partial
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
<% if current_user.following?(user) %>
<%= form_for(#current_user.relationships.find_by(followed_id: #users),
html: { method: :delete },
remote: true) do |f| %>
<%= f.submit "Unfollow", class: "btn btn-large" %>
<% end %>
<% else %>
<%= form_for(current_user.relationships.build(followed_id: #users),
remote: true) do |f| %>
<div><%= f.hidden_field :followed_id %></div>
<%= f.submit "Follow", class: "btn btn-large btn-primary" %>
<% end %>
<% end %>
</li>
This code however, only shows the correct follow/unfollow buttons for each user but when you click a button nothing happens. I also attempted to edit the JS files with the following code
create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#user").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= #user.followers.count %>')
destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#user").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= #user.followers.count %>')
This didn't have any effect.
The more I tinker with different parts of the code the more it's confusing me. Here is my relationships controller for good measure.
relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :signed_in_user
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
end
I know it's alot but if anyone can help shed some light on my situation I would be very grateful. This is my first venture outside of tutorials and I figured it would be a good idea to try and add features to an already working project instead of start something from scratch.
Just in case anybody was on this question and was still looking for the correct Ajax code. This works with the existing controller and nothing else will have to be changed.
create.js.erb
var indexed_form = "follow_form_<%=#user.id%>"
if ( document.getElementById(indexed_form) ){
var jquery_indexed_form = "#" + indexed_form
$(jquery_indexed_form).html("<%= escape_javascript(render('users/unfollow')) %>");
}
else {
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>");
$("#followers").html('<%= #user.followers.count %>');
}
destory.js.erb
var indexed_form = "follow_form_<%=#user.id%>"
if ( document.getElementById(indexed_form) ){
var jquery_indexed_form = "#" + indexed_form
$(jquery_indexed_form).html("<%= escape_javascript(render('users/follow')) %>");
}
else {
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>");
$("#followers").html('<%= #user.followers.count %>');
}
_user.html.erb
<div class="col-md-2">
<% unless current_user?(user) %>
<% form_id = user.id.to_s %>
<div id="follow_form_<%= form_id %>">
<% 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" %>
<% 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 %>
</div>
This is my first post. Yay! Hope it helps someone!
Use the following code in _user.html.erb partial:
<li>
<%= gravatar_for user, size: 52 %>
<%= link_to user.name, user %>
<% if current_user.admin? && !current_user?(user) %>
| <%= link_to "delete", user, method: :delete,
data: { confirm: "You sure?" } %>
<% end %>
<% 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 %>
</li>
I made couple of changes to the code in form_for method call in 2 places:
#current_user should be current_user.
Secondly, followed_id: #users should be followed_id: user.id

Categories

Resources