Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checkbox form in Ruby on Rails based on many-to-many relationship

My Ruby on Rails application has a DocumentType model and a PersonType model. A Document is of a DocumentType (eg Letter, Postcard) and lists one or more People. Each Person is assigned a PersonType to represent their relationship to a Document (sender, receipient, author etc.). A user is only allowed to assign People to the PersonTypes relevant to the DocumentType.

Table definitions:

create_table "document_types", :force => true do |t|
 t.string   "name" 
end

create_table "document_types_person_types", :id => false, :force => true do |t|
 t.integer "document_type_id"
 t.integer "person_type_id"
end

create_table "person_types", :force => true do |t|
 t.string   "name"
end

Model Definitions:

class Document < ActiveRecord::Base
 has_many :people, :dependent => :destroy
 belongs_to :document_type
end

class DocumentType < ActiveRecord::Base
 has_many :documents
 has_and_belongs_to_many :person_types
end

class Person < ActiveRecord::Base
belongs_to :document
has_and_belongs_to_many :person_types
end

class PersonType < ActiveRecord::Base
 has_and_belongs_to_many :people
 has_and_belongs_to_many :document_types
end

Table examples:

documents
 id:   1 
 document_type_id: 1
 name: Letter from John Smith  to Jane and Joe Smith

document_types
 id: 1  |  name: letter

document_types_person_types
 document_type_id: 1  |   person_type_id:   1
 document_type_id: 1  |   person_type_id:   2
 document_type_id: 1  |   person_type_id:   4

person_types
 id: 1  |  name: Sender
 id: 2  |  name: Recipient
 id: 3  |  name: Photographer
 id: 4  |  name: Author  

people
 id: 1  |  document_id: 1  |  name: John Smith  |  person_type_id: 1
 id: 2  |  document_id: 1  |  name: Jane Smith  |  person_type_id: 2
 id: 3  |  document_id: 1  |  name: Joe Smith   |  person_type_id: 2

When a user is adding a Person to a Document, they will select what the relationship that Person is to the Document, and that will be stored within the Person model (or extended model).

A Document will only present PersonTypes that are relevant to that DocumentType (for example, a Photograph won't have an Author, but will have a Photographer).

So after all that...What I want to achieve is an admin interface for the DocumentTypes, representing the document_types_person_types table which shows all the PersonTypes and allows me to select a checkbox if a PersonType is applicable:

EDIT DocumentType Letter
Sender       [x]
Recipient    [x]
Photographer [ ]
Author       [x]

Those PersonTypes selected will then be the only PersonTypes available when adding a Person to a Document. Hopefully more straight forward than my convaluted attempt at explaining may have represented. Could anyone provide any pointers?

edit: For future reference, based on Frederick's answer below, this worked

<% for pt in PersonType.find(:all) %>
  <%= check_box_tag "document_type[person_type_ids][]", pt.id, @document_type.person_types.include?(pt)  %>
  <%= pt.name %>
<% end %>
like image 402
Christian Mayne Avatar asked Nov 03 '22 02:11

Christian Mayne


1 Answers

With an association like this, DocumentType will have a person_type_ids method that returns an array of the ids of the associated person types.

Therefore if you create a set of check boxes where the name is document_type[person_type_ids][] and whose value is the id of each person type then what will be submitted is an array containing the ids of the checked person types, so

document_type.update_attributes params[:document_type]

Would update the association. The only subtlety here is that if no checkboxes are checked then no array is submitted (you can't submit an empty array) and the list of associated person types won't be cleared. I normally get around this by having a hidden field that adds the value 0 to the array (since I know that will never be a legitimate id) and then strip that 0 from the array in the controller.

like image 92
Frederick Cheung Avatar answered Nov 13 '22 03:11

Frederick Cheung