views:

276

answers:

3

I'm working on an association between two models:

class Person < ActiveRecord::Base
  belongs_to :user
end

class User < ActiveRecord::Base
  has_one :person
end

Many person records exist in the system that don't necessarily correspond to a user, but when creating a user you need to either create a new person record or associate to an existing one.

What would be the best way to associate these two models when the person record already exists? Do I need to manually assign the user_id field, or is there a Rails way of doing that?

A: 

You first have to do a nested form :

<% form_for @user do |user| %>
  <%= user.text_field :name %>
  <% user.fields_for user.person do |person| %>
    <%= person.text_field :name %>
  <% end %>
  <%= submit_tag %>
<% end %>

In your User model :

class User < ActiveRecord::Base
  accepts_nested_attributes_for :person
end

If you want the person deleted when the user is :

class User < ActiveRecord::Base
  accepts_nested_attributes_for :person, :allow_destroy => true
end

And in your controller do nothing :

class UserController < ApplicationController
  def new
    @user = User.new
    #find the person you need
    @user.person = Person.find(:first)
  end

  def create
    @user = User.new(params[:user])
    @user.save ? redirect_to(user_path(@user)) : render(:action => :new)
  end
end
Mike
There's a problem with nested forms here. How does one link an existing person to a new user?
EmFi
Yeah, that's what I'm doing if both are created at the same time, but if one of them already exists, this won't work.
Adam Lassek
I updated the code to make it work even with a person existing
Mike
A: 

If you don't want to create/alter a form for this, you can do

@person_instance.user = @user_instance

For has_many relationships, it would be:

@person_instance.users << @user_instance
JRL
+1  A: 

Where @user is a recently created user, and @person is an existing person.

@user.person = @person
@user.save

Alternately:

User.new :person => @person, ... #other attributes

or in params form:

User.new(params[:user].merge({person => @person}))

As far as forms go:

<% form_for @user do |f| %>
  ...
  <% fields_for :person do |p| %>
    <%= p.collection_select, :id, Person.all,  :id, :name, :include_blank => "Use fields to create a person"%>
    <%= p.label_for :name%>
    <%= p.text_field :name %>
    ...
  <% end %>
<% end %>

And in the user controller:

def create
  @user = User.create(params[:user])
  @person = nil
  if params[:person][:id]
    @person = Person.find(params[:person][:id])
  else
    @person = Person.create(params[:person])
  end
  @user.person = @person
  ...
end
EmFi