Reputation: 1446
I am trying to create a calendar table to display the daily availability of every staff member of a company. What I think I need is a header with the days of the month and then a row (with as many cells as the number of the days) for each staff member. The different background color of each cell will represent a different availability status and the staff members change so I want all this to be dynamically generated.
After researching online and with Ryan Bates' Railscast #213 (Calendars Revised) as my guide, I have so far managed to generate the header of my table that displays the days of the month in each cell.
And that's my code so far:
module ReceptionHelper
def reception(date = Date.today, &block)
Reception.new(self, date, block).table
end
class Reception < Struct.new(:view, :date, :callback)
delegate :content_tag, to: :view
def table
content_tag :table, class: "calendar" do
daysHeader
end
end
def daysHeader
last_day = date.end_of_month.strftime("%d").to_i
(0..last_day).to_a.map { |day| content_tag :th, day }.join.html_safe
end
end
Now, here is where the questions and confusion begins:
Removing &block
and :callback
takes away the { ... } functionality, as I found out. I can't really say I understand why though. Anyone with a good explanation?
Why does the above work but I can't use (..).each do
and the content_tag
block below?
(0..last_day).to_a.each do |day|
content_tag :th do
day
end
end
In my effort to display the rows for each staff, I went with this:
def table
content_tag :table, class: "calendar" do
daysHeader + staffRows
end
end
def staffRows
staff.to_a.map { |staff| content_tag :tr, staff.name }.join.html_safe
end
I added staff
to the Reception
class definition and I call with <%= reception @staff %>
- if that's not a very good practice please feel free to shout at me :D
However, instead of getting one row per staff member I get all the member names next to each other in one row and right above the header. Changing content_tag :tr
to content_tag :td
results in a cell with the name of each staff after the last header cell.
As you understand, I am quite lost in this and it seems I am not even clearly getting why the part that works as I want it to is correct. I hope this post doesn't give the impression that I am looking to have everything served to me in a dish - I am rather looking for directions that will help me understand. :)
EDIT:
I've made some progress by changing the staffRows
method to this:
def staffRows
staff.to_a.in_groups_of(1).map do |staff|
content_tag :tr do
staff.map { |room| content_tag :th, staff.name }.join.html_safe
end
end.join.html_safe
end
However this produces only one cell for each room while I want a row with as many cells as the header.
Upvotes: 1
Views: 1736
Reputation: 756
First of all ruby conventions: use 2 spaces for spacing and use _ for method names.
Now meet your best friend when writing complex helpers: concat
. What it does is outputs string directly to ERB buffer. To show you and example:
def my_helper
concat "hello world"
end
<% my_helper %>
would output hello world
in html even though we used <%
and not <%=
.
It's very important method when dealing with blocks in helpers, as it means you can call concat
multiple times in block and both strings will be output. Here's an example:
def my_helper
content_tag :div do
concat "Hello "
concat "World"
concat "!"
end
end
<%= my_helper %>
would output <div>Hello World!</div>
. So using same idea you could do something like this:
def my_helper
content_tag :ul do
@people.each do |person|
concat content_tag(:li, person.name)
end
end
end
<%= my_helper %>
which would result in something like this: <ul><li>John Doe</li><li>Mike Tyson</li></ul>
.
So I would rewrite days_helper
to something like this:
def days_header
(0..date.end_of_month.day).each { |day| concat content_tag(:th, day) }
end
do something similar with staff_rows
method and then table
method would look simply like this:
content_tag :table, class: "calendar" do
days_header
staff_rows
end
As for the callback part of question: &block
captures block that is passed to method into Proc object. This object can later be passed around to other methods or called directly. As you're not using callback object I would simply advise to remove it.
Upvotes: 6