Skip to content

Instantly share code, notes, and snippets.

@dresselm
Created October 8, 2012 17:19
Show Gist options
  • Save dresselm/3853702 to your computer and use it in GitHub Desktop.
Save dresselm/3853702 to your computer and use it in GitHub Desktop.
<%= form_for(@person) do |f| %>
<fieldset>
<div class="left">
<%= f.label :first_name %><br/>
<%= f.text_field :first_name %>
</div>
<div>
<%= f.label :last_name %><br/>
<%= f.text_field :last_name %>
</div>
<div>
<%= f.label :email %><br/>
<%= f.text_field :email %>
</div>
<div>
<%= f.label :organisation_id %><br/>
<% # You need to customize this so that it displays the names, but sends option values equal to the ids %>
<%= f.select(:organisation_id, Organisation.all.map(&:id), {:include_blank => "--- None ---"}, :id => 'organization_select') %>
</div>
</fieldset>
<%= f.fields_for :address do |address| %>
<%= render 'shared/address', :f => address %>
<% end %>
<%= f.submit %>
<% end %>
# I am assuming you have a User model with a
# has_many :people association?
def create
# Your params for Person creation are found on the params[:person]
# I do not understand what you are doing here. Basically, what's going
# on - if an organisation is selected, you are building the person off of
# the organisation relationship. Your form, however, revolves around people, not
# organisations.
# So, get rid of the complexity below
#if params[:organisation_id]
# @person = current_user.organisations.build_person(params[:person])
#else
# @person = current_user.people.build(params[:person])
#end
# Uncomment this to test the creation against a standalone Person object
# test_person = Person.new(params[:person])
# puts test_person.valid?
# puts test_person.organisation
# puts test_person.address
puts 'testing @person:'
@person = current_user.people.build(params[:person])
puts "valid? #{@person.valid?}"
puts "errors: #{@person.errors.inspect}"
if @person.save
flash[:success] = "Person created."
redirect_to people_path
else
render :action => "new"
end
end
class Organisation < ActiveRecord::Base
has_many :people
has_one :address, :as => :addressable,
:dependent => :destroy
accepts_nested_attributes_for :address, :allow_destroy => true
end
class Person < ActiveRecord::Base
belongs_to :organisation
has_one :address, :as => :addressable,
:dependent => :destroy
# The form sends the address attributes as blank values when they are not entered
# Without the reject, the address model gets populated with blank values and then blows up during validation
accepts_nested_attributes_for :address, :allow_destroy => true, :reject_if => lambda { |a| a[:line1].blank? && a[:line2].blank? && a[:city].blank? && a[:zip].blank? }
# Organization must be selected, unless Address details are added
validates_presence_of :organisation, :unless => "address.present?"
# The Address association must be validated, unless organization is selected
validates_associated :address, :unless => "organisation.present?"
end
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
# These validations are necessary for the validated_associated above
# If there are no validations, then missing organizations and address inputs will not trigger the proper validations
validates_presence_of :line1, :line2, :city, :zip
end
# I excluded all User relationships
class PeopleController < ApplicationController
before_filter :print_params
def index
@people = Person.all
end
def new
# Add default values if you want them displayed
@person = Person.new
# Necessary to build out the blank address fields
@person.build_address
@title = "New person"
end
def edit
@person = Person.find(params[:id])
@title = @person.name
end
def create
# This is the beauty of accepts_nested_attributes
@person = Person.new(params[:person])
if @person.save
flash[:success] = "Person created."
redirect_to people_path
else
Rails.logger.info "==== errors: #{@person.errors.inspect}"
@person.build_address if @person.address.nil?
render :new
end
end
# Just for debugging purposes - remove once you've figured everything out
def print_params
Rails.logger.info "==== params: #{params.inspect}"
end
end
# Once your models are updated, open the console via `rails c` and enter the following tests
# Note: I am using organization vs organisation - you might want to do a search/replace
# I made an assumption that Organization has at least a name attribute
organization = Organization.create(:name => 'Org1')
# Simple method that prints validity and errors
def print_validation(obj)
puts "valid?: #{obj.valid?}"
puts obj.errors.inspect
end
# nested attrs containing a full person, org reference and full address
full_person_attrs = {
:first_name => 'Harry',
:last_name => 'Smith',
:email => 'hsmith@gmail.com',
:organization_id => organization.id,
:address_attributes => {
:line1 => '122 N Lane St',
:line2 => 'Apt 35',
:city => 'Chicago',
:zip => '60625'
}
}
p = Person.create(full_person_attrs)
print_validation(p)
# nested attrs containing a full person and full address
person_address_attrs = {
:first_name => 'Harry',
:last_name => 'Smith',
:email => 'hsmith@gmail.com',
:address_attributes => {
:line1 => '122 N Lane St',
:line2 => 'Apt 35',
:city => 'Chicago',
:zip => '60625'
}
}
p2 = Person.create(person_address_attrs)
print_validation(p2)
# nested attrs containing a full person and org reference
person_organization_attrs = {
:first_name => 'Harry',
:last_name => 'Smith',
:email => 'hsmith@gmail.com',
:organization_id => organization.id
}
p3 = Person.create(person_organization_attrs)
print_validation(p3)
# nested attrs containing a full person, but no org or address
person_without_organization_or_address_attrs = {
:first_name => 'Harry',
:last_name => 'Smith',
:email => 'hsmith@gmail.com'
}
p4 = Person.create(person_without_organization_or_address_attrs)
print_validation(p4)
# nested attrs containing a full person and partial address
# I added presence_of validations in Address for all the attributes
person_with_partial_address_attrs = {
:first_name => 'Harry',
:last_name => 'Smith',
:email => 'hsmith@gmail.com',
:address_attributes => {
:line1 => '122 N Lane St',
:line2 => 'Apt 35'
}
}
p5 = Person.create(person_with_partial_address_attrs)
print_validation(p5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment