1

HI I am trying to implement the MTI in my application. I have a Person Model and 2 models inheriting from it: Client and TeamMember. When creating a Team Member I want to save to to database vallues for both person (first and last name, email etc) and team member(experience level, type of team, if lead or not). I am using the nested attributes form so in my team member form I am nesting the person fields. Unfortunatellly I am getting "Can't mass-assign protected attributes: person" error when trying to save. Can anyone tell me how this can be solved? Thanks! Models:

UPDATED TeamMember class but still the same error also tried people_attributes and persons_attributes and none of these worked

class TeamMember < ActiveRecord::Base
  has_many :project_team_members
  has_many :projects, through: :project_team_members
  has_one :person, as: :profile, dependent: :destroy
  accepts_nested_attributes_for :person
  attr_accessible :person_attributes, :experience_level, :lead, :qualification, :team
end

class Person < ActiveRecord::Base
  belongs_to :company
  belongs_to :profile, polymorphic: true
  attr_accessible :email, :first_name, :last_name, :phone_number, :profile_id,     :profile_type
end

Controller as follows:

class TeamMembersController < ApplicationController
  def create
    person = Person.create! { |p| p.profile = TeamMember.create!(params[:team_member]) }
    redirect_to root_url
  end

and the view:

<%= form_for(@team_member) do |f| %>
  <%= f.fields_for :person do |ff| %>
    <div>
      <%= ff.label :first_name %>
      <%= ff.text_field :first_name %>
    </div>
    <div>
      <%= ff.label :last_name %>
      <%= ff.text_field :last_name %>
    </div>
    <div>
      <%= ff.label :phone_number %>
      <%= ff.text_field :phone_number %>
    </div>
    <div>
      <%= ff.label :email %>
      <%= ff.text_field :email %>
    </div>
    <div>
      <%= ff.label :company_id %>
      <%= ff.text_field :company_id %>
    </div>
<% end %>
<div class="field">
  <%= f.label :team %><br />
  <%= f.text_field :team %>
</div>
<div class="field">
  <%= f.label :experience_level %><br />
  <%= f.text_field :experience_level %>
</div>
<div class="field">
  <%= f.label :qualification %><br />
  <%= f.text_field :qualification %>
</div>
<div class="field">
  <%= f.label :lead %><br />
  <%= f.check_box :lead %>
</div>
  <div class="actions">
<%= f.submit %>
</div>

UPDATED TeamMembersController (Solution thanks to the courtesy of Tiago)

def new
  @team_member = TeamMember.new
  @team_member.build_person

  respond_to do |format|
    format.html # new.html.erb
    format.json { render json: @team_member }
  end
end

def create
  @team_member = TeamMember.create!(params[:team_member])
  redirect_to root_url
end
evoo
  • 300
  • 4
  • 15

1 Answers1

1

To mass assign attributes in a nested form, you'll need to specify:

class TeamMember < ActiveRecord::Base
  has_many :project_team_members
  has_many :projects, through: :project_team_members
  has_one :person, as: :profile, dependent: :destroy
  :experience_level, :lead, :qualification, :team #what is this line doing??
  accepts_nested_attributes_for :person      
  attr_accessible :person_attributes    
end

EDIT:

In the action called before the form you need to build person. Like:

@team_member = TeamMember.new
@team_member.build_person

Then you'll have one person (non-persisted) associated with @team_member.

Tiago Farias
  • 3,397
  • 1
  • 27
  • 30
  • Actually when I add line accepts_nested_attributes_for :person and refresh the page, the fields for person completely disappear. – evoo Jul 30 '14 at 23:35
  • Ok. It probably disappeared because you're passing @team_member just initialized with no person associated. Right? – Tiago Farias Jul 31 '14 at 00:50
  • yes, indeed I am. When action new is invoked I initialize the TeamMember object. However when I try adding the line suggested (@team_member.person.build), it returns 'undefined method `build' for nil:NilClass'. Why is that? By the way Tiago- I really appreciate your help. – evoo Jul 31 '14 at 01:33
  • I'm sorry. My mistake. I edited the answer. You should try: @team_member.build_person when it's a has_one association. build() is for has_many. – Tiago Farias Jul 31 '14 at 01:58
  • That worked except for the fact that now 2 person objects are saved to db: one with the data I want and then a millisecond later an empty one. – evoo Jul 31 '14 at 09:24
  • 1
    I solved this by changing my create methods as above. Tiago- you are the best :) Thank you so much! – evoo Jul 31 '14 at 09:37