How to render different versions of the same file? - ruby-on-rails

For example I have this file:
_goal.html.erb
<table>
<tr>
<%= goal.name %>
<span class="label label-info"><%= goal.deadline.strftime("%d %b %Y") %></span>
</tr>
</table>
It is being rendered from the home page:
<h1><b>Goals</b></h1>
<%= render #unaccomplished_goals %>
<%= render #accomplished_goals %>
<% end %>
How can we wrap an accomplished goal with <span class="label label-info-success"> but if it is an unaccomplished goal keep it <span class="label label-info">?
In the controller:
#accomplished_goals = current_user.goals.accomplished
#unaccomplished_goals = current_user.goals.unaccomplished
Here was my latest attempt, which just made them all -info:
<% if #unaccomplished_goals == true %>
<span class="label label-info"><%= goal.deadline.strftime("%d %b %Y") %></span>
<% else #accomplished_goals == true %>
<span class="label label-warning"><%= goal.deadline.strftime("%d %b %Y") %></span>
<% end %>
Maybe you'll have more luck :)
Thank you so much.

Create a helper method that returns the correct classes for the goal's status. In application_helper.rb:
def deadline_label_class(goal)
if goal.accomplished?
'label label-info'
else
'label label-warning'
end
end
This assumes that Goal has an instance method called accomplished? which returns true/false. You may have to write that method if it doesn't exist or use some other criteria.
Then use the helper in the _goal.html.erb template:
<table>
<tr>
<%= goal.name %>
<span class="<%= deadline_label_class(goal) %>">
<%= goal.deadline.strftime("%d %b %Y") %>
</span>
</tr>
</table>

Related

Rails search function rendering page multiple timess

I have a search function in rails that should render a page to display the grants that were picked up by the search. However when you search, the template is rendered multiple times instead of just once, and its rendered on top of itself so it looks like a cluttered mess. I'm not sure where the error is but it must be calling render more than once. Heres my controller method:
def index
if params[:search]
#grants = Grant.search(params[:search]).order("created_at DESC")
else
#grants = Grant.all.order('created_at DESC')
end
end
And the part of my view where I render the template
<% if #grants.present? %>
<%= render #grants %>
<% else %>
<p>There are no grants containing the term(s) <%= params[:search] %>.</p>
<% end %>
<%= yield %>
and the template;
<html>
<body>
<style>div {
margin-left:17%;
padding:1px 16px;
height:1000px;}
</style>
<div>
<center>
<hr style="height:5 px; visibility:hidden;" />
<br>
<font size=6 >
<strong>
US Federal Grants
<br>
<br>
<hr style="height:5 px; visibility:hidden;" />
</strong>
</font>
</center>
<% if #grants != [] && #grants != nil%>
<table border="1" style="width:100%">
<tr>
<td><strong><font size=5>Title</font></strong></td>
<td><strong><font size=5>Award Ceiling</font></strong></td>
<td><strong><font size=5>Description</font></strong></td>
<td><strong><font size=5>Additional Information</font></strong></td>
<td><strong><font size=5>Closing Date</font></strong></td>
</tr>
<% for item in #grants %>
<tr>
<td><%= item.title %></td>
<% if item.ceiling != '$0' && item.ceiling != nil && item.ceiling != '' && item.ceiling != '$1' && item.ceiling != '$2'%>
<td><%= item.ceiling %></td>
<% else %>
<td> See link for more information </td>
<% end %>
<% if item.description == "" %>
<td>See link for more information</td>
<%elsif item.description == nil%>
<td>See link for more information</td>
<% elsif item.description.sub('Description:', '').length > 720 %>
<td>
<%= truncate(item.description.sub('Description:', ''), length: 720) %>
<%= link_to 'Read more', '', class: "read-more-#{item.id}" %>
<script>
$('.read-more-<%= item.id %>').on('click', function(e) {
e.preventDefault()
$(this).parent().html('<%= escape_javascript item.description.sub('Description:', '') %>')
})
</script>
</td>
<%else%>
<td> <%=item.description.sub('Description:', '')%></td>
<%end%>
<td><center> <a href= <%= item.link %>>LINK</a><center></td>
<%unless item.date == nil%>
<td><% newdate = Date.parse item.date %>
<%= newdate.strftime("%D") %>
</td>
<%end%>
</tr>
<% end %>
<% else %>
<center>
<p> There are no Grants available to Entrepreneurs in this category at this time. However this list updates daily based on Grants.gov data, so feel free to check back later. </p>
</center>
<% end %>
</table>
</div>
</body>
</html>
I'm not sure where its happening but it seems to be rendering it about 25 times
You've accidentally encountered Rails collection rendering. You can read more about it here: https://robots.thoughtbot.com/rendering-collections-in-rails
When you do
<%= render #grants %>
Rails interprets this as you wanting to render the grants/_grant.html.erb (I think – or some similar path) partial once for each grant.
If you instead want to render it only once, try
<%= render "grants/grant" %>
(Renaming the partial to something like "_grants.html.erb" and rendering that might also be a good idea, just so it doesn't look like it's intended to render a single grant.)

Agenda calendar/roster view

I would like to display an agenda that shows who is available for roster for the next seven days, with the following logic:
Looping through each of the 7 days, for each day:
If the leave starts today, show Starts %H:%M
If the leave finishes today, show Finishes %H:%M
If the leave starts and finishes today, show %H:%M - %H:%M
If the leave doesn't start or finish today but spans over today, show all day
Should include leave that start or finish outside of the 7 days but span the 7 days being displayed.
I am hoping for someone to point me in the right direction preferably using Rails and Postgres. I am not against doing the queries for each day since at most there will only be 30 days displayed, but also looking for reasonably performant code since there could be 100+ leave records per day.
First example that does not fulfill the criteria outlined above.
<% #dates.each do |d| %>
<h5><%= d.strftime("%A %d %b") %></h5>
<% #leave = Leave.where('(start_at BETWEEN ? AND ?) OR (end_at BETWEEN ? AND ?)', d.beginning_of_day, d.end_of_day, d.beginning_of_day, d.end_of_day) %>
<% #leave = #leave.where.not('end_at < ?', Time.current) %>
<% if #leave.any? %>
<ul>
<% #leave.each do |leave| %>
<% if leave.single_day? && leave.start_at.to_date == d %>
<li>
<label class="label label-danger"><%= leave.start_at.strftime('%H:%M') %> - <%= leave.end_at.strftime('%H:%M') %></label>
<%= leave.user.name %>
</li>
<% elsif !leave.single_day? %>
<% if leave.start_at.to_date == d %>
<li>
<label class="label label-danger">From <%= leave.start_at.strftime('%H:%M') %></label>
<%= leave.user.name %>
</li>
<% elsif leave.end_at.to_date == d %>
<li>
<label class="label label-danger">Until <%= leave.end_at.strftime('%H:%M') %></label>
<%= leave.user.name %>
</li>
<% else %>
<li>
<label class="label label-danger">All Day</label>
<%= leave.user.name %>
</li>
<% end %>
<% end %>
<% end %>
</ul>
<br/>
<span class="label label-success" style="margin-right: 10px;">
<span class="glyphicon glyphicon-ok"></span>
</span>
<%= current_account.users.active.where.not(id: #leave.map(&:user_id)).count %> Available
<% else %>
<span class="label label-success" style="margin-right: 10px;">
<span class="glyphicon glyphicon-ok"></span>
</span>
<%= current_account.users.active.count %> Available
<% end %>
<br />
<br />
<% end %>
I would start with something like this:
In the model:
def starts_on?(date)
start_at.to_date == date
end
def ends_on?(date)
end_at.to_date = date
end
def covers?(date)
leave.start_at.to_date <= date && leave.end_at.to_date >= date
end
def starts_and_ends_on?(date)
starts_on?(date) && ends_on?(date)
end
In the controller:
#dates = # define the date range like you already do, I assume it is an array
#leaves = Leave.includes(:user).
where('start_at =< ? AND end_at >= ?', dates.max, dates.min)
In the helper:
def relevant_leaves_for_date(date, leaves)
leaves.select { |leave| leave.covers?(date) }
end
def leave_description_for_date(leave, date)
if leave.starts_and_ends_on?(date)
"#{leave.start_at.strftime('%H:%M')} - #{leave.end_at.strftime('%H:%M')}"
elsif leave.starts_on?(date)
"From #{leave.start_at.strftime('%H:%M')}"
elsif leave.ends_on?(date)
"Until #{leave.end_at.strftime('%H:%M')}"
else
'All day'
end
end
def available_users(leaves)
current_account.users.active.count - leaves.size
end
In the view:
<% #dates.each do |date| %>
<h5><%= date.strftime("%A %d %b") %></h5>
<% leaves = relevant_leaves_for_date(date, #leaves) %>
<% if leaves.any? %>
<ul>
<% leaves.each do |leave| %>
<li>
<label class="label label-danger">
<%= leave_description_for_date(leave, date) %>
</label>
<%= leave.user.name %>
</li>
<% end %>
</ul>
<% end %>
<span class="label label-success">
<span class="glyphicon glyphicon-ok"></span>
</span>
<%= available_users(leaves) %> Available
<% end %>
You might notice that I remove the <br> and style tags from the html. Please do not use <br> for styling or style attributes in the html. Add class the the tags and style them in your css file.
The reason why case 4 & 5 are not working is you are not fetching the leaves which started before the beginning of day or which are going to end after the end of day. So you can fetch all leaves which have not ended yet.
<% #leave = Leave.where('(end_at >= ?', d.beginning_of_day) %>
And then in application_helper.rb, you can have a function like this,
def check_for_leave(leave,d)
msg = ""
if leave.single_day? && leave.start_at.to_date == d
msg = "#{leave.start_at.strftime('%H:%M')} - #{leave.end_at.strftime('%H:%M')}"
elsif !leave.single_day?
if leave.start_at.to_date == d
msg = "From #{leave.start_at.strftime('%H:%M')}"
elsif leave.end_at.to_date == d
msg = "Until #{leave.end_at.strftime('%H:%M')}"
else
msg = "All Day"
end
return msg
end
In html.erb file
<% #dates.each do |d| %>
<h5><%= d.strftime("%A %d %b") %></h5>
<% #leave = Leave.where('(end_at >= ?', d.beginning_of_day) %>
<% if #leave.any? %>
<ul>
<% #leave.each do |leave| %>
<li>
<label class="label label-danger">
<%= check_for_leave(leave, d) %>
</label>
<%= leave.user.name %>
</li>
<% end %>
</ul>
<br/>
<span class="label label-success" style="margin-right: 10px;">
<span class="glyphicon glyphicon-ok"></span>
</span>
<%= current_account.users.active.where.not(id: #leave.map(&:user_id)).count %> Available
<% else %>
<span class="label label-success" style="margin-right: 10px;">
<span class="glyphicon glyphicon-ok"></span>
</span>
<%= current_account.users.active.count %> Available
<% end %>
<br />
<br />
<% end %>

Rails if greater than 0

I just started playing with rails, what's the best way to do the following: #events.x is an integer, if its value isn't > 0 it has to be hidden.
<div class="chartwell radar">
<span style="color: #fff;">dx</span>
<span style="color: #3498db"><%= #events.design %></span>
<span style="color: #1abc9c"><%= #events.typography %></span>
<span style="color: #2c3e50"><%= #events.code %></span>
<span style="color: #f8ff08"><%= #events.art %></span>
<span style="color: #fd79f2"><%= #events.lifestyle %></span>
</div>
As per your comment you want to show the value only if the value of the integer is no 0. so you can use this example:
<span style="color: #3498db"><%= #events.design unless #events.design.to_i == 0 %></span>
Or if you want not to display the span too
<% unless #events.design.to_i == 0 %>
<span style="color: #3498db"><%= #events.design %></span>
<% end %>
Let me know if you meant something different.
When you say "it is hidden", what is "it"? The whole div above? Something else?
If you wanted to conditionally show a div for #events.x, like #events.art for example, you could do
<% unless #events.art == 0 %>
<span style="color: #f8ff08"><%= #events.art %></span>
<% end %>
doing this for all of them is a bit tedious and repetitive. You could dry it up like this:
<div class="chartwell radar">
<span style="color: #fff;">dx</span>
<%
[["#3498db", "design"],
["#1abc9c", "typography"],
["#2c3e50", "code"],
["#f8ff08", "art"],
["#fd79f2", "lifestyle"]].each do |color, method| %>
<% value = #events.send(method) %>
<% unless value == 0 %>
<span style="color: <%= color %>;"><%= value %></span>
<% end %>
<% end %>
</div>

advanced Search (checkboxes and selection)

I'm having a problem with my advanced search.
Essentially, its an advanced search for bands (name, style, bandpicture by checkboxes (checked: have a bandpicture))
Here is the code.
result.html.erb
<table >
<colgroup>
<col width="250" />
</colgroup>
<tr>
<td>
<label for="name">Filter</label></br>
<%= form_tag band_path do %>
<label for="Style">Style</label></br>
<%= select_tag :style_id, options_from_collection_for_select(Style.all, :id, :name, params[:style_id]), include_blank: true, class: "form-control" %>
<br>
</br>
<%= check_box_tag 'options[]', "picture" %>
<%= button_to '#', class: 'btn btn-default' do %>
<%= t(:find) %>
<% end %>
<% end %>
</td>
<td>
<div>
<% #bands.each do |band|%>
<div class="top-bar">
<div class="center">
<div class="info">
<div class="name"><%=band.id %></div>
<div> <%= band.zip %>, <%= band.city %> </div>
</div>
<div class="desc">
<table>
<tr>
<td>Styles</td>
<td>
<% band.styles.each do |s| %>
<%= s.style.name %>
<% end %>
</td>
</tr>
</table>
</div>
<% end %>
</td>
</tr>
</table>
models band.rb
def self.search1(style_id)
Profile.joins("...").where("style_id = ?", style_id)
end
controller.
def searchresult
if params[:style_id].present?
#bands = Band.search1 params[:style_id]
elsif params[:options]
Band.where(:options => #filtered_options)
else
#bands = Band.all
end
end
The searchresult don't show the result of the checkboxes and I have this errors:
undefined method `search1' for #<Class:0x00000008eb5548>

Looping through a date integer

I have the following code:
<span class="bookings">
<span class="col-md-2">
<h4><%= time_tag(Date.today + 1.days) %></h4>
<% #booking.each do |b| %>
<% if b.date == Date.today + 1.days && b.type == "Hot Desk" %>
<% if b.desk == #hotdesk.code %>
<span class="glyphicon glyphicon-remove booked-show"></span>
<% end %>
<% end %>
<% end %>
</span>
</span>
<span class="bookings">
<span class="col-md-2">
<h4><%= time_tag(Date.today + 2.days) %></h4>
<% #booking.each do |b| %>
<% if b.date == Date.today + 2.days && b.type == "Hot Desk" %>
<% if b.desk == #hotdesk.code %>
<span class="glyphicon glyphicon-remove booked-show"></span>
<% end %>
<% end %>
<% end %>
</span>
</span>
Which extends on to however many days I want to display availability of bookings for. What I would like to achieve is writing only one of these blocks of codes out and having it loop through where it says Date.today + 1.days and increase the value of the days by 1 each loop up to 20 or so times.
Any ideas on a way to do this to save me writing this code over and over again?
<span class="bookings">
<% 1.upto(YOUR_COUNT.to_i).each do |day_count| %>
<span class="col-md-2">
<h4><%= time_tag(Date.today + day_count.days) %></h4>
<% #booking.each do |b| %>
<% if b.date == Date.today + day_count.days && b.type == "Hot Desk" %>
<% if b.desk == #hotdesk.code %>
<span class="glyphicon glyphicon-remove booked-show"></span>
<% end %>
<% end %>
<% end %>
</span>
<% end %>
</span>

Resources