views:

198

answers:

1

I am building a Rails application which allows a user to create an object that refers to multiple other models, creating them if they do not exist, and just associating to ones that already exist:

# app/models/upload.rb
class Upload < AR:B
  belongs_to :user
  belongs_to :observed_property
  belongs_to :sensor

  accepts_nested_attributes_for :observed_property, :sensor
  validates_presence_of :observed_property, :sensor
end

(The associations to sensor and observed_property are just one-way, there are no has_many returning.)

The Controller is nothing special, just a standard RESTful seven, and I would think it would be possible to do this properly while keeping most of the logic in the Model.

Instead of having the user fill out multiple different forms and then reference those objects separately, I have attempted to use accepts_nested_attributes_for to embed them into the Upload form using fields_for:

# app/views/uploads/new.html.erb
<% form_for @upload, :url => user_uploads_path(@user) do |f| %>
  <%= f.error_messages %>
  <% f.fields_for :observed_property do |builder| %>
  <fieldset>
  <legend>Observed Property</legend>
  <p><%= builder.label :_id, "Observed Property ID" %><br />
  <%= builder.text_field :_id %></p>

  <p><%= builder.label :description %><br />
  <%= builder.text_area :description, :rows => 5 %></p>
  </fieldset>
  <% end %>
  <% f.fields_for :sensor do |builder| %>
  <fieldset>
  <legend>Sensor</legend>
  <p><%= builder.label :_id, "Sensor ID" %><br />
  <%= builder.text_field :_id %></p>

  <p><%= builder.label :description %><br />
  <%= builder.text_area :description, :rows => 5 %></p>
  </fieldset>
  <% end %>
  <%= f.submit "Submit", :class => "button" %>
<% end %>

This however does not work, as no form is displayed for the fields_for. I tried to apply what was mentioned in this answer, but the model would just fail to save, citing missing associations.

I have attempted a few hackish things such as overriding the sensor= and observed_property= methods and caching the hashes for before_save, but that doesn't really feel like the right way to do things.

+1  A: 

I ended up using the following solution, and it does seem to work. I created a gist to hold the solution with a matching spec to define the behaviour I was seeking.

http://gist.github.com/437939

James