Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Rails build and fields_for to create only a new record and not include existing?

I am using build, fields_for, and accepts_nested_attributes_for to create a new registration note on the same form as a new registration (has many registration notes). Great.

Problem: On the edit form for the existing registration, I want another new registration note to be created, but I don't want to see a field for each of the existing registration notes.

I have this

class Registration < ActiveRecord::Base   attr_accessible :foo, :bar, :registration_notes_attributes   has_many :registration_notes   accepts_nested_attributes_for :registration_notes end 

and this

class RegistrationsController < ApplicationController   def edit     @registration = Registration.find(params[:id])     @registration.registration_notes.build   end end 

and in the view I am doing this:

<%= form_for @registration do |r| %>   <%= r.text_field :foo %>   <%= r.text_field :bar %>   <%= r.fields_for :registration_notes do |n| %>     <%= n.text_area :content %>   <% end %> <% end %> 

and it is creating a blank text area for a new registration note (good) and each existing registration note for that registration (no thank you).

Is there a way to only create a new note for that registration and leave the existing ones alone?

like image 947
Jason Galuten Avatar asked Feb 14 '13 21:02

Jason Galuten


2 Answers

EDIT: My previous answer (see below) was bugging me because it's not very nice (it still loops through all the other registration_notes needlessly). After reading the API a bit more, the best way to get the behaviour the OP wanted is to replace:

<%= r.fields_for :registration_notes do |n| %> 

with:

<%= r.fields_for :registration_notes, @registration.registration_notes.build do |n| %> 

fields_for optionally takes a second parameter which is the specific object to pass to the builder (see the API), which is built inline. It's probably actually better to create and pass the new note in the controller instead of in the form though (just to move the logic out of the view).


Original answer (I was so close):

Just to clarify, you want your edit form to include a new nested registration note (and ignore any other existing ones)? I haven't tested this, but you should be able to do so by replacing:

  <%= r.fields_for :registration_notes do |n| %> 

with:

  <%= r.fields_for @registration.registration_notes.build do |n| %> 

EDIT: Okay, from a quick test of my own that doesn't work, but instead you can do:

<%= r.fields_for :registration_notes do |n| %>   <%= n.text_area :content if n.object.id.nil? %> <% end %> 

This will only add the text area if the id of the registration note is nil (ie. it hasn't been saved yet).

Also, I actually tested this first and it does work ;)

like image 130
zkcro Avatar answered Oct 19 '22 18:10

zkcro


If you want to create a new registration form on your edit action, you can just instantiate a new registration_note object. Right now, your form is for the existing registration object.

I believe this is what you want:

class RegistrationsController < ApplicationController   def edit     @new_registration_note = RegistrationNote.new     @registration = Registration.find(params[:id])     @registration.registration_notes.build   end end 

In your view, you should pass a hidden param that references the registration record id:

<%= form_for @new_registration_note do |r| %>   <%= r.hidden_field :registration_id, :value => @registration.id  %>   <%= r.text_area :content  %> <% end %> 

Now, you can create your new registration note that belongs to @registration. Make sure you have a column in your registration_notes table to point to the registration. You can read more about associations here: http://guides.rubyonrails.org/association_basics.html

like image 33
Huy Avatar answered Oct 19 '22 19:10

Huy