Das Umschalten von Sichbarkeiten im View mit toggle() geht schnell, aber nur weil ein div-Element unsichtbar ist, bedeutet dies nicht, dass sein Inhalt beim Formularversand nicht mitgeschickt würde.
Damit der Controller eindeutig wissen kann, welches Feld gewählt wurde, muss man das jeweils ausgeblendete Feld nullen:
<div id="personselect">
<p >
Person<br />
<%= select_tag 'project[person_id]', options_for_select([["",""]] +
Person.all.map {|w| [w.gname + " " + w.sname, w.id]}), :id => 'personid' %>
</p>
<p>
<%= link_to_function "Person neu anlegen", "$('personselect').toggle();
$('personcreate').toggle(); $('personid').clear();" %>
</p>
</div>
<div id="personcreate" style="display: none">
<p >
Vorname Nachname<br />
<%= text_field_tag 'gname', {}, :size => 10, :id => 'gnameid' %>
<%= text_field_tag 'sname', {}, :size => 20, :id => 'snameid' %>
</p>
<p>
<%= link_to_function "Person wählen", "$('personcreate').toggle();
$('personselect').toggle(); $('gnameid').clear(); $('snameid').clear();" %>
</p>
</div>