I participated in the source of Rails 3.1, to understand this, I realized that it would be easier than searching elsewhere. Earlier versions of Rails should be similar. Go to the end if tl; dr.
When you call form_for(@user) , you end this:
def form_for(record, options = {}, &proc)
And since @user is neither a string nor an object, you go through the else branch also in apply_form_for_options! . Inside apply_form_for_options! we see the following:
as = options[:as] #... options[:html].reverse_merge!( :class => as ? "#{as}_#{action}" : dom_class(object, action), :id => as ? "#{as}_#{action}" : dom_id(object, action), :method => method )
Pay attention to this piece of code, it contains both the source of your problem and the solution. The dom_id method calls record_key_for_dom_id , which looks like this:
def record_key_for_dom_id(record) record = record.to_model if record.respond_to?(:to_model) key = record.to_key key ? sanitize_dom_id(key.join('_')) : key end
And here is your call to_key . The to_key method to_key defined by ActiveRecord::AttributeMethods::PrimaryKey , and since you are not using ActiveRecord, you do not have a to_key method. If you have something in your model that behaves like a primary key, then you can define your own to_key and leave it to that.
But if we go back to apply_form_for_options! , we will see another solution:
as = options[:as]
So you can provide :as a form_for option to create a DOM identifier for your form manually:
<%= form_for(@user, :as => 'user_form') do |f| %>
You need to make sure that :as was unique on the page.
Summary :
- If your model has an attribute that behaves like a primary key, then define your own
to_key method, which returns it. - Or put the appropriate option
:as on form_for .