Fields_for

I need to display information from the collection in a fields_for
without using the fields_for block’s object. For example, in the
following code:

<% form_for :my_object, @my_object, :url => { :action => “my_action” }
do |form| %>
Last name: <%= form.text_field :last %>
<% from.fields_for :my_collection do |fields_for_object| %>

    <%= fields_for_object.text_field :my_attribute %> # <<<<< This

is the line I’m having trouble with.

<% end -%>
<%= submit_tag 'Save' %>

<% end %>

I would like to replace:
<%= fields_for_object.text_field :my_attribute %>

With simply:
<%= @an_object.my_attribute %>

Basically I just want to display an attribute that belongs to the
collection object being processed as text, with no ‘input’ box or
anything else around it. I have looked and looked but couldn’t find an
example. Is this possible?

Thank you.

Sorry, there was a typo: <% from.fields_for :my_collection do |
fields_for_object| %> should have been <%
form.fields_for :my_collection do |fields_for_object| %>. Also, after
thinking about it, what I am really looking for is access to the
collection object being processed, not just one of it’s attributes.

Any help would be much appreciated.

Thank you.

pepe wrote:

Sorry, there was a typo: <% from.fields_for :my_collection do |
fields_for_object| %> should have been <%
form.fields_for :my_collection do |fields_for_object| %>. Also, after
thinking about it, what I am really looking for is access to the
collection object being processed, not just one of it’s attributes.

Then why don’t you just call methods on @my_object.my_collection ? It
sounds like you don’t need fields_for.

Any help would be much appreciated.

Thank you.

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Marnen,

I do need fields_for, I am getting at data 2 levels deep in
associations (main table + association + association) and I need to
update the contents of the associations.

I am just learning how to use ‘fields_for’ so forgive me if I sound
like I don’t know what I’m talking about.

My understanding is that ‘fields_for’ will iterate through the
collection, hence working with one element/object of the collection in
each iteration. If I need an attribute from the element/object at each
iteration, how would I know which element to access with
@my_object.my_collection? I don’t even know if there is an index I can
use to get to the element I need as in @my_object.my_collection
[my_index], hence allowing me to do something like:

<%= @my_object.my_collection[my_index].my_attribute %>

In any case, I found a line of code “hidden” in the documentation that
gave me a clue to find what I needed:

<% if project_fields.object.active? %>

As it turns out you can access the object that ‘fields_for’ is using
by just using method ‘object’ on the block object (“fieds_for_object”
in the sample below):

<% form_for :my_object, @my_object, :url => { :action => “my_action” }
do |form| %>
<% form.fields_for :my_collection do |fields_for_object| %>
<%= fields_for_object.object.my_attribute %> # <<< This is
what I was looking for

Thanks for the insight, though.

On Sat, Jan 9, 2010 at 9:19 PM, pepe [email protected] wrote:

I am just learning how to use ‘fields_for’ so forgive me if I sound
like I don’t know what I’m talking about.

My understanding is that ‘fields_for’ will iterate through the
collection, hence working with one element/object of the collection in
each iteration. If I need an attribute from the element/object at each
iteration, how would I know which element to access with
@my_object.my_collection? I don’t even know if there is an index I can
use to get to the element I need as in @my_object.my_collection
[my_index], hence allowing me to do something like:

No fields_for doesn’t do any iteration. It’s used for setting up a
scope for one or more form fields for a different object than the one
which scopes an outer form_for

From the doc:

<% form_for @person, :url => { :action => “update” } do |person_form| %>
First name: <%= person_form.text_field :first_name %>
Last name : <%= person_form.text_field :last_name %>

<% fields_for :person do |permission_fields| %>
   Admin?: <%= permission_fields.check_box :admin %>
<% end %>

<% end %>

So just like form_for doesn’t do any iteration, neither does fields_for.

Since you haven’t told us any more about what you want to do, I don’t
know how to help any further.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: Rick DeNatale - Developer - IBM | LinkedIn

Thanks Rick,

After I read your post and looked for the nth time at the
documentation I finally “saw” a couple of things that I had completely
misunderstood. I still need help, though. I’ll try to explain as best
as possible.

  • The application uses a legacy DB
  • A person has many person_projects (1 to n)
  • A person_project has one project
  • A person_project has one supervisor
  • A project contains a group code (this is important, the projects are
    selected by the group code)
  • A project has one supervisor (1)
  • A project has many contractors (0 to n)
  • A contractor has one supervisor (1)
  • A supervisor is not a person, meaning his/her data is not in the
    same table as a person’s data (remember, this is a legacy DB)
  • The application is “wizard” style and the same pages are used for
    create/update
  • The information should not be changed/created until the last page of
    the “wizard” is hit, which fortunately is the page used to select the
    information for the person_project records

In a first page the user selects the group codes and that list will
provide all the projects a person should have person_projects for.
Once the group codes are selected the next page should display a table/
list of the projects. If the person record already exists this list
might match exactly the current person_projects list and/or contain
different projects and/or… every possible combination. In addition to
that for each project there should be a drop down of supervisors to
choose from composed of:

  • The current person_project supervisor if the person_project record
    exists
  • The project supervisor (the supervisor ID stored in the
    person_project record could be different [wrong or most likely empty]
    than what the project record indicates should be)
  • All the supervisors for the project contractors

The person_project table should be updated by:

  • Removing any record from the person_projects table not on the
    selected list
  • Updating the signatory IDs in those existing person_project records
    where they have changed
  • Adding new records for any projects not yet in the person_project
    table

Unfortunately I am not as comfortable with Rails yet as I would like
to be and I have been working on this on and off for more than 2 weeks
now. I have hit every possible page (many times) I could find with
information about complex forms and multi record processing, watched
the railscasts, hit the books, everything… Depending on the approach I
take sometimes validations are skipped or new person_project records
are not saved, or… I’ve hit every possible roadblock.

If you guys know how to solve this riddle I would be very, very
thankful.

Thanks a lot.

pepe wrote:
[…]

Unfortunately I am not as comfortable with Rails yet as I would like
to be and I have been working on this on and off for more than 2 weeks
now. I have hit every possible page (many times) I could find with
information about complex forms and multi record processing, watched
the railscasts, hit the books, everything… Depending on the approach I
take sometimes validations are skipped or new person_project records
are not saved, or… I’ve hit every possible roadblock.

Which tests are failing under which circumstances?

If you guys know how to solve this riddle I would be very, very
thankful.

Thanks a lot.

Best,
–Â
Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Hi Marnen,

Thanks for taking an interest. I really appreciate you and Rick taking
the time to check on my problem.

I finally made the whole thing work (kind of). I know I am doing
something wrong because the associated objects validations are not
being hit, probably because I am creating the wrong type of object,
(‘project’ rather than ‘person_project’) for the form as you can see
in the params hash below, but at this point I am already too tired of
the problem and I am also too late to keep looking into it or I won’t
meet the deadline I have. I would like to fix it in the (near) future,
though, so here goes some more info in case it helps.

This is a sample of the params hash (edited):

person: !map:HashWithIndifferentAccess

person fields and values go here

person_projects_attributes: !map:HashWithIndifferentAccess
“0”: !map:HashWithIndifferentAccess
project_attributes: !map:HashWithIndifferentAccess
id: “000267”
project_id: “000267”
supervisor_id: “10”
id: “10326”
“1”: !map:HashWithIndifferentAccess
project_attributes: !map:HashWithIndifferentAccess
id: 000392
project_id: 000392
supervisor_id: “2”

I ended up validating the associated objects values by hand in the
controller. Something like this:

def validate_person_projects_list
params[:person][:person_projects_attributes].each_pair do |index,
person_project|
if person_project[:supervisor_id].blank?
@person.errors.add_to_base ‘All projects must have a
supervisor.’
return
end
end
end # def validate_person_projects

This is the form (edited):

<% form_for :person, @person, :url => { :action => “approval” } do |f|
%>

person’s fields go here

<% for @person_project in @person.person_projects %>
  <% f.fields_for :person_projects, @person_project  do |

pp_fields| %>
<%= pp_fields.hidden_field :project_id -%>
<%= pp_fields.select :supervisor_id,
@person_project.supervisors.map {|s| [s.id.to_s + ’ -> ’ + s.lname.strip + ', ’ + s.fname.strip, s.id]}.sort {|a, b| a[0] <=>
b[0]} -%>
<% end %>
<% end %>
<%= submit_tag ‘Save’ -%>
<% end -%>

@person_project#supervisors is a model method that will return the
list of supervisor objects to choose from: current record’s, current
record project’s and current record project contractors’.

Thanks again for taking the time. I really appreciate it.