← Back to Upcase

How to include a new association with simple form?


(rafik bennacer) #1

This is the next episode in the saga, implementing a many-to-many relationship that started here ( http://forum.thoughtbot.com/t/how-to-implement-a-has-many-and-belongs-to-many-association-in-rails/863/2 )
after struggling with my DB schema implementation and with help form the awesome thoughtbot people i finally got this to work

class Person < ActiveRecord::Base
 attr_accessible :alignment, :gender, :source, :ethnicity, :description, :first_name, :last_name , :profession_ids
  has_many :roles
  has_many :organizations, through: :roles
  has_many :positions, through: roles
  accepts_nested_attributes_for :roles
end
class Role < ActiveRecord::Base
  belongs_to :person       
  belongs_to :organization 
  belongs_to :position
end
class Organization < ActiveRecord::Base 
   has_many :roles
   has_many :people, through: roles
end
class Position < ActiveRecord::Base 
   has_many :roles
   has_many :people, through: roles
end

What i want to do now, is to create a form that will enter roles with organization and positions that already exist.

<%= simple_form_for @person do |f| %>
  <%= f.input :first_name %>
  <%= f.input :last_name %>
  <%= f.input :alignment , collection: ['democrate','republican','neutral'], include_blank: false %>
  <%= f.input :gender , collection: ['male','female'], include_blank: false %>
  <%= f.input :ethnicity, collection: ['white','african-american','asian-american'], include_blank: false  %>

  <%= f.simple_fields_for :roles do |p| %>
      <%= p.input :organizations,
                  collection: Organization.all,  
                  :label_method => lambda { |organization| "#{organization.name}"},
                  :input_html => {:class => 'chosen-select'} %>   
      <% p.input :positions %>
  <% end %>
  <%= f.button :submit %>
<% end %>

it seems like the simple_field_for is not displaying anything, how do i get this to work?


(Chad Pytel) #2

simple_fields_for is going to iterate over the roles that are already on the user. If the user has no roles, nothing will be there.

If the user doesn’t have any roles (or, if you always want an additional one that could be created), you’re going to want to populate the roles of the user with a new, blank role that can be used for creation of a new role.


(Chad Pytel) #3

Also, just looking at your code again… You may want to do:

  <%= f.simple_fields_for @person.roles do |p| %>

I’m not sure that that will help, but give it a try.

Also, I recommend you don’t use f and p as your variables. I recommend you use form and person_form to increase readability.


(rafik bennacer) #4

i am getting this error now, it seems like it is not able to create a role object:


(Chad Pytel) #5

@rafikrafik Do you see how the error is “Organization expected, got String” this is exactly the error. It is expecting an Organization and and its being given a String.

Take a look at your params. See how its just an organization field? I’d expect this to be organization_id and for the value to be the id of the selected organization.


(rafik bennacer) #6

changing it to organization_id and position_id, fixed the problem of updating a Person.
I still can add a new Role though nor delete one.


(rafik bennacer) #7

I am going to answer to my questions, to add person.
in the controller you need to have:

  # GET /people/new
  # GET /people/new.json
  def new
    @person = Person.new
    @person.roles.build 
  ....

and to delete you would have something like this:

  <%= f.simple_fields_for :roles do |p| %>
      <%= p.input :organization_id,
                  collection: Organization.all,  
                  :label_method => lambda { |organization| "#{organization.name}"},
                  :input_html => {:class => 'chosen-select'} %>   
      <%= p.input :position_id,
                  collection: Position.all,  
                  :label_method => lambda { |organization| "#{organization.name}"},
                  :input_html => {:class => 'chosen-select'}  %>
      <%= p.input :active ,collection: ['true','false'] , include_blank: false %>
      Delete:<%= p.check_box :_destroy %>
  <hr>
  <% end %>