开发者

nested_form, collection_select, accepts_nested_attributes_for and fields_for, and adding records to a join table

开发者 https://www.devze.com 2023-03-11 18:18 出处:网络
Update: according to the stack trace, posted at the end of this question, I think the real problem is to figure out what attr_accessible and build association settings I need to get the contributors a

Update: according to the stack trace, posted at the end of this question, I think the real problem is to figure out what attr_accessible and build association settings I need to get the contributors and linkers attributes to update with the new isbn id. Please help me!

Following on from this question...

I've got a join table between two models - isbns and contributors - which have a many to many relationship. I want to use the existing v开发者_StackOverflowalues from the contributor model in a collection_select drop-down, within a nested form using fields_for.

So when I'm creating a new isbn, I don't want to create new contributor records - I want to be able to select existing ones. And I want to be able to select many contributors, which is why I'm using the nested_form gem which allows me to dynamically create additional form fields for contributors.

My question: should I be calling the method on the join table? And if so, why do I get a 'missing block' error despite having pretty much everything attr_accessible and accepts_nested_attributes_for:

isbn.rb:

  attr_accessible :linkers_attributes, :contributors_attributes, :contributor_id,
  has_many   :linkers
  has_many   :contributors, :through => :linkers
  accepts_nested_attributes_for :contributors
  accepts_nested_attributes_for :linkers

contributor.rb:

attr_accessible :linkers_attributes, :isbns_attributes 
  has_many :linkers
  has_many :isbns, :through => :linkers
  accepts_nested_attributes_for :isbns
  accepts_nested_attributes_for :linkers

linker.rb:

belongs_to :isbn
  belongs_to :contributor
  accepts_nested_attributes_for :contributor
  accepts_nested_attributes_for :isbn
  attr_accessible :isbn_id, :contributor_id, :isbns_attributes, :contributors_attributes, :contributor_attributes, :isbn_attributes

isbns controller:

def new
    @isbn  = Isbn.new
    @title = "Create new ISBN"
    1.times {@isbn.linkers.build}
  end

new.html.erb:

<td class="main">
<%= nested_form_for @isbn, :validate => false do |f| %>
<h1>Create new ISBN</h1>
<%= render 'shared/error_messages', :object => f.object %>
<%= render 'fields', :f => f %>
  <div class="actions">
    <%= f.submit "Create" %>
  </div>  

_fields: (option 1)

<%= f.fields_for :contributors do |contributor_form| %>
<li>
<%= contributor_form.label 'Contributor Name' %>
<%= contributor_form.collection_select(:isbn_id, Contributor.all, :id, :personnameinverted ) %>
</li>
<%= contributor_form.link_to_remove "[-] Remove this contributor"%>
<% end %>
<%= f.link_to_add "[+] Add a contributor", :contributors  %>

This creates a new ISBN, and a new record in linkers with the correct isbn_id, but also a new record in contributors, when I actually want the new linker record to contain an existing contributor_id. So I figured I'd do this:

_fields (option 2)

<%= field_set_tag 'Contributor' do %>
<li>
<%= f.label 'Contributor Sequence Number' %>
<%= f.text_field :descriptivedetail_contributor_sequencenumber%>
<%= tooltip(:xxx, :hover) %>
</li>

<%= f.fields_for :linkers do |contributor_form| %>
<li>
<%= contributor_form.label 'Contributor Name' %>
<%= contributor_form.collection_select(:isbn_id,  Contributor.all, :id, :personnameinverted ) %>
</li>
<%= contributor_form.link_to_remove "[-] Remove this contributor"%>
<% end %>
<%= f.link_to_add "[+] Add a contributor", :contributors  %>

But this returns a missing block error.

Huge thanks in advance, I've spent two solid days on this and think I might pop.

update: Here's a clue, the stack trace from this new code, because I figured you can't actually call a method on a join table:

<%= f.fields_for :contributors do |contributor_form| %>
<li>
<%= contributor_form.collection_select(:id, Contributor.all, :id, :personnameinverted, :include_blank => true ) %>



Started POST "/isbns" for 127.0.0.1 at 2011-06-08 20:12:48 +0100
  Processing by IsbnsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"u0TszLESOnZlr4iEiBlVg6w9B5T+EH0dxJg/0E6PKuQ=", "isbn"=>{"descriptivedetail_titledetail_titleelement_titleprefix"=>"", "descriptivedetail_titledetail_titleelement_titlewithoutprefix"=>"qqq", "istc_id"=>"471", "descriptivedetail_contributor_sequencenumber"=>"", "contributors_attributes"=>{"0"=>{"id"=>"1", "_destroy"=>"false"}, "1307560328932"=>{"id"=>"14", "_destroy"=>"false"}}, "descriptivedetail_contributor_contributorrole"=>""}, "commit"=>"Create"}
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
  Contributor Load (0.3ms)  SELECT "contributors".* FROM "contributors" INNER JOIN "linkers" ON "contributors".id = "linkers".contributor_id WHERE "contributors"."id" IN (1, 14) AND (("linkers".isbn_id = NULL))
Completed   in 308ms

So it looks like the contributor IDs are actually being set, but the linker table isn't being passed the isbn id. Onwards...


Well. Here's how I did it.

Installed cocoon gem. Finally got round to installing Haml, too,

I split out the new and update action, so the new form is just a quickie to get the id set, with the bare minimum of fields. Then users can edit it, and add contributors. Not actually bad from the user point of view as they can create an isbn quickly without having to fill in a bazillion fields.

isbns/new.html.haml

%td.main
= semantic_form_for @isbn do |f|
  %h1 Create new ISBN
  = render 'shared/error_messages', :object => f.object
  = render 'fields', :f => f
  %div#actions
  = f.submit "Create"

isbns/_fields.html.haml

- f.inputs do
  = f.input :istc_id, :as => :select, :collection => Istc.all
  = f.input :descriptivedetail_titledetail_titleelement_titlewithoutprefix
  %h3 Contributors
  #tasks
    = f.semantic_fields_for :linkers do |linker|
      = render 'linker_fields', :f => linker
    .links
      = link_to_add_association 'add contributor', f, :linkers
  -f.buttons do
    = f.submit 'Save'

isbns/_linker_fields.html.haml

.nested-fields
  = f.inputs do
    = f.input :contributor_id, :label_method => :keynames, :as => :select, :collection => Contributor.all
    = link_to_remove_association "remove contributor", f

Isbn.rb

  has_many :linkers
  has_many :contributors, :through => :linkers
  accepts_nested_attributes_for :contributors, :allow_destroy => true
  accepts_nested_attributes_for :linkers, :allow_destroy => true

contributor.rb

  attr_accessible :linkers_attributes, :isbns_attributes
  has_many :isbns, :through => :linkers
  has_many :linkers
  accepts_nested_attributes_for :linkers

linker.rb

belongs_to :contributor
belongs_to :isbn
accepts_nested_attributes_for :contributor

Results in

Started POST "/isbns/58" for 127.0.0.1 at 2011-06-09 12:34:14 +0100
  Processing by IsbnsController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"u0TszLESOnZlr4iEiBlVg6w9B5T+EH0dxJg/0E6PKuQ=", "isbn"=>{"istc_id"=>"360", "descriptivedetail_titledetail_titleelement_titlewithoutprefix"=>"thurs title", "linkers_attributes"=>{"0"=>{"contributor_id"=>"3", "_destroy"=>"", "id"=>"68"}, "1"=>{"contributor_id"=>"71", "_destroy"=>"", "id"=>"69"}, "2"=>{"contributor_id"=>"72", "_destroy"=>"", "id"=>"70"}, "3"=>{"contributor_id"=>"3", "_destroy"=>"", "id"=>"71"}}}, "commit"=>"Save", "id"=>"58"}
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 2 LIMIT 1
  Isbn Load (8.2ms)  SELECT "isbns".* FROM "isbns" WHERE "isbns"."id" = 58 ORDER BY descriptivedetail_titledetail_titleelement_titlewithoutprefix LIMIT 1
  Linker Load (0.3ms)  SELECT "linkers".* FROM "linkers" WHERE "linkers"."id" IN (68, 69, 70, 71) AND ("linkers".isbn_id = 58)
  AREL (0.4ms)  UPDATE "linkers" SET "contributor_id" = 3, "updated_at" = '2011-06-09 11:34:14.509943' WHERE "linkers"."id" = 71
  Contributor Load (158.3ms)  SELECT "contributors".* FROM "contributors"
Redirected to http://localhost:3000/isbns/58
Completed 302 Found in 545ms

In other words, from an isbn edit form which has dynamically produced nested fields_for, using formtastic, I can use a drop down menu to select an existing contributor which has a many to many relationship with isbns.

Phew.

0

精彩评论

暂无评论...
验证码 换一张
取 消