I have created a simple appointment system, and I now need to display something inside a loop if there's two or more appointments with the same date and time. The appointments are displayed in order of time, so they're just appearing one after the other.
Controller
def index
#todays_apps = current_user.appointments.order(time ASC)
end
View
<% #todays_apps.each do |app| %>
<%= app.business_name %>
<%= app.business_address %>
<%= app.time %>
<% end %>
I'm looking to display a message or icon the appointment shares a date and time with another appointment. Tried a collection of things with no luck.
You can group your collection by time and modify your iteration accordingly. You can group it like
#todays_apps.group_by(&:time)
The outcome will be something like
=> { timestamp1 => [app1,app2], timestamp2 => [app3], timestamp3 => [app4]}
Or you can try a quick hacky way like:
<% previous_time = nil %>
<% #todays_apps.each do |app| %>
<%= app.business_name %>
<%= app.business_address %>
<%= 'Your message or class or anything' if previous_time == app.time %>
<%= previous_time = app.time %>
<% end %>
Try Like this:
controller:
def index
#appointments = current_user.appointments.order("time ASC")
#todays_apps = #appointments.group_by(&:time)
end
View:
<% #todays_apps.each do |time, appointments| %>
<%= time %>
<% appointments.each do |appointment| %>
<%= appointment.business_name %>
<%= appointment.business_address %>
<% end %>
<% end %>
It will list all the appointments for particular time.
Thanks
Related
I'm looking to get the last 5 items in an array, but to display each item individually, not as a group.
Here's what I've tried below with no success.
#array = Town.all
<% #array.each_slice(5) do |a| %>
<%= a.first %>
<%= a.second %>
<%= a.third %>
<%= a.fourth %>
<%= a.fifth %>
<% end %>
I can't figure out how to pull out a specific number of items and then to call each individual item.
The method you are looking for is in_groups_of (https://apidock.com/rails/Array/in_groups_of):
<% #towns.in_groups_of(5) do |five_towns| %>
<% five_towns.each do |town| %>
# [...]
<% end %>
<% end %>
Update: Maybe you want only the last 5 elements of the array. If so, you can simply call:
Town.all.last(5)
# => array of (max) 5 Town records
To get the last 5 items of an Array you could use last and then iterate them with each:
<%= #array.last(5).each do |a| %>
...
<% end %>
But it seems that you want to get the last 5 records of a model; in that case, you could try this instead:
#array = Town.limit(5).order('id desc')
<%= #array.each do |a| %>
...
<% end %>
... is there a way that I can have let's say the last 5 records of a
model all within one loop? maybe
<%= #array.each do | a, b, c, d, e| %>
<%= a.description %>
<%= b.description %>
<% end %>
You could use the index of each item instead of using each; for example:
#last_five = #array.last(5)
<%= last_five[0] %>
<%= last_five[1] %>
<%= last_five[2] %>
<%= last_five[3] %>
<%= last_five[4] %>
Although that wouldn't be DRY, so it will be better to stick with each.
Let say I have a controller Transactions:
#transactions = Transaction.all.group(:type)
#transaction_date_asc = Transaction.all.order(:DATE => :desc).group(:type)
#transaction_date_desc = Transaction.all.order(:DATE => :asc).group(:type)
In my view I need to loop all 3 instances.
Something like this where I want to show newest and oldest amount or discount for each transaction type.
<% #transactions do |transaction|%>
transaction.type.name
<%end%>
<% #transaction_date_asc do |transaction_asc|%>
transaction_asc.amount
<%end%>
<% #transaction_date_desc do |transaction_desc|%>
transaction_desc.amount
<%end%>
<% #transaction_date_asc do |transaction_asc|%>
transaction_asc.discount
<%end%>
<% #transaction_date_desc do |transaction_desc|%>
transaction_desc.discount
<%end%>
How am I supposed to place loops, columns and <%end> in my view?
Someone may come up with a better solution, but from my seat it looks like you need to do a query for each group in your view to get the first date transaction, but on the plus side, you only need one query in the controller for the transactions with the last date.
#transactions = Transaction.group(:type).having('DATE = MAX(DATE)')
In the view...
<% #transactions do |transaction| %>
<% first_transaction = Transaction.where(type: transaction.type).order('transaction_date').first %>
<%= transaction.type.name %>
<%= first_transaction.amount %>
<%= transaction.amount %>
<%= first.transaction.discount %>
<%= transaction.discount %>
<% end %>
However... to keep the logic in the view cleaner you could have an instance method for transaction types that will return the first and last transaction.
class Type << ActiveRecord::Base
def first_transaction
Transaction.where(type: self).order('transaction_date ASC').first
end
def last_transaction
Transaction.where(type: self).order('transaction_date DESC').first
end
end
Then in the controller...
#types = Type.all
then in the view...
<% #types.each do |type| %>
<%= type.name %>
<%= type.first_transaction.try(:amount) %>
<%= type.last_transaction.try(:amount) %>
<%= type.first_transaction.try(:discount) %>
<%= type.last_transaction.try(:discount) %>
<% end %>
The reason I'm suggesting #try is to handle the case of no transactions being present for a specific type.
I'm trying to create a timeline for #challenges. For those challenges that have a :deadline I want them to be organized on the timeline according to their :deadline and for those challenge that have a :date_started I want them to be organized on the timeline according to their :date_started.
If a challenge has a :deadline then date_started is nil and vice versa.
example
2016
February
CHALLENGE 1 (Deadline: 1st)
CHALLENGE 2 (Date_Started: 3rd)
CHALLENGE 3 (Deadline: 18th)
controller
#challenges = current_user.challenges
#challenges_timeline = #challenges.group_by { |t| t.deadline.beginning_of_year + t.date_started.beginning_of_year }
view
<% #challenges_timeline.sort.each do |year, challenges| %>
<%= year.strftime('%Y') %>
<% challenges.group_by { |t| t.deadline.beginning_of_month + t.date_started.beginning_of_month }.sort.each do |month, challenges| %>
<%= month.strftime('%B') %>
<% for challenge in challenges %>
<% if challenge.deadline.present? %>
<%= challenge.deadline %>: <%= challenge.action %>
<% end %>
<% if challenge.date_started.present? %>
<%= challenge.date_started %>: <%= challenge.action %>
<% end %>
<% end %>
<% end %>
<% end %>
Change your schema:
If the two dates negate each other, perhaps you should have just one date field, and another field to show whether the date is the beginning or the end. That would allow you to group on the database level, saving some processing time.
Add instance method
A simple instance method such as
def timeline_date
deadline || date_started
end
would allow simple grouping such as
challenges.group_by { |c| c.timeline_date.beginning_of_month }
Use || directly in the group_by block.
I've got workers, workers has many posts. I want to be able to search for a worker, displaying all his posts, then narrow down to the date the posts where made. I can search by name of the worker but when I try to search for date aswell it just displays all posts for that worker (if the date exists in one post).
what I'm trying to run with:
controller:
#q = Worker.ransack(params[:q])
#workers = #q.result.order(name: :asc).includes(:posts).uniq
view:
<%= search_form_for #q do |f| %>
<%= f.label :name_cont %>
<%= f.search_field :name_cont %>
<%= f.label :posts_date_start %>
<%= f.search_field :posts_date_start %>
<%= f.submit %>
<% end %>
<% #workers.each do |worker| %>
<% worker.posts.group_by { |t| t.date.to_time.beginning_of_month }.each do |month, posts| %>
<some table header logic>
<% posts.each do |post| %>
<table content>
Unless you created a custom predicate of start, that will not work.
From your group_by statement I can see that your posts has a date field. If you wanted posts only for the date specified you would use the eq predicate
<%= f.search_field :posts_date_eq %>
If you need to massage your user input, I would look into making a custom predicate you can look at how to do that here -> creating custom predicates
EDIT
To test parsing your date field string into a date put
begin
params[:q][:posts_date_eq] = Date.parse(params[:q][:posts_date_eq])
rescue
# no param present
end
before your search object
#q = Worker.ransack(params[:q])
I solved it like this
instead of
<% worker.posts.group_by { |t| t.date.to_time.beginning_of_month }.each do |month, posts| %>
I did
<% Post.search_post(params[:search_post]).search_post_present(params[:search_post_present]).where(worker_id: worker.id).order(date: :asc).group_by { |t| t.date.to_time.beginning_of_month }.each do |month, posts| %>
that pointed to a search hepler in post.rb
def self.search_post(search_post)
if search_post
where('date LIKE ?', "%#{search_post}%")
else
all
end
end
I then overlapped the forms for both ransack and this search, so both are run with the same submit button, and that worked just fine.
I have a database table called "bookings" which users can select the 'time_from' and 'time_to' in which they want the booking done.
When adding these fields to the database I added them as a time_field.
<%= f.label :time_from, "From (24hr Clock)" %>
<%= f.time_field :time_from %>
<%= f.label :time_to, "To (24hr Clock)" %>
<%= f.time_field :time_to %>
The form works and saves correctly but my problem is the order. Below is my controller code and subsequently my view to display the time and its output. Any idea on how to order these by time correctly?
Controller:
def show
#location = Location.find(params[:id])
#booking = Booking.order("time_to")
#company = Company.all
end
View:
<% 0.upto(11.to_i).each do |day_count| %>
<span class="col-md-3 booking-times">
<h4><%= time_tag(Date.today + day_count.days) %></h4>
<span class="label label-danger no-bookings">No Bookings</span>
<% #booking.each do |b| %>
<% if b.date == Date.today + day_count.days && b.type == "Meeting" %>
<% if b.location == params[:id] %>
<span class="label label-info booking-time">
<%= time_tag(b.time_from, :format=>"%H:%M") %> -
<%= time_tag(b.time_to, :format=>"%H:%M") %>
</span>
<% #company.each do |c| %>
<% if c.id == b.company %>
<%=link_to c.name, c %></br>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
</span>
<% end %>
Output: (For first day time)
09:30 - 10:30
22:00 - 23:00
07:30 - 08:30
I appreciate this is not the nicest looking code. I would like the above output to order by time. Any ideas? I have tried to order in the controller, this effects the layout but not in the correct order still. I think the dat attatched to the time_to input may be having ian affect? Thanks!
Have you tried this:
#booking = Booking.order(time_to: :desc)
Can you please try this:
#booking = Booking.order('time_to desc')