Can't get date_select to work


#1

Hi,

I render a couple of date_select fields, the HTML looks fine, I can
see the values submitted back to the server, but AR doesn’t pick them
up from the hash in Booking.new(params[‘booking’]).

I’ve got a ‘booking’ object with parameters product, startdate and
enddate.

HTML snippets:


In the view controller method I create a booking object and set
startdate to Date.today+1, and enddate to Date.today+2. When the
page renders the dates are showing correctly according to how the
controller set them up, so date_select is showing the right fields
from my model.

I’ve tried different browsers, and I’ve tried gem rails and edge rails.

From the console log I can see the values:
Processing SiteController#booking (for 127.0.0.1 at 2006-02-08
10:19:25) [POST]
Parameters: {“commit”=>“Check Availability”, “action”=>“booking”,
“id”=>“1”,
“controller”=>“site”,
“booking”=>{“startdate(1i)”=>“2006”, “startdate(2i)”=>“2”,
“startdate(3i)”=>“9”,
“enddate(1i)”=>“2006”, “enddate(2i)”=>“2”, “enddate(3i)”=>“10”}}

But the save always fails and the view reports the errors like so:

2 errors prohibited this booking from being saved
There were problems with the following fields:
* Enddate can’t be blank
* Startdate can’t be blank

The form looks like this:

<%=error_messages_for(“booking”)%>
<%=form_tag({:action => ‘booking’, :id=>@product})%>

Start:
<%=date_select("booking", "startdate")%>

End:
<%=date_select("booking", "enddate")%>

<%= submit_tag "Check Availability"%> <%= end_form_tag %>

There are no methods in the model:

class Booking < ActiveRecord::Base
belongs_to :product
validates_presence_of :startdate, :enddate, :product
end

The controller method is quite simple:

def booking
@product = Product.find(params[:id])
@booking = Booking.new(params[‘booking’])
@booking.product = @product

 # I added these 3 lines so I could dump them
 # in the view to try and debug the problem:
 @startdate = params['booking']['startdate']
 @enddate = params['booking']['enddate']
 @params = params

 if @booking.save
   redirect_to(:action=>'index')
 else
   render(:action=>'view')
 end

end

I dump @startdate, @enddate and @params in my view and get:
Startdate:

Enddate:

Params:
— !map:HashWithIndifferentAccess
commit: Check Availability
action: booking
id: “1”
controller: site
booking: !map:HashWithIndifferentAccess
startdate(1i): “2006”
startdate(2i): “2”
startdate(3i): “9”
enddate(1i): “2006”
enddate(2i): “2”
enddate(3i): “10”

The database table has all the fields:

CREATE TABLE bookings (
id int(11) NOT NULL auto_increment,
product_id int(11) default NULL,
startdate datetime default NULL,
enddate datetime default NULL,
created_at datetime default NULL,
updated_at datetime default NULL,
PRIMARY KEY (id),
KEY bookings_product_id_index (product_id),
KEY bookings_startdate_index (startdate),
KEY bookings_enddate_index (enddate)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

(they were originally ‘date’ fields, I changed them to ‘datetime’
while trying to get this working).

Any help would be appreciated!

Jon


#2

On Wed, 2006-02-08 at 10:36 +0000, Jon Evans wrote:

<%=error_messages_for(“booking”)%>

 @product = Product.find(params[:id])
   redirect_to(:action=>'index')

Params:
enddate(2i): “2”
created_at datetime default NULL,

Any help would be appreciated!


not an expert on this stuff at all - perhaps you have seen from my array
of confused questions but this looks to me like you need a definition
for the aggregation in the model to put this all back together.

I am using the following for names (which I learned from the Agile
book)…

class Wholename
attr_reader :first_name, :middle_initial, :last_name

def initialize(first_name, middle_initial, last_name)
@first = first_name
@initials = middle_initial
@last = last_name
end

def to_s
[ @first_name, @middle_initial, @last_name ].compact.join(" ")
end
end

and then I can refer to either table.wholename or table.first_name,
table.last_name, etc. pretty much interchangeably.

In your case, I am not certain if you would need leading ‘0’ on single
digit day/month but I think you can work that out.

Craig


#3

Hi Craig,

On 8 Feb 2006, at 11:45, Craig W. wrote:

On Wed, 2006-02-08 at 10:36 +0000, Jon Evans wrote:

I render a couple of date_select fields, the HTML looks fine, I can
see the values submitted back to the server, but AR doesn’t pick them
up from the hash in Booking.new(params[‘booking’]).

not an expert on this stuff at all - perhaps you have seen from my
array
of confused questions but this looks to me like you need a definition
for the aggregation in the model to put this all back together.

Thanks for your input, but I’m not convinced you’re right. All of
the other form field helpers produce fields which can be
automatically read back into the AR model object when the form is
submitted. date_select works fine to read the date out of the model
object and render it, it’s just that AR doesn’t recognise the form
field when it is submitted, even though the data makes it back to the
server OK.

Anyone else? Is Craig right, I have to handle the returned YYYY, MM
and DD fields myself?

I think I’ve decided that for the sake of a cleaner UI I’m going to
do my own dropdowns anyway. One with a date, the other with a
combined month and year. But it would still be useful to know where
I’m going wrong with date_select.

Thanks

Jon


#4

On Wed, 2006-02-08 at 22:33 +0000, Jon Evans wrote:

field when it is submitted, even though the data makes it back to the
server OK.

Anyone else? Is Craig right, I have to handle the returned YYYY, MM
and DD fields myself?

I think I’ve decided that for the sake of a cleaner UI I’m going to
do my own dropdowns anyway. One with a date, the other with a
combined month and year. But it would still be useful to know where
I’m going wrong with date_select.


now you’ve removed the context for which I gave an answer and with this
context, I would answer differently since I have used the date_select
function with nary a whimper and no extra futzing around.

You might find it wise to restate your question - perhaps now that you
have had more time to think about it and simplify it as best as you can
because that is the way you get answers. I know because when my normal
state of confusion is obvious in the question, no one is gonna answer
it.

Craig


#5

If your model has a date or datetiime field, then AR should properly
convert
the multi-select values back into a valid date object for your database
when
you save your record. If it doesn’t, then your database adapter doesn’t
convert dates properly for your db or you are doing something else
wrong.
Giving it the wrong name maybe?

You’ll need to provide more info of your table layout and how you are
calling the date_select for more help.

Bob


#6

Hi Bob,

Thanks for your reply.

On 8 Feb 2006, at 23:36, Bob S. wrote:

[I was asking whether AR was supposed to be able to automatically parse the date fields generated by date_select when the form is submitted.]

You’ll need to provide more info of your table layout and how you are
calling the date_select for more help.

Well, my first message in this thread had all the information I
thought anyone might have needed to help, but as Craig has pointed
out it probably just made the problem appear to be more complicated. :slight_smile:

My table def is:
CREATE TABLE bookings (
id int(11) NOT NULL auto_increment,
product_id int(11) default NULL,
startdate datetime default NULL,
enddate datetime default NULL,
created_at datetime default NULL,
updated_at datetime default NULL,
PRIMARY KEY (id),
KEY bookings_product_id_index (product_id),
KEY bookings_startdate_index (startdate),
KEY bookings_enddate_index (enddate)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

startdate and enddate were originally of type ‘date’, I changed them
to ‘datetime’ because I thought that was the problem.

Here’s the (simplified) form:
<%=form_tag({:action => ‘booking’, :id=>@product})%>
<%= date_select( “booking”, “startdate”) %>
<%= date_select( “booking”, “enddate”) %>
<%= submit_tag “Check Availability”%>
<%= end_form_tag %>

To be clear, if I set startdate and enddate on @booking before
displaying the form, the values that I set are correctly displayed in
the drop-downs. I think that proves that I haven’t made a typo in
the parameter names or something basic like that.

The model is about as simple as it gets:
class Booking < ActiveRecord::Base
belongs_to :product
validates_presence_of :startdate, :enddate, :product
end

According to the log file the values get passed back to AR OK:
Processing SiteController#booking (for 127.0.0.1 at 2006-02-08
10:19:25) [POST]
Parameters: {“commit”=>“Check Availability”, “action”=>“booking”,
“id”=>“1”,
“controller”=>“site”,
“booking”=>{“startdate(1i)”=>“2006”, “startdate(2i)”=>“2”,
“startdate(3i)”=>“9”,
“enddate(1i)”=>“2006”, “enddate(2i)”=>“2”, “enddate(3i)”=>“10”}}

error_messages_for(“booking”) produces:
2 errors prohibited this booking from being saved
There were problems with the following fields:
* Enddate can’t be blank
* Startdate can’t be blank

the controller method that the form gets submitted to is:
def booking
@product = Product.find(params[:id])
@booking = Booking.new(params[‘booking’])
@booking.product = @product

 if @booking.save
   redirect_to(:action=>'index')
 else
   render(:action=>'view')
 end

end

I’m using a MySQL database on Mac OS X.

Thanks

Jon


#7

FWIW i have to do something like this to get date_select back to a
usable form to be inserted into the DB

birthdate = @params[:user][“birthdate(1i)”] + ‘-’ +
@params[:user][“birthdate(2i)”] + ‘-’ +
@params[:user][“birthdate(3i)”]

@user = User.new
@user[“birthdate”] = birthdate if birthdate

hope that helps. I think i tried just doing @user
=User.new(@params[:user]) but the birthdate was breaking.

adam