How to use bootstrap progress bars - ruby-on-rails

This is a foolish question But I have no idea where to begin.
I want to use Bootstrap's Progress Bars.
I have a simple todo list app. I want to be able to visually show that 70% of a todo list is complete.
How would I go about this, or what resources do I need to look at. I can only find information on using the progress bars to display a websites loading progress.
I want to set these up to be dynamic of course. So when a user marks an object as complete, then the progress bar should change as well.
_todo_item.html.erb
<div class="row clearfix">
<% if todo_item.completed? %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(#todo_list, todo_item.id), method: :patch do %>
<i style="opacity: 0.4;" class="glyphicon glyphicon-ok"></i>
<% end %>
</div>
<div class="todo_item">
<p style="opacity: 0.4;"><strike><%= todo_item.content %></strike></p>
</div>
<div class="trash">
<%= link_to todo_list_todo_item_path(#todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<span class="glyphicon glyphicon-trash"></span>
<% end %>
</div>
<% else %>
<div class="complete">
<%= link_to complete_todo_list_todo_item_path(#todo_list, todo_item.id), method: :patch do %>
<span class="glyphicon glyphicon-ok"></span>
<% end %>
</div>
<div class="todo_item">
<p><%= todo_item.content %></p>
</div>
<div class="trash">
<%= link_to todo_list_todo_item_path(#todo_list, todo_item.id), method: :delete, data: { confirm: "Are you sure?" } do %>
<span class="glyphicon glyphicon-trash"></span>
<% end %>
</div>
<% end %>
</div>
todo_items_controller.rb
class TodoItemsController < ApplicationController
before_action :set_todo_list
before_action :set_todo_item, except: [:create]
def create
#todo_item = #todo_list.todo_items.create(todo_item_params)
redirect_to #todo_list
end
def destroy
if #todo_item.destroy
flash[:success] = "Todo List item was deleted"
else
flash[:error] = "Todo List item could not be deleted."
end
redirect_to #todo_list
end
def complete
#todo_item.update_attribute(:completed_at, Time.now)
redirect_to #todo_list, notice: "Todo item completed"
end
private
def set_todo_list
#todo_list = TodoList.find(params[:todo_list_id])
end
def set_todo_item
#todo_item = #todo_list.todo_items.find(params[:id])
end
def todo_item_params
params[:todo_item].permit(:content)
end
end
A users has a todo_list and a todo list has a todo_item. I want to use a progress bar so that I can show a percentage of tasks that have been completed.

If you look at this example, taken from the Bootstrap Docs, you can see the width is set on the .progress-bar element. That width is what sets the 'completeness' of the bar. So for 70% done, set its width to 70%.
Relevant code from Bootstrap:
<div class="progress">
<div class="progress-bar" style="width: 60%;" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
<span class="sr-only">60% Complete</span>
</div>
</div>

Bootstrap Progress Bar implementation for HTML Forms:
-This scripts creates an event handler.
-When the user switches input element (form-group in this case), it increments the progress bar status by 20% (there are 5 inputs in my form).
let progressBar = document.getElementsByClassName("progress-bar")[0];
$('.form-group').focusout(function() {
let currentValue = parseInt(progressBar.style['width']);
progressBar.style['width']=currentValue+20+"%";
});
You can find some examples here

Related

best way to sort by id on the index view

I have a gossip controller and model and before i've got this way to display all my gossips in the index view :
My controller :
def index
#gossips = Gossip.all
end
My view index.html.erb :
<% #gossips.each do | gossip | %>
<div class="card gossip-card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title"><%= gossip.title %></h5>
<h6 class="card-subtitle mb-2 text-muted"><%= gossip.user.username %></h6>
<%= link_to "Read", gossip_path(gossip), :class => "btn btn-info" %>
<%= link_to "Edit", edit_gossip_path(gossip), :class => "btn btn-success" %>
<%= link_to "Delete", gossip_path(gossip), :class => "btn btn-danger", method: :delete, data: { confirm: "Are you sure?"} %>
</div>
</div>
<% end %>
But when I edit a gossip it goes all the way down to the last position, probably because they are sorted by modification date.
So i've found this solution for my controller :
def index
#gossips = Gossip.all.sort_by { |gossip| gossip.id }
end
I would like to know if it is normal that my gossips are normally sorted by date of modifications and if it was possible to do this more cleanly to sort them by id than what I did.
You probably want leave sorting on your database:
def index
#gossips = Gossip.order(:id)
end
Never ever use .all in any controller or model or anywhere. For your use case
# for ascending order
def index
#gossips = Gossip.order(:id)
end
# for descending order
def index
#gossips = Gossip.order(created_at: :desc)
end
Also try to refer Rails docs for reference.
https://guides.rubyonrails.org/active_record_basics.html#read

Recurring Action template error ruby on rails

I keep on having this error
ActionView::Template::Error (undefined method `each' for nil:NilClass):
Here's my show.html.erb
<% #bookings.each do |booking| %>
<% if booking.checkin_on > Date.today %>
<% if booking.status == "Confirmed" %>
<li class="dashboard">
<%= cl_image_tag(booking.bed.photo.path, width: 400, height: 300, crop: :fill, class: "pdt-image hidden-xs" ) %>
<div class='product-body'>
<h2><%= booking.bed.title %></h2>
<p>City: <strong><%= booking.bed.city %></strong></p>
<p>Address: <strong><%= booking.bed.address %></strong></p>
<p>Total price: <strong><%= booking.value %> €</strong></p>
</div>
<div>
<ul class="list-unstyled hidden-sm hidden-xs padded">
<li><strong>Your booking is confirmed !</strong></li>
<li class="text-right"><%= link_to "Delete this booking", booking_path(booking), method: :delete, class:"btn btn-default", data: {confirm: "Are you sure"} %> </li>
</ul>
</div>
</li>
<% end %>
<% if booking.status == "Canceled" %>
<li class="dashboard">
<%= cl_image_tag(booking.bed.photo.path, width: 400, height: 300, crop: :fill, class: "pdt-image hidden-xs" ) %>
<div class='product-body'>
<h2><%= booking.bed.title %></h2>
<p>City: <strong><%= booking.bed.city %></strong></p>
<p>Address: <strong><%= booking.bed.address %></strong></p>
<p>Total price: <strong><%= booking.value %> €</strong></p>
</div>
<div>
<ul class="list-unstyled hidden-sm hidden-xs padded">
<li><p><%= booking.bed.user.first_name%> canceled your booking </p></li>
</ul>
</div>
</li>
<% end %>
<% end %>
<% end %>
And here's my my_bookings controller
class My::BookingsController < ApplicationController
def index
#bookings = Booking.where(user_id: current_user.id)
#bookings = Booking.all
#beds = Bed.all
end
def show
set_booking
#bed = #booking.bed
end
private
def set_booking
#booking = Booking.find(params[:id])
end
end
Any suggestions? Or anything I can't see? I have tried almost everything I can think of at the moment. Thanks!
You are not declairing the #bookings variable on your show method, which explains the crash. It appears you are declaring it as you wanted it on the first line of your index method. Just change where you declare it, and it shall be alright.
Also, to avoid further headaches, you should refactor the set_booking method to:
def set_booking
#booking = Booking.find_by(id: params[:id])
end
by deafult .find() will crash your view if it doesn't find anything
.find_by, on the other hand, will return an empty answer, so it won't crash. Also, it's more versatile, since this way you can search from innumerous other variables set in your model, i.e. name.
By convention in Rails controller actions (index and show in your case) render views with same names, in your case those might be intex.html.erb and show.html.erb. In your show method you define two variables: #bed and #booking and in your view (show.html.erb) you try to loop variable #bookings which you have not defined in your controller action. Thus, you are getting this error.
Looks like you need to rename show.html.erb to index.html.erb as you are listing bookings and their information in it.

Want to refresh only favorite and not the entire page

Hi there it's the third I ask you to help me on this point.
I don't know how to explain it because I read some tutorials or answers but I don't understand what can I do.
Ok I am working on an app to learn Japanese language with hiragana flashcards.
I created a feature to add a card as a favorite. When I click on a grey color heart, the heart becomes in red color and it saves in an index favs page.
The problem is when I click to add as favorite the full page is loaded and I don't want it. I just wnat have the heart object which changes of state.
I would use ajax and javascript but I don't know what can I call and which is the syntax. I have ever read http://guides.rubyonrails.org/working_with_javascript_in_rails.html
And Try to do the same but it doesn't work.
here is the favs 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
# redirect_to favs_path
# redirect_to :back
render json: #fav
end
def destroy
#fav = Fav.find(params[:id])
#fav.destroy
redirect_to :back
end
end
Above I choose to redirect as a json format but now
here is the render favorite view
<% 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 the index hiraganas view where the favs render is located
<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>
I try to call it with this javascript code but i don't where I can place it and how do I have to call the file .js.erb? (I put it in application.js for now but it doesn't communicate with the rest of my code)
application.js
$(document).ready(function() {
$('.faved-on').click(function() {
var fav = $('.faved-off')
$.ajax({
type: "POST",
url: "/hiraganas",
dataType: "json",
success: function(data) {
console.log(data);
},
error: function(jqXHR) {
console.error(jqXHR.responseText);
}
});
})
})
Help will be appreciated :).
Have you tried this: http://guides.rubyonrails.org/working_with_javascript_in_rails.html#link-to ?
There is a simple "remote: true" to add inside your link_to code. Something like that:
<%= link_to hiragana_favs_path(hiragana), class: "add-to-favorite", method: :post, remote: true do %>
<i class="fa fa-heart faved faved-off"></i>
<% end %>
Then to perform some special actions in your Coffee (JS), you could do:
$ ->
$("a.add-to-favorite").on "ajax:success", (e, data, status, xhr) ->
console.log(data)
alert "Favorite added."
And you can do the same thing for the other link_to (the :delete one).
Also I would rather use "button_to" instead of "link_to method: :post" as you did, as "link_to" should not really be used to POST data. Button_to is a simple helper that works like link_to but is replaced by a form, which is better to post data. :)
Of course you don't have to, but it'd be better this way. :)
Let me know if it worked. If not, add comments and edit your question to add more info, I'll try to help you more by editing my answer and adding more info.

Rails 4 - Combine Params from Previous Page (Pass Array in Hidden Field?)

On Rails 4. I'm working on an e-commerce app where a user can choose to go through a wizard-like process.
First the user selects a color scheme,
then selects products from two different pages,
then the results of those product selections are displayed on a fourth page.
No rows are created or updated in the database, I just want the results to be displayed on the fourth page (because this info is then fed to a third-party service).
Because the array would be no more than five or six choices, I am passing the product ids through the URL params. Here's the controller (let's say on the second page the user selects paper products and on the third page the user selects pencil products)
class WizardController < ApplicationController
def index
# Where the user clicks on a color scheme link
end
def paper
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
end
def paper_submit
respond_to do |format|
format.html { redirect_to wizard_pencils_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
id: params[:ids]) }
end
end
def pencils
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
#paper = Product.find(params[:id])
end
def pencils_submit
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
id: params[:ids] + [:paper_ids]) } # ?? Not sure what goes here
end
end
def finish
# Haven't gotten here yet
end
private
def color_scheme_params
params.require(:wizard).permit(:color_scheme_id, :id)
# Also not too sure about this area either
end
end
Routes:
get '/wizard/paper', controller: 'wizard', action: 'paper'
put '/wizard/paper', controller: 'wizard', action: 'paper_submit'
get '/wizard/pencils', controller: 'wizard', action: 'pencils'
put 'wizard/pencils', controller: 'wizard', action: 'pencils_submit'
get '/wizard/finish', controller: 'wizard', action: 'finish'
resources :wizard
Form for the second page (selecting paper products)
<%= form_for([#color], html: {multipart: true}, url: {action: "paper_submit"}, method: 'put') do |f| %>
<%= f.hidden_field(:color_scheme_id, value: #color.id) %>
<div class="row">
<% #product.where(enabled: true, color_scheme_id: #color).each do |product| %>
<% if product.tags.where(name: "Paper").count > 0 %>
<div class="col-lg-3 col-md-4 col-sm-6">
<%= check_box_tag 'ids[]', product.id -%>
<%= link_to image_tag(product.thumbnail.url(:thumbnail_small_opt), alt: product.name), product %>
<p><%= link_to product.name, product %>, $<%= product.price %></p>
</div>
<% end %>
<% end %>
</div>
<div class="row">
<div class="col-lg-12">
<p style="text-align:right;"><%= f.submit "Next: Select Pencils", class: "btn bg-primary" %></p>
</div>
</div>
<% end %>
So far this all works fine. But, the problem is when the user makes product selections on the third page and reaches the fourth page. Ideally I want my application to combine the product id params from the second page with the different product ids from the third page.
<%= form_for([#color], html: {multipart: true}, url: {action: "embellishments_submit"}, method: 'put') do |f| %>
<%= f.hidden_field(:color_scheme_id, value: #color.id) %>
<!-- A hidden field maybe?? This does not work though -->
<%= f.hidden_field(:paper_ids, multiple: true, value: #paper) %>
<div class="row">
<% #product.where(enabled: true, color_scheme_id: #color).each do |product| %>
<% if product.tags.where(name: "Pencil").count > 0 %>
<div class="col-lg-3 col-md-4 col-sm-6">
<%= check_box_tag 'ids[]', product.id -%>
<%= link_to image_tag(product.thumbnail.url(:thumbnail_small_opt), alt: product.name), product %>
<p><%= link_to product.name, product %>, $<%= product.price %></p>
</div>
<% end %>
<% end %>
</div>
<div class="row">
<div class="col-lg-12">
<p style="text-align:right;"><%= f.submit "Next: Purchase Your Selections", class: "btn bg-primary" %></p>
</div>
</div>
<% end %>
It seems like a simple thing, I just want to combine an array from two different pages from the URL params but I can't figure out how to do this. Don't really want to use a gem for this because this is all I need to figure out. Thanks for any help.
Just put your variables into session:
def paper_submit
session[:paper_ids] = params[:ids]
respond_to do |format|
format.html { redirect_to wizard_pencils_path(
color_scheme_id: params[:color_scheme][:color_scheme_id]
) }
end
end
def pencils
#color = ColorScheme.find(params[:color_scheme_id])
#product = Product.all
#paper = Product.find(params[:id])
end
def pencils_submit
session[:pencil_ids] = params[:ids]
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id]
) }
end
end
def finish
#all_products = Product.where(
enabled: true,
color_scheme_id: params[:color_scheme_id],
id: session[:paper_ids] + session[:pencil_ids]
)
end
finish.html.erb:
<% #all_products.each do |product| %>
<%= product.name %>
<br />
<% end %>
You should add those two arrays and make something like:
def pencils_submit
respond_to do |format|
format.html { redirect_to wizard_finish_path(
color_scheme_id: params[:color_scheme][:color_scheme_id],
product_ids: params[:ids] + [:paper_ids]) }
end
end
Then in your form:
<% #product_ids.each do |id| %>
<%= f.hidden_field_tag 'product_ids[]', id %>
<% end %>
Then in your last finish action do whatever you want.

Rails - unsuccessful edit in modal on index site

I have a list of group and I want to edit a single group name via modal. I use edit.js.erb file and bootstrap modal.
There are two cases, both wrong.
First:
Using "remote: true" in Partial and link_to(in single row file)
Then modal is displaying, but after SAVE button clicked always is rendering again and never close. (I don't know why)
Second:
Delete remote:true from partial.
Then modal is displaying, I can even save the changes. But when I type wrong name (blank or too long), line "render 'edit'" from Controller crash. (error: "Missing template groups/edit, application/edit...". I think rails doesn't know about edit.js.erb then, but how to repair it?
Have you got any ideas about this situation ?
Controller
def edit
#group = current_user.groups.find_by(id: params[:id])
respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
end
end
def update
#group = current_user.groups.find_by(id: params[:id])
if #group.update_attributes(group_params)
flash[:success] = "Nazwa grupy została zmieniona"
redirect_to groups_path
else
render 'edit'
end
end
Partial for displaying form_for in modal
<%= form_for(#group, remote: true) do |f| %>
<div>
<%= render 'shared/error2_messages', object: f.object%>
<p>
<%= f.label :name, "Nazwa" %>
<%= f.text_field :name, class: 'form-control'%>
</p>
</div>
<%= f.submit yield(:button_name), class: "btn btn-primary" %>
<% end %>
edit.js.erb file
<% provide(:button_name, 'Zapisz zmiany') %>
$('.modal-title').html("Edytuj nazwę grupy");
$('.modal-body').html("<%= escape_javascript( render partial: 'layouts/group_data_form', locals: {group: #group} ) %>");
$('#myModal').modal();
Single row in a list
<li id="group-<%= group.id %>" class="list-group-item">
<span class="group-name"><%= group.name %></span>
<%= link_to edit_group_path(group.id), remote: true, :class => "edit-option btn" do %>
<i class="fa fa-pencil-square-o fa-2x" ></i>
<% end %>
<%= link_to group, method: :delete, data: { confirm: "Na pewno chcesz usunąć tę grupę?" }, :class => "delete-option btn btn-danger" do %>
<i class="fa fa-trash-o" > usuń</i>
<% end %>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Zmień nazwę grupy</h4>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Anuluj</button>
</div>
</div>
</div>
</div>
This looks like a follow-up to your question of yesterday.
I won't say both your approaches are wrong, I'll say you are conbining two right approaches in such a way...
(1) since you used js to send save (with the use of remote: true on your form), all you need to do is to close the modal on successful save as will be defined from update.js.erb (just like you defined an edit.js.erb for the format.js in edit) as follow:
#update.js.erb
<% if #group.errors.empty? %>
$('.modal-body').html("");
$('#myModal').modal('hide');
$("#notice").html("Group was successfully updated.");
<% else %>
$("#notice").html("Error! Group not updated.");
<% end %>
#controller update action
def update
#group = current_user.groups.find_by(id: params[:id])
#group.update_attributes(group_params)
respond_to do |format|
format.html
format.js
end
end
What you essentially did here is to check if there is no error in the #group object(this will be true if #group got saved), then emptied your Modal and then hid it from view.
(2) When you removed remote: true you are no longer using js, so when you have a wrong name, the update does not work, and the render :edit portion of your update method kicks in. However, your edit action only specifies format.js, So what you may have to do in this case is to add format.html if you want to call with html.
def edit
#group = current_user.groups.find_by(id: params[:id])
respond_to do |format|
format.js # actually means: if the client ask for js -> return file.js
format.html
end
end
Note however that this may not open your modal, it will go to the edit_group_path of your app, which is the /groups/:id/edit

Resources