views:

61

answers:

1

I have complex form similar to a recent Ryan Bates screencast

The nested elements work fine however. I'm creating or updating a grid of data such as this through a form where the day's prices are the input. My problem begins when they leave one blank. I have the nested_attributes_for option for not saving nils and it works, if they only save one value in a particular row, it saves the correct day however when reloaded, it will place it in the wrong column. I'm not sure how to order the values in a row to the form. IE A saved value for wednesday will appear in the monday column (of the correct row). This doesn't happen if they save all value for a row (then it works perfectly).

Data is stored in the DB like so

ID OBJECT_ID DAYOFWEEK PRICE and displaying like below

+------+----------------+-------+-------+-------+------+-------+
| id   | name           | Mon   | Tue   | Wed   | Thu  | Fri   | -> +2 more days etc
+------+----------------+-------+-------+-------+------+-------+
| 1234 | Some name      | 87.20 | 87.20 | 87.20 | 82.55| 85.48 |
+------+----------------+-------+-------+-------+------+-------+
| 1234 | Some name      | 87.20 | 87.20 | 87.20 | 82.55| 85.48 |
+------+----------------+-------+-------+-------+------+-------+
| 1234 | Some name      | 87.20 | 87.20 | 87.20 | 82.55| 85.48 |
+------+----------------+-------+-------+-------+------+-------+

The controller code either building or display these values is like so:

controller

@rooms.each do |r|
  ((r.room_rates.size+1)..7).each {
      r.room_rates.build
  }
end

rooms.html.erb

<% @dow = 0 %>
  <tr class="room">
 <td><%= f.text_field :name %></td>

 <% f.fields_for :room_rates do |rates| %>
  <%= render 'rates', :f => rates %>

  <% @dow += 1 %>
 <% end %>

 <td class="delete_mode" style="display:none;">
  <%= f.hidden_field :_destroy %>
  <%= link_to_function "remove", "remove_room(this)" %>
 </td>
  </tr>

rates.html.erb

<td> 
 <%= f.text_field :price, :size => 3 %>
 <%= f.hidden_field :dayofweek, :value => @dow %> 
 <%= f.hidden_field :source, :value => 0 %>
</td>

room_rates model (where the data from the form is going)

+-------+---------+-----------+-------+--------+---------------------------+---------------------------+
| id    | room_id | dayofweek | price | source | created_at                | updated_at                |
+-------+---------+-----------+-------+--------+---------------------------+---------------------------+
| 92745 | 8       | 0         | 1.0   | 0      | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92746 | 8       | 1         | 2.0   | 0      | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92747 | 8       | 2         | 3.0   | 0      | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92748 | 8       | 3         | 4.0   | 0      | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92749 | 8       | 4         | 5.0   | 0      | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92750 | 8       | 5         | 6.0   | 0      | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92751 | 8       | 6         | 7.0   | 0      | 2010-02-23 14:33:05 +0100 | 2010-02-23 14:33:05 +0100 |
| 92752 | 9       | 3         | 5.0   | 0      | 2010-02-23 14:33:33 +0100 | 2010-02-23 14:33:33 +0100 |
+-------+---------+-----------+-------+--------+---------------------------+---------------------------+

ordering in the console

+---------+-----------+-------+--------+---------------------------+---------------------------+
| room_id | dayofweek | price | source | created_at                | updated_at                |
+---------+-----------+-------+--------+---------------------------+---------------------------+
| 2517    | 0         |       |        |                           |                           |
| 2517    | 1         |       |        |                           |                           |
| 2517    | 2         | 3.0   | 0      | 2010-02-23 17:54:28 +0100 | 2010-02-23 17:54:28 +0100 |
| 2517    | 3         | 4.0   | 0      | 2010-02-23 17:54:28 +0100 | 2010-02-23 17:54:28 +0100 |
| 2517    | 4         |       |        |                           |                           |
| 2517    | 5         |       |        |                           |                           |
| 2517    | 6         |       |        |                           |                           |
+---------+-----------+-------+--------+---------------------------+---------------------------+
+1  A: 

The error is when you create the form - because you are depending on the order of the room_rates to be correct, you need to put the empty (built) rates into the correct positions. If each room has many room rates, you need to generate the form so that the rates are at the right day in the week. This code will build that in a new array, and set the new array correctly:

@rooms.each do |r|
  new_rates = []
  (0..6).each { |dow|
    rate = r.room_rates.find_by_dayofweek(dow)
    if rate
      new_rates << rate
    else 
      new_rates << r.room_rates.build(:dayofweek => dow)
    end
  }
  r.room_rates = new_rates
end

Alternatively, you may be able to just build the missing weeks, if you specify an order for your association:

// In room model 
has_many :rates, :order => "dayofweek"

// In controller
@rooms.each do |r|
  (0..6).each { |dow|
    if not r.room_rates.find_by_dayofweek(dow)
      r.room_rates.build(:dayofweek => dow)
    end
  }
end
jamuraa
Sorry, I should have been more clear, there are not distinct fields in on record but multiple records. I added the rates model to the bottom of my post. However the 2nd part you added I thought might work also. I tried similar things but it still isn't getting the ordering on the form correctly ;-(
holden
I've edited my answer based on the additional information in the question.
jamuraa
The first one looks like it should work perfectly. However it still doesn't order them correctly. I'm not sure if anything else is going on, but I'll try going thru in on the console.
holden
It seems to work in the console, I added my result to my question above. So something must be wrong in the form.
holden
Can you try it in the rails console? The result that you pasted above looks like a SQL result, which I would be surprised if the first one is producing. You may want to add the :order => "dayofweek" in any case.
jamuraa