How do you Display Avarage Rating in index page? - ruby-on-rails

I'm trying to display average ratings for jobs on my index page, it works perfectly fine on my show page
but on my index page the stars are there but are blank, how do i get them to display on my index page?
My Show Page:
<h4>Average Rating</h4>
<div class="average-review-rating" data-score=<%= #average_review %>></div>
<span class="number-of-reviews">Based on <%= #job.reviews.count %> reviews</span>
</div>
</div>
<script>
$('.review-rating').raty({
readOnly: true,
score: function() {
return $(this).attr('data-score');
},
path: '/assets/'
});
</script>
<script>
$('.average-review-rating').raty({
readOnly: true,
path: '/assets/',
score: function() {
return $(this).attr('data-score')
}
});
</script>
Jobs Show controller
def show
if #job.reviews.blank?
#average_review = 0
else
#average_review = #job.reviews.average(:rating).round(2)
end
end
My Index Page:
<% #jobs.each do |job| %>
<%= link_to job.title, job_path(job) %></h4>
<%= job.category %></p>
<%= job.city %>
<div class="average-review-rating" data-score=<%= average_review %>></div>
<span class="number-of-reviews">Based on <%= job.reviews.count %> reviews</span>
</div>
</div>
<% end %>
<script>
$('.average-review-rating').raty({
readOnly: true,
path: '/assets/',
score: function() {
return $(this).attr('data-score')
}
});
</script>

In your show page, you have #average_review defined. I'm guessing this was done in your jobs controller in the show action.
In your index page, you will need to calculate the average rating for each job as you are iterating through them. You can do this the same way you defined #average_rating. If you are defining your #average_rating in the show action as:
#average_rating = job.reviews.sum('score') / job.reviews.count
You will need to either define this method in the model (the better option), so something like:
app/models/job.rb
def average_review
reviews.sum('score') / reviews.count
end
Then in your index page:
<div class="average-review-rating" data-score=<%= job.average_review %>></div>
The other option is to set a variable for each object on the index page itself, less work but probably not as neat:
<% #jobs.each do |job| %>
<%= link_to job.title, job_path(job) %></h4>
<%= job.category %></p>
<%= job.city %>
<% average_review = job.reviews.sum('score') / job.reviews.count %>
<div class="average-review-rating" data-score=<%= average_review %>></div>
<span class="number-of-reviews">Based on <%= job.reviews.count %> reviews</span>
</div>
</div>
<% end %>
EDIT:
In your app/models/job.rb
def average_review
reviews.blank? ? 0 : reviews.average(:rating).round(2)
end
And index.html.erb
<div class="average-review-rating" data-score=<%= job.average_review %>></div>

You can fetch these results like so:
def index
#jobs = Job.all
#average_reviews = Review.where(job_id: #jobs)
.group(:job_id)
.average(:rating)
.transform_values { |rating| rating.round(2) }
end
This will return a hash with job ids as keys and the average rating as value (rounded to 2 decimals). To access these average ratings you can do the following in your index view:
#jobs.each do |job|
average_review = #average_reviews[job.id]
end
The above code only makes 2 SQL calls, 1 for fetching your jobs and 1 for fetching all average reviews for all the fetched jobs. Keep in mind that if a job has no reviews. When fetching the average rating from the hash the value nil is returned.

Related

Rails query: Find first record value and display in form

I'm currently trying to display the first record. The record is updated when someone decides to buy a wine. How would I get the first record for the specific wine ?
I thought of using .find(1)? but how would implement this into my controller ?
My current controller:
def create
wine = Wine.find(params[:wine_id])
if current_user == wine.user
flash[:alert] = "Du kannst nicht deinen eigenen Wein kaufen!"
else
start_date = Date.parse(reservation_params[:start_date])
#reservation = current_user.reservations.build(reservation_params)
#reservation.wine = wine
#reservation.price = wine.price
#reservation.in_stock = wine.in_stock - #reservation.bottle
#reservation.total = wine.price * #reservation.bottle
wine.update(in_stock: #reservation.in_stock)
# #reservation.save
if #reservation.save
if wine.Reservieren?
flash[:notice] = "Reserviert!"
else
#reservation.Versendet!
flash[:notice] = "Eroflgreich bestellt!"
end
else
flash[:alert] = "Can't make a reservation!"
end
end
redirect_to wine
end
My current view:
<% #wines.each do |wine| %>
<div class="row">
<div class="col-md-3">
<%= link_to wine.wine_name, wine_path(wine) %>
</div>
<div class="col-md-3">
<%= wine.in_stock %> <!-- Display first record -->
</div>
<div class="col-md-3">
<% if !wine.in_stock.blank? %>
Aktiv
<% else %>
Nicht Aktiv
<% end %>
</div>
<div class="col-md-3 right">
<%= link_to "Update", details_wine_path(wine), class: "btn btn-form" %>
</div>
</div><!-- row -->
<hr/>
<% end %>
Maybe you can explain a little better your code, because you receive #wines in your view and it is not coming from this controller action that you posted.
But if you want to take the first register you can basically call wines.first.
You would change from <%= wine.in_stock %> to <%= #wines.first %> for example.
Here is some thread related:
Display first record in rails

undefined local variable or method `nominations_data'

Currently unable to pass information from the cycles controller to the cycle_nominees_table.html.erb using partials.
The data is defined in my controller show method.
And the show method has information in the #nominations_data and #nominations_team_data.
Why cant my _cycles_nominations_table.html.erb access nominations_data thats being passed into the partial?
Ive been using this link for direction.
Code Below:
app/controllers/cycles_controller.rb
def show
...
#nominations_data = {}
#nominations.each do |nomination|
#nominations_data[nomination.for_user_id] ||= {}
#nominations_data[nomination.for_user_id][:nominee] ||= nomination.for_user
if user_is_admin
#nominations_data[nomination.for_user_id][:nominations] ||= []
#nominations_data[nomination.for_user_id][:nominations].push nomination
end
if user_is_admin_or_reviewer
#nominations_data[nomination.for_user_id][:count] ||= 0
#nominations_data[nomination.for_user_id][:count] += 1
end
end
#nominations_data = #nominations_data.sort_by { |_nid, nomination| nomination[:nominee].name }
#nominations_team_data = {}
#team_nominations.each do |nomination|
#nominations_team_data[nomination.for_user_id] ||= {}
#nominations_team_data[nomination.for_user_id][:nominee] ||= nomination.for_user
if user_is_admin
#nominations_team_data[nomination.for_user_id][:nominations] ||= []
#nominations_team_data[nomination.for_user_id][:nominations].push nomination
end
if user_is_admin_or_reviewer
#nominations_team_data[nomination.for_user_id][:count] ||= 0
#nominations_team_data[nomination.for_user_id][:count] += 1
end
end
#nominations_team_data = #nominations_team_data.sort_by { |_nid, nomination| nomination[:nominee].name }
end
app/views/cycles/show.html.erb
<div class="container-float-right-small" id="cycle-nominees-section">
<h2 class="inline">Nominees for <%= #cycle.name %></h2>
<h4 class="inline"> - (<%= #cycle.votes_per_reviewer %> votes allowed)</h4>
<h5> Indivdual Nominees: </h5>
<!-- <%= render "cycles/cycle_nominees_table" %>-->
<%= render partial: "cycles/cycle_nominees_table", locals: { nominations_data: #nominations_data } %>
<h5> Team Nominees: </h5>
<!-- <%= render "cycles/cycle_nominees_table" %>-->
<%= render partial: "cycles/cycle_nominees_table", locals: { nominations_data: #nominations_team_data } %>
</div>
app/views/cycles/_cycle_nominees_table.html.erb
<% if nominations_data.empty? %>
<th class="center" colspan="4"><h3>There are no nominees <%= "for cycle '#{#cycle.name}'" if #cycle %></th>
<% end %>
</thead>
<tbody>
<% nominations_data.each do |nid, data| %>
<tr id='<%= "nominee-row-#{nid}" %>' class="nominee-row">
<% if user_is_reviewer && #cycle.voting_open %>
<td class="center">
<% nomination_icon_class = "voted_for" if Vote.where(cycle_id: #cycle.id, by_user_id: current_user.id, for_user_id: data[:nominee].id).count > 0 %>
<span class="glyphicon glyphicon-check pointer <%= nomination_icon_class %>" id=<%= "vote_for_nominee_#{nid}" %> onclick="<%= "Vote.send_vote_data(this, #{data[:nominee].id}, #{#cycle.id})" %>"></span>
</td>
<% end %>

Action Listener on ruby on rails?

I have this project: https://todo-app-back-end-prospeed.c9users.io/
It's basically a reminder web app. I trying to add a function in which the user clicks on the checkbox and the value <Todo id: 24, description: "Publish project", pomodoro_estimate: 1, complete: nil the complete: nill changes to complete: true or false `
<body>
<div class="container2">
<h1 id ="list">Workshop Todo List</h1>
<ul>
<% #todos.each do |todo| %>
<li>
<label class="container">
<input type="checkbox"/ checked="checked">
<%= todo.description %>
<span class="pomodoro-estimate"><%= todo.pomodoro_estimate %> pomodoro</span>
<span class="checkmark"></span>
</label>
</li>
<% end %>
</ul>
<a class="noColor" href="/new/"><input class="add-new-todo-button" type="submit" value="Add todo"/></a>
<h1 id="Pomodoro-technique">What is a pomodoro estimate?</h1>
<p id="Pomodoro-technique-info">
<strong>1 pomodoro = 25 minutes + 5 minutes break.</strong><br>
For more info: https://www.focusboosterapp.com/the-pomodoro-technique
</p>
</div>
</body>
ToDoController:
class TodoController < ApplicationController
def index
#todos = Todo.all
end
def show
# Gets number user typed in URL
todo_id = params[:id]
#Grab the todo with that id from the database
#todo = Todo.find_by_id(todo_id)
end
def new
#
end
def create
t = Todo.new
t.description = params['description']
t.pomodoro_estimate = params['pomodoro_estimate']
t.save
redirect_to "/show/#{t.id}"
end
def destroy
t = Todo.find_by_id(params[:id])
t.destroy
redirect_to "/"
end
def edit
#todo = Todo.find_by_id(params[:id])
end
def update
t = Todo.find_by_id(params['id'])
t.description = params['description']
t.pomodoro_estimate = params['pomodoro-estimate']
t.save
redirect_to "/show/#{t.id}"
end
end
What kind of controller would I need? How does it know when It is clicked?
I would just like to be pointed in the right direction
Your checkbox in your view is not good I think. You need something like:
<%= f.check_box: field, {}, true %>

How to display a selection based on user input using ajax and jquery

Think of the below as a bike rental. Someone fills out a form and gets a bike assigned to them which they can rent and borrow for a certain amount of time.
The problem I am having is I am trying to show the person who wants to rent the bikes what bikes are available before they submit the form. Below is my attempt using ajax. I have no errors but also my select is not updating.
request controller methods below
def new
#bikes = Bike.available_based_on_request_date(params[:Borrow_date], params[:Return_date])
#new_request = Request.new
end
create method below (with a temporary workaround, that reloads the form with a warning about availability.)
def create
#request = Request.new(request_params)
available_bikes = #request.new_request(current_user.id)
if (available_bikes >= #request.number_of_bikes_wanted) && #request.save
redirect_to root_path
else
flash[:warning] = "You have requested more bikes than available. There are only #{available_bikes} bikes available"
redirect_to new_request_url
end
end
params in request controller
def request_params
params.require(:request).permit(:Borrow_time, :Borrow_date,
:Return_date, :Return_time,
:number_of_bikes_wanted, bike_ids: [])
end
new.html.erb view
<div class="form" align = "center">
<%= render 'form.js.erb' %>
</div>
_form.js.erb below
<script type="text/javascript">
$(document).ready(function() {
$('.my-date').on('change', function() {
var data = {}
$('.my-date').each(function() {
if($(this).val()) {
data[$(this).attr("id")] = $(this).val();
}
});
if(Object.keys(data).length > 1) {
$.ajax({
type: "POST",
url: <%= new_request_path %>,
data: data
});
}
});
});
var options = "";
<% #bikes.each do |bike| %>
options += "<option value='<%= bike.id %>'><%= bike.name %></option>"
<% end %>
$('#request_number_of_bikes_wanted').html(options);
</script>
<div class="block-it" align=center>
<br>
<%= form_for #new_request do |request| %>
<%= request.label :Borrow_date, 'Borrow on' %>
<%= request.date_field :Borrow_date, id: 'Borrow_date', class: 'my-date', min: Date.today, :required => true %>
<%= request.label :Borrow_time, 'Borrow at' %>
<%= request.time_field :Borrow_time, value: '10:00', min: '9:00 AM', max: '4:30 PM', default: '10:00 AM', :ignore_date => true, :required => true %>
<br><br>
<%= request.label :Return_date, 'Return On' %>
<%= request.date_field :Return_date, id: 'Return_date', class: 'my-date', min: Date.today, :required => true %>
<%= request.label :Return_time, 'Return at' %>
<%= request.time_field :Return_time, value: '10:00', min: '9:00 AM', max: '4:30 PM', default: '10:00 AM', :ignore_date => true, :required => true %>
<br><br>
<br><br>
<%= request.label :NumberOfBikesWanted, 'Number of bikes' %>
<%= request.select :number_of_bikes_wanted, %w(select_bike), :required => true %>
<br>
<%= request.submit 'Submit' %>
<%= request.submit 'Reset', :type => 'reset' %>
<% end %>
<br>
</div>
There are a two main problems with your code:
Controller
Use a different action to set the endpoint that you will call with ajax, so instead of this:
def new
#bikes = Bike.available_based_on_request_date(params[:Borrow_date], params[:Return_date])
#new_request = Request.new
end
Try this:
def bikes
#bikes = Bike.available_based_on_request_date(params[:Borrow_date], params[:Return_date])
def new
#new_request = Request.new
end
If you want to keep REST routes, then create a new controller and use the index action within that controller.
Form
This code:
var options = "";
<% #bikes.each do |bike| %>
options += "<option value='<%= bike.id %>'><%= bike.name %></option>"
<% end %>
$('#request_number_of_bikes_wanted').html(options);
doesn't belong here, it must be deleted from your file and instead put it on a new file called bikes.js.erb; also rename your form to _form.html.erb.
And update your ajax call to use your new route:
$.ajax({
type: "POST",
url: <%= bikes_path %>,
data: data
});
What you want to setup is a new endpoint but instead of returning html, it will return a js. But you must treat it as an independent action, just as any other action in rails. The only difference is how you call that action (ajax) and how you respond to it (js).

How do I use the Quicksand jQuery plugin with a Rails AJAX request?

I am trying to use the Quicksand jQuery plugin to decorate the response of an AJAX call in Rails:
Link:
<% Project.services.each_with_index do |service, index| %>
<%= link_to_function(service, "regatherProjects('#{service}', #{index})", :id => "service_link_#{index}") %>
<%= " / " if !index.eql?(Project.services.length - 1) %>
<% end %>
JS:
function regatherProjects(service_name, service_id) {
$.get("/index_project_update", { service: service_name }, function(data) {
$('#home_projects').quicksand($(data), {
adjustHeight: 'dynamic'
});
});
$('#home_services').find('a').removeClass("on");
$('#service_link_' + service_id).addClass("on");
};
Controller:
def index_project_update
if params[:service] && !params[:service].blank?
#projects = Project.highlighted.where(:service => params[:service])
else
#projects = Project.highlighted
end
end
View:
$("#home_projects").replaceWith("<%= j(render('projects')) %>")
Projects:
<div id="home_projects">
<% if #projects.empty? %>
<p>No projects. <%= link_to_function("View All", "regatherProjects('')") %>.</p>
<% else %>
<ul class="all_projects">
<% #projects.each_with_index do |project, index| %>
<li data-id="<%= project.customer.name.underscore.downcase %>_<%= project.name.underscore.downcase %>">
<%= link_to(image_tag(project.project_images.first.image.home), project) %>
</li>
<% end %>
</ul>
<% end %>
</div>
I think the problem is that the data returned by the AJAX request (see below) is not in the format that Quicksand expects it to be in but I'm not sure how to extrapolate the relevant information from the response. The response from my AJAX request is something like:
$("#home_projects").replaceWith("<some><html><that><i><need>")
So, the problem is that it's using the above code as the destination code for the Quicksand call when it should be using the replacement HTML:
<some><html><that><i><need>
The AJAX request works perfectly fine, but I need to integrate Quicksand into here.
I need:
a better way to do this or;
a way to extrapolate the argument for replaceWith() in the aforementioned code to use as the destination code for Quicksand.
If I've omitted any information you think you need to help, please ask.
This is the first question I've asked on Stack Overflow so I feel obligated to apologise for any misusage.
If anyone runs into a similar issue, the following worked for me in Chrome, Firefox, IE9, IE8 and IE7.
Link:
<% Project.services.each_with_index do |service, index| %>
<%= link_to_function(service, "regatherProjects('#{service}', #{index})", :id => "service_link_#{index}") %>
<%= " / " if !index.eql?(Project.services.length - 1) %>
<% end %>
JS:
function regatherProjects(service_name, service_id) {
$.get("/index_project_update.html", { service: service_name }, function(data) {
$('.all_projects').quicksand($(data).find('li'), {
adjustHeight: 'dynamic'
});
});
$('#home_services').find('a').removeClass("on");
$('#service_link_' + service_id).addClass("on");
};
Route:
match '/index_project_update' => 'application#index_project_update', :defaults => { :format => 'html' }
Controller:
def index_project_update
if params[:service] && !params[:service].blank?
#projects = Project.highlighted.where(:service => params[:service])
else
#projects = Project.highlighted
end
render :layout => false
end
View:
<%= render('application/index/projects') %>
Projects:
<div id="home_projects">
<% if #projects.empty? %>
<ul class="all_projects">
<li data-id="project">No projects. <%= link_to_function("View All", "regatherProjects('')") %>.</li>
</ul>
<% else %>
<ul class="all_projects">
<% #projects.each_with_index do |project, index| %>
<li data-id="project_<%= project.id %>">
<%= link_to(image_tag(project.project_images.first.image.home, :alt => (project.customer.name + " - " + project.name), :title => (project.customer.name + " - " + project.name)), project) %>
</li>
<% end %>
</ul>
<% end %>
</div>

Resources