<%= f.select :day, [['Sunday', 0], ['Monday', 1], ['Tuesday', 2],
['Wednesday', 3], ['Thursday', 4], ['Friday', 5], ['Saturday', 6]] %>
can be rewritten as
<%= f.select :day, DATE::DAYNAMES %>
You can also use it instead of creating the variable for days in the
second part.
Shawn
Note also that (again, in the 2.3 app I'm looking at), Shawn's code
produces a different set of tags than Andrew's code does:
<select id="object_field" name="object[field]">
<option value="Sunday">Sunday</option>
<option value="Monday">Monday</option>
[snip]
</select>
This is a good opportunity to point out something interesting about
Ruby: it's got a lot of functional constructs just sitting around
waiting for you to pick them up.
For example, there's Array#zip (and its sibling, Enumerable#zip),
which you could use to reconstruct that array:
<%= f.select :day, Date::DAYNAMES.zip((0..6).to_a) %>
Note that, if you're not sure how many things are in the array you're
zipping with, #zip will return a zipped array that is as long as the
thing you're calling #zip on. So you could do this and get the exact
same result:
<%= f.select :day, Date::DAYNAMES.zip((0..20).to_a) %>
I didn't really think about how many functional constructs Ruby had
borrowed (many of them, ironically, from Smalltalk) until I typed
something like...
[user.last_name, user.first_name].reject(&:blank?).join(', ')
...and the person I was pairing with said something like, "What do you
think this is, a functional language?"
Hope this helps,
-Sam
I'd just like to point out that this, too, doesn't actually do what
Andrew was asking for -- it gives you a select box for the number of
the day of the month (i.e., in the range (1..31)), not the name of the
day of the week.
The rest of Bryan's advice was great, though. (=
-Sam
Date::DAYNAMES.each_with_index
>> puts helper.options_for_select Date::DAYNAMES.each_with_index
<option value="0">Sunday</option>
<option value="1">Monday</option>
<option value="2">Tuesday</option>
<option value="3">Wednesday</option>
<option value="4">Thursday</option>
<option value="5">Friday</option>
<option value="6">Saturday</option>
Matthew Boeh
...And now we're well off into Nerdsville, population me. ;>
You could also do Date::DAYNAMES.to_enum.with_index, but I like
.each_with_index better.
The API docs for options_for_select[1] expressly indicates that you
can pass an Enumerable. The actual code uses #map.
Matthew Boeh
More inline...
> I'm not familiar with the terms "enumerable" and "enumerator". Is this
> similar to object iteration in PHP? (http://php.net/manual/en/
> language.oop5.iterations.php)
Aha! To quote a sticker floating around my office, "Welcome to Club Awesome."
Enumerable is a mixin module in Ruby. Documentation for it is here:
http://ruby-doc.org/core/classes/Enumerable.html
Basically, if you have some kind of collection class (let's say you
feel the need to write a binary tree in Ruby), and that class is able
to provide an #each method that takes a block and yields each member
of the collection, then you can include the Enumerable module in your
class, and you get about thirty extra methods for free: things like
#any?, #map, #each_cons, and so on. (That last one, by the way, is
short for "each consecutive" and is really useful if you need to do
pairwise comparisons of stuff in a collection.)
Now, because Ruby lets you throw around blocks, and that's an
incredibly powerful construct, you can get really far with just #each
and #map and so on. But sometimes it's more convenient, or maybe just
reads better, to ask a collection for an Enumerator, and then use that
Enumerator to get members of the collection whenever you're ready for
them. If you're familiar with the concept of cursors in SQL, this is
vaguely like that; there's a construct like this that gets used all
over the place in Java. An Enumerator has a #next method on it, which
(according to the docs) will do one of two things when called: (1)
Give you the next element in the collection that it came from, or (2)
raise a StopIteration exception when it doesn't have anything else to
give you.
Check out the docs for more details on how to use these, but I hope
that gives you the basic idea.
> Anyway, once I've got that part figured out, I'm wondering if there is
> a way to move some of this logic out of my view and into a model or
> something. Is it easy to create a custom form element/method? Is this
> a common thing in Rails? Something like this:
>
> <%= f.weekday_select :day %>
You can do this by subclassing ActionView::Helpers::FormBuilder and
defining a #weekday_select method on it. You can then tell the
#form_for method to use your subclass instead of the basic one, or you
can define a helper method that does that for you. This is one of the
recipes in the book "Rails Recipes"; if you're downtown, I've got a
copy at my office that I'd be happy to lend out. (Caveat: the book
dates back to Rails 1.x, so some of its code requires adaptation. I
think this part of Rails has been fairly stable, though.) More
information on that class here:
http://apidock.com/rails/ActionView/Helpers/FormBuilder
> I'd also be interested in doing this sort of thing for my "time of day
> select". I'm thinking of creating 3 select fields: one for selecting
> the hour, one for minute, and one for AM/PM. Then when the form is
> submitted, something needs to stitch these fields back into a 24 hour
> time format. How can I create this sort of form element?
This one gets a little bit tricky. You can DIY by using the *_tag
helpers and crafting your tag names carefully; Rails' controller
plumbing will use the field names to build the params hash. You
should be able to reverse-engineer this from one of the existing
date-picker controls -- which is usually what I do, since I don't work
with forms often enough to keep the magic pattern memorized. ;>
Then, in your model, you'll need to write a #time_of_day= method that
accepts the data structure accessible via
params[:object][:time_of_day] and uses that to build a Time object.
I realize that last is a bit handwavy, but I'm hungry and tired. (=
I'm planning to be at next week's beginner meetup; if you haven't
figured this out by then, I'd be happy to work through it with you.
-Sam
https://github.com/attinteractive/rails-twelve-hour-time-plugin
Matthew Boeh