Alternative to "link_to... do ... end" aproach - ruby-on-rails

I have this piece of code.
<div class="tweet" id="tweet-<%= tweet.id %>">
<%= image_tag #user.avatar.url(:thumb) %>
<div class="tweet-content">
<strong><%= #user.first_name + " " + #user.last_name %></strong>
<span class="date">- <%= tweet.created_at.strftime("%e %B %Y") %></span>
<p><%= tweet.content %></p>
<div class="tweet-action">
<% #replies_count = tweet.replies_count %>
<% #like_class = "glyphicon glyphicon-star like-tweet"+tweet.liked(current_user.id) %>
<% #like_id = "tweet-like-"+tweet.id.to_s %>
<%= link_to "", liked_tweets_path(tweet_id: tweet.id), method: :post, remote: true, class: #like_class, id: #like_id %>
<% if tweet.liked_tweets.count > 1 %>
<span><%= tweet.liked_tweets.count %></span>
<% end %>
<!-- -->
Retweet
</div>
<%= render 'tweets/form', parent: tweet %>
</div>
<div class="replies">
<!-- Here goes ajax resposnse tweets#show_resplies -->
</div>
</div>
I want to achieve that when I click on ".tweet" I want to do this action tweets_show_replies_path(parent: tweet, active: false ). When I tried to wrap the whole thing in link_to .... do ... end it failed and the link didn't wrap the ".tweet" element.
Could you please tell me how to achieve the effect that I described above?

Use some javascript and an ajax request!
$(document).ready(function() {
$( ".tweet" ).click(function() {
$.ajax({
type: "POST",
format: "js",
url: <url for tweets_show_replies_path>,
data: {
parent: <%= tweet %>,
active: false
},
dataType: "script"
});
});
});
Then in your controller, do whatever you need to and render the partial.

Related

Anchor while itering - Rails

I am trying to make an anchor in an index page while itering through a list of elements.
On the home page I display each element with a 'more info' button. When clicked it goes to the index of detailed elements. I tried the code below, but it doesn't work.
link_to 'More info', tours_path(#tour, :anchor => "#{tour.name}"
I also tried, without success:
link_to 'More info', tours_path(#tour, :anchor => tour.name
Here is the code of home.html.erb :
<section id="walking-tours">
<h2 class="text-center">Lisbon walking tours </h2>
<div class="walking-tours d-flex">
<% #tours.each do |tour| %>
<div class="walking-tours-cards item">
<% photo = tour.photos[0] %>
<%= cl_image_tag photo.key, height: 300, width: 300, crop: :fill if tour.photos.attached? %>
<h3> <%= tour.name %> </h3>
<p> <%= tour.description %> </p>
<%= link_to 'More info', tours_path(#tour, :anchor => "#{tour.name}"), class: 'btn btn-outline-secondary' %>
</div>
<% end %>
</div>
</section>
and the code in index.html.erb
<div class="index-tours">
<div class="tours-title">
<h1 >WALKING TOURS</h1>
</div>
<div class="tours-list">
<% #tours.each do |tour| %>
<div class="walking-tours-details ">
<div class="walking-tours-info">
<h3> <%= tour.name %> </h3>
<p> <%= tour.full_information %> </p>
<p><b>Duration</b> -<%= tour.duration %> </p>
<p><b>Meeting Point</b> - <%= tour.meeting_point %> </p>
</div>
<div class="tours-pics">
<% tour.photos.each do |photo| %>
<%= cl_image_tag photo.key, height: 220, width: 220, crop: :fill, :class => "tours-img" %>
<% end %>
</div>
</div>
<% if logged_in? %>
<%= link_to 'Edit', edit_tour_path(tour), :class => "tours-links" %> <%= link_to 'Destroy', tour, method: :delete, data: { confirm: 'Are you sure?' } %>
<% end %>
<% end %>
</div>
For now, all 'more info' buttons go to the first element of the list (at the top of the index page).
Any idea to help? Thanks!!
Cécile
I found a solution by generating a dynamic ID:
<% tour_link = tour.name %>
<% tour_identification = tour_link.gsub(/\s+/, '') %>
<div id= <%= tour_identification %> >
and for the link_to :
<%= link_to 'More info', tours_path(tour, anchor: tour_identification) %>
But I still wonder if the anchor could work without an ID.

Add as favorite with no full page refresh

I am working on a Hiragana flashcards app.
I spend nights and days to understand how don't refresh full page when I add a flashcard (hiragana) as a favorite.
Here is the favorite controller
class FavsController < ApplicationController
def index
#favs = Fav.where(user: current_user)
end
def create
#hiragana = Hiragana.find(params[:hiragana_id])
#fav = current_user.favs.new(hiragana: #hiragana)
if not #hiragana.favs.where(user: current_user).take
#fav.save
end
render json: #fav
end
def destroy
#fav = Fav.find(params[:id])
#fav.destroy
redirect_to :back
end
end
I render json in the create method and when I click on view I add only an hash
render view favorite
<% if current_user %>
<div class="hiragana-fav">
<% if hiragana.is_faved_by(current_user) %>
<%= link_to fav_path(hiragana.is_faved_by(current_user)), method: :delete do %>
<i class="fa fa-heart faved faved-on"></i>
<% end %>
<% else %>
<%= link_to hiragana_favs_path(hiragana), method: :post do %>
<i class="fa fa-heart faved faved-off"></i>
<% end %>
<% end %>
</div>
<% end %>
and it is located in hiragana render
<div class="row">
<ul class="list-inline text-center card-frame">
<li>
<div class="card">
<div class="front">
<% if current_user.try(:admin?) %>
<%= link_to hiragana_path(hiragana), class:'trash-hiragana', data: { confirm: 'Are you sure?' }, method: :delete do %>
<%= image_tag("delete-btn.png") %>
<% end %>
<% end %>
<span class="card-question img-popover" data-content="<h4 class='text-center letter-uppercase'><%= hiragana.bigletter.upcase %></h4><p class='text-center'><b><%= hiragana.midletter %></b> comme dans <b><%= hiragana.transcription %></b></p>">
<i class="fa fa-eye fa-lg"></i>
</span>
<div class="card-hiragana hiragana-<%=hiragana.bigletter.downcase.last%>">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-katakana">
<p><%= hiragana.ideo2 %></p>
</div>
<%= render 'favs/favorites', hiragana: hiragana %>
</div>
<div class="back">
<div class="col-sm-3 col-xs-4 col-md-3 containerbackcards-<%=hiragana.bigletter.downcase.last%>">
<div class="backcard-hiragana">
<h1><b><%= hiragana.ideo1 %></b></h1>
</div>
<div class="card-bigletter">
<h4><%= hiragana.bigletter.upcase %></h4>
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
When I add a card as favorite it gives me a hash like this :
{
id: 64,
user_id: 1,
hiragana_id: 4,
created_at: "2016-02-10T16:37:26.270Z",
updated_at: "2016-02-10T16:37:26.270Z"
}
I just want to have the heart grey to red as favorite, saved and not refresh the entire page. Your explainations are appreciated thank you.
In order to send the request to the controller without the page refreshing you need to use a combination of Ajax and JavaScript.
You use JavaScript to add a click listener to the .faved-on button and to trigger the Ajax request. You will also use JavaScript to prevent the default action occurring when you click the link ie. The Page Refresh
You then use Ajax to send the request to the controller and handle the response.
Your initial JavaScript code looks pretty correct, except you are missing the bit to stop the page from reloading.
See the e.preventDefault(); line below
$(document).ready(function() {
$('.faved-on').click(function(e) { //make sure to pass in the e (the event paramter)
e.preventDefault(); //this is the line you are missing
var fav = $('.faved-off')
//let your ajax handle the rest then
$.ajax({
type: "POST", url: "/hiraganas", dataType: "json",
success: function(data) {
console.log(data);
//change the color of your heart to red here
},
error: function(jqXHR) {
console.error(jqXHR.responseText);
}
});
})
})
I haven't tested your JavaScript but it looks pretty close to correct, I believe its the e.preventDefault(); bit you were missing

How do I make the like counter to go down when I click the dislike button and vice versa?

this is the controller with like action:
def like
like = Like.create(like: params[:like], user: current_user, story: #story)
respond_to do|format|
if like.valid?
format.js
else
format.js {render status: 403, js: "alert('You can only like/dislike a story once')"}
end
end
this is the model that has the counter from model:
def thumbs_up_total
self.likes.where(like: true).size
end
def thumbs_down_total
self.likes.where(like: false).size
end
this is the View. I am getting the counter from the model. 'thumbs up' and 'thumbs down':
<div class="pull-right">
<%= link_to like_story_path(story, like: true), method: :post, data: { remote: true } do %>
<div class="likes"></div>
<% end %>
<div id = "like-<%= story.id %>">
<%= story.thumbs_up_total %>
</div>
<%= link_to like_story_path(story, like: false), method: :post, data: { remote: true } do %>
<div class="dislikes"></div>
<% end %>
<div id="dislike-<%= story.id %>">
<%= story.thumbs_down_total %>
</div>
</div>
I guess you are asking for something like this, correct?
<div class="pull-right">
<%= link_to like_story_path(story, like: true), method: :post, data: { remote: true } do %>
<div class="likes"></div>
<% end %>
<div id = "like-<%= story.id %>">
<%= story.thumbs_up_total - story.thumbs_down_total%>
</div>
<%= link_to like_story_path(story, like: false), method: :post, data: { remote: true } do %>
<div class="dislikes"></div>
<% end %>
<div id="dislike-<%= story.id %>">
<%= story.thumbs_down_total - story.thumbs_up_total %>
</div>
</div>
Move parts of your view to partials, createlike.js and fill it with code to render the partials.
First change your view code to this
<div class="pull-right">
<%= link_to like_story_path(story, like: true), method: :post, data: { remote: true } do %>
<div class="likes"></div>
<% end %>
<%= render "thumbs_up" %>
<%= link_to like_story_path(story, like: false), method: :post, data: { remote: true } do %>
<div class="dislikes"></div>
<% end %>
<%= render "thumbs_down" %>>
</div>
Then create two new partials.
# _thumbs_up.html..erb
<div id = "like-<%= story.id %>" class="thumbs-up">
<%= story.thumbs_up_total %>
</div>
# _thumbs_down.html..erb
<div id = "like-<%= story.id %>" class="thumbs-down">
<%= story.thumbs_down_total %>
</div>
Add a file called like.js
# like.js
$(".thumbs-up").html("<%= j(render("thumbs_up")) %>");
$(".thumbs-down").html("<%= j(render("thumbs_down")) %>");
like.js will then be called when your links are clicked. It will re-render your partials and update your thumb counts on click.

how to implement pagination with multistep?? OR is their any way to hold the previous page radio button value when using pagination

I am creating a rails quiz .. i have done everything the problem is that i want to implement pagination and when the user goes to next page the previous page values are lost. i am new to rails.
view page -- that show question paper
<div class="navbar navbar-fixed-top">
<h3><% if #paper.timing!=0 %><div id="time" class="bg"></div><%end%></h3>
</div>
<br>
<%= form_for Result.new do |f| %>
<div id="content">
<div class="inputs">
<div>
<div>
<div>
<div>
<% #questions.each_with_index do |question , i | %>
<%= f.hidden_field :userchoice_id, :value => session[:id] %>
<%= f.hidden_field :exam_id, :value => session[:exam_id] %><br>
<h3> <%= i + 1 %>.<%= question.content %></h3><br>
<%count = 0%>
<% a=question.answers %>
<%#raise a.inspect%>
<% a.each do |sushil| %>
<%#raise sushil.inspect%>
<% if sushil.correct_answer?%>
<%count = count+1 %>
<%else %>
<%count = count+0 %>
<%end%>
<%end%>
<%#raise count.inspect%>
<%if count == 1 %>
<% for answer in question.answers %>
<%= radio_button_tag("result[question_id][#{question.id}]", answer.id ) %>
<%= answer.content %><br>
<%end%>
<%elsif count >= 2 %>
<% for answer in question.answers %>
<%= check_box_tag("result[question_ids][][#{question.id}]", answer.id ) %>
<%#= check_box_tag ("result[question_id][#{question.id}]", answer.id ) %>
<%= answer.content %><br>
<% params[:answer_id] = answer.id %>
<%end%>
<% end %>
<%# raise params[:answer_id].inspect%>
<% end %>
</div>
<div class="form-actions">
<center><%= f.submit "Submit", :class => 'btn btn-primary',:onclick => "if(confirm('Are you sure you want to Submit the Paper?')) return true; else return false;" %></center>
</div>
<% end %>
</div>
</div>
</div>
<div style='display:none' id="timeup"><% if #time==0 %>0<%else%>1<%end%></div>
<!-- Added javascript for back button-->
<script>
jQuery(document).ready(function($) {
if (window.history && window.history.pushState) {
window.history.pushState('forward', null, './#forward');
$(window).on('popstate', function() {
history.forward();
});
}
});
</script>
<!-- Added Timer Javascript in Test -->
<% if #paper.timing!=0 %>
<script>
$(document).ready(function(){
var now=new Date();
if($('#timeup').html()==0){
stopTest();
}
now.setMinutes(now.getMinutes()+<%=#min%>);
now.setSeconds(now.getSeconds()-<%=#sec%>);
$('#time').countdown({until:now, format: 'MS',onExpiry:stopTest});
});
function stopTest(){
$('#time').html('<center><h4>Time\'s up!</h4></center>');
$('#timeup').html('0');
// $('input.radio').attr("onclick","return false;");
$("#new_result").submit();
}
</script>
<%end%>
You should use kaminari or will_paginate gem...
Kaminari example:
Gemfile:
gem 'kaminari'
bash:
bundle
rails g kaminari:views default
products_controller.rb:
#products = Product.order("name").page(params[:page]).per(5)
config/locales/en.yml:
en:
hello: "Hello world"
views:
pagination:
previous: "< Previous"
next: "Next >"
truncate: "..."
products/index.html.erb:
<%= paginate #products %>
app/views/kaminari/_prev_span.html.erb
<span class="prev disabled"><%= raw(t 'views.pagination.previous') %></span>
Will_paginate example:
http://richonrails.com/articles/getting-started-with-will-paginate

Rendering a collection isn't rendering all items in the collection?

This seems very elementary, so I'm not sure what I'm doing wrong. I have a #videos collection (which debugging #videos.count reveals to be 4), but the line <%= render #videos %> is only rendering 2 of the 4 items. Here is the controller method (VideosController):
def index
#video = Video.new(athlete_id: current_user.id, sport_id: current_athlete_sport.id)
#videos = current_user.videos_for_sport(current_athlete_sport).order("date DESC")
debugger
respond_with #videos
end
And the _video partial that the aforementioned <%= render #videos %> line is rendering:
<%= form_for video do |f| %>
<div class="row edit-video-container <%= video == #videos.pop ? 'last' : '' %>">
<div class="span4">
<div class="row">
<div class="span4 video-thumbnail">
<%= image_tag video.thumbnail_url || asset_path("video-encoding-placeholder.png"), {alt: "", title: "#{video.name || "My video" + video.id}"} %>
<div class="video-ribbon">
<ul>
<li class="pull-left">
<%= link_to "#video-player-modal", { data: { toggle: "modal", link: video.mp4_video_url, thumbnail: video.thumbnail_url }, role: "button", class: "video-player-link" } do %>
<i class="icon video-play"></i>
<p>Play</br>Video</p>
<% end %>
</li>
<li class="pull-left">
<%= link_to rotate_video_path(video, direction: "ccw"), :data => { :method => "put", :confirm => "Are you sure?", :type => 'json' } do %>
<i class="icon video-rotate-left"></i>
<p>Rotate</br>Left</p>
<% end %>
</li>
<li class="pull-left">
<%= link_to rotate_video_path(video, direction: "cw"), :data => { :method => "put", :confirm => "Are you sure?", :type => 'json' } do %>
<i class="icon video-rotate-right"></i>
<p>Rotate</br>Right</p>
<% end %>
</li>
<li class="pull-left">
<%= link_to video_path(video), :data => { :method => "delete", :confirm => "Are you sure?", :type => 'json' } do %>
<i class="icon video-delete"></i>
<p>Delete</br>Video</p>
<% end %>
</li>
</ul>
</div>
</div>
</div>
<div class="row">
<div class="span4">
<%= f.check_box :featured, { checked: video.featured?, class: "autosave checkbox-right", data: { event: 'change' } } %>
<%= label_tag "video-checkbox-featured-#{video.id}", "Use as featured video?", { class: "checkbox-right-label" } %>
</div>
</div>
</div>
<div class="span4">
<div class="row">
<div class="span4">
<%= label :video, :name, "Video Name" %>
<%= f.text_field :name, { class: "span4 autosave"} %>
</div>
</div>
<div class="row">
<div class="span4">
<%= label :video, :video_type_id, "Video Type" %>
<%= f.select:video_type_id, VideoType.all.collect { |vid| [vid.name, vid.id] }, { include_blank: "Choose One", selected: video.video_type_id }, { class: "chosen-select autosave", id: "", data: { event: 'change' } } %>
</div>
</div>
<div class="row">
<div class="span4">
<%= label :video, :sport_id, "Video Sport" %>
<%= f.select :sport_id, current_user.sports.collect { |sp| [sp.name, sp.id] }, { include_blank: "Choose one", selected: video.sport_id }, { class: "chosen-select autosave", id: "", data: { event: "change" } } %>
</div>
</div>
<div class="row">
<div class="span4">
<%= label :video, :date, "Date Recorded" %>
<%= f.text_field :date, {class: "autosave date datePicker span4", value: js_date(video.date) } %>
</div>
</div>
<div class="row">
<div class="span4">
<%= label :video, :uniform_number, "Uniform Number" %>
<%= f.text_field :uniform_number, { class: "autosave span4"} %>
</div>
</div>
</div>
</div>
<% end %>
Again, throwing a debugger in the controller, or a debug on the page just before the <%= render #videos %> line shows 4 videos, however only 2 are actually being rendered. At a bit of a loss here!
The problem is here:
video == #videos.pop
Pop takes out a member from your collection. You shouldn't use it here because you brake the looping.
If this is the case, I suppose you can see only the first and the last item of your collection.

Resources