Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create nested objects in Rails3 using accepts_nested_attributes_for?

I cannot figure out how I can setup a form that will create a new Study while also creating the related StudySubject and the Facility. The user_id, facility_id and study_subject_id have to be available to create the Study object as you can see in the database relation model.

Database model

Here is the migration for the studies. The other tables do not contain foreign keys.

def self.up
 create_table :studies do |t|
  t.references :user
  t.references :facility
  t.references :subject
  t.date "from"
  t.date "till"
  t.timestamps
 end
 add_index :studies, ["user_id", "facility_id", "subject_id"], :unique => true
end

The models define the following associations.

# user.rb
has_many :studies

# subject.rb
has_many :studies

# facility.rb
has_many :studies

# study
belongs_to :user
belongs_to :subject
belongs_to :facility

Questions

1) Are the has_many and belongs_to definitions correct?
2) How can I create a study using accepts_nested_attributes_for?
3) A study should only belong to one user. Do I need to add the user_id into every other object to store the association?

I am totally new to Rails since 2 weeks of extensive learning. Sorry for a stupid question maybe.

like image 558
JJD Avatar asked Oct 11 '22 12:10

JJD


1 Answers

Yeah. It works. A good friend offered his help. This is what we set up.
Please mind that I renamed StudySubject to Subject in the meantime.

The model study.rb

belongs_to :student, :class_name => "User", :foreign_key => "user_id"  
belongs_to :subject  
belongs_to :university, :class_name => "Facility", :foreign_key => "facility_id"  

accepts_nested_attributes_for :subject, :university

The controller studies_controller.rb

def new
  @study = Study.new
  @study.subject = Subject.new
  @study.university = Facility.new
end

def create
  @study = Study.new(params[:study])
  @study.student = current_user

  if @study.save
    flash[:notice] = "Successfully created study."
    redirect_to(:action => 'index')
  else
    render('new')
  end
end

I use devise for authentication and cancan for authorization. That is why current_user is available in the controller.

The new study view new.html.erb

<%= form_for @study, :url => { :action => "create" } do |f| %>

  <table summary="Study form fields">

    <%= render :partial => "shared/study_form_fields", :locals =>  { :f => f } %>

    <%= f.fields_for :subject do |builder| %>
      <%= render :partial => "shared/subject_form_fields", :locals =>  { :f => builder } %>
    <% end %>

    <%= f.fields_for :university do |builder| %>
      <%= render :partial => "shared/facility_form_fields", :locals =>  { :f => builder } %>
    <% end %>

  </table>

  <p><%= f.submit "Submit" %></p>

<% end %>

I hope this will save you some time. I spent a lot of time to realize how things have to be set up.

like image 97
JJD Avatar answered Oct 27 '22 00:10

JJD