Rails 3 Nested Forms - ruby-on-rails

I have a Person model and an Address Model:
class Person < ActiveRecord::Base
has_one :address
accepts_nested_attributes_for :address
end
class Address < ActiveRecord::Base
belongs_to :person
end
In my people controller I have #person.build_address in my new action. My forms builds correctly. The problem is that when I submit the form, a person record and an address record is created but they aren't linked via the address_id column in the Person table.
Am I missing a step in the controller?
Thanks!
New Action
UPDATE
def new
#person = Person.new
#person.build_address
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => #person }
end
end
Form Code
UPDATE
<%= form_for(#person) do |f| %>
<% if #person.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#person.errors.count, "error") %> prohibited this person from being saved:</h2>
<ul>
<% #person.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :telephone %><br />
<%= f.text_field :telephone %>
</div>
<div class="field">
<%= f.label :mobile_phone %><br />
<%= f.text_field :mobile_phone %>
</div>
<div class="field">
<%= f.label :date_of_birth %><br />
<%= f.date_select :date_of_birth %>
</div>
<div class="field">
<%= f.label :gender %><br />
<%= f.select(:gender, Person::GENDER_TYPES) %>
</div>
<div class="field">
<%= f.label :notes %><br />
<%= f.text_area :notes %>
</div>
<div class="field">
<%= f.label :person_type %><br />
<%= f.select(:person_type, Person::PERSON_TYPES) %>
</div>
<%= f.fields_for :address do |address_fields| %>
<div class="field">
<%= address_fields.label :street_1 %><br />
<%= address_fields.text_field :street_1 %>
</div>
<div class="field">
<%= address_fields.label :street_2 %><br />
<%= address_fields.text_field :street_2 %>
</div>
<div class="field">
<%= address_fields.label :city %><br />
<%= address_fields.text_field :city %>
</div>
<div class="field">
<%= address_fields.label :state %><br />
<%= address_fields.select(:state, Address::STATES) %>
</div>
<div class="field">
<%= address_fields.label :zip_code %><br />
<%= address_fields.text_field :zip_code %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

You need to have accepts_nested_attributes_for :address on your Person model for this to work nicely. In your create action you can then do this:
def create
#person = Person.new(params[:person])
...
end
Then Rails will take care of the rest.
UPDATE: if the address_id column is in the people table then it should be belongs_to :address, not has_one :address

Why is your address built in your new action, and not in the create action? You're building an address from a non saved model, without an id, so the foreign key can't be set. You should keep your #person in your new action, but put your build_address in your create action, after #person has been saved.

Related

Bootstrap-form gem, strange error

Here is the code for a form created with the bootstrap-form gem for rails.
<%= bootstrap_form_tag(user_sessions_path) do |f| %>
<div class="field">
<%= f.label_tag :email %><br />
<%= f.text_field_tag :email %>
</div>
<div class="field">
<%= f.label_tag :password %><br />
<%= f.password_field_tag :password %>
</div>
<div class="actions">
<%= f.submit_tag "Login" %>
</div>
<% end %>
This throws an error: no implicit conversion of symbol to string on the first line of the form containing the user sessions path. Not sure why this is happening
I believe you have to be explicit about the url. Like this:
<%= bootstrap_form_tag(url: user_sessions_path) do |f| %>
<div class="field">
<%= f.label_tag :email %><br />
<%= f.text_field_tag :email %>
</div>
<div class="field">
<%= f.label_tag :password %><br />
<%= f.password_field_tag :password %>
</div>
<div class="actions">
<%= f.submit_tag "Login" %>
</div>
<% end %>
Check the source code. You can see as how the bootstrap_form_tag method, expects a Hash parameter:
def bootstrap_form_tag(options = {}, &block)
options[:acts_like_form_tag] = true
bootstrap_form_for("", options, &block)
end

How to create a HTTP post request using the form fields to the external websites API using Ruby on Rails?

I am trying to create a HTTP post request using the form fields to the external website here it is factual.com
I have created the method in the my data_controller.rb which is like
def posttofactual
uri = URI.parse("http://api.factual.com/v2/tables/Nj0JN3/input?")
# Full control
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"name" => "datum.name", "address" => "datum.address", "locality" => "datum.locality", "region" => "datum.region", "postcode" => "datum.postcode","category" => "datum.category","website" => "datum.website","latitude" => "datum.latitude","longitude" => "datum.longitude","&APIKey=" => "myapikey" })
# Tweak headers, removing this will default to application/x-www-form-urlencoded
request["Content-Type"] = "application/json"
response = http.request(request)
end
I have a form like
<%= form_for(#datum) do |f| %>
<% if #datum.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#datum.errors.count, "error") %> prohibited this datum from being saved:</h2>
<ul>
<% #datum.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :address %><br />
<%= f.text_field :address %>
</div>
<div class="field">
<%= f.label :locality %><br />
<%= f.text_field :locality %>
</div>
<div class="field">
<%= f.label :region %><br />
<%= f.text_field :region %>
</div>
<div class="field">
<%= f.label :postcode %><br />
<%= f.number_field :postcode %>
</div>
<div class="field">
<%= f.label :category %><br />
<%= f.text_field :category %>
</div>
<div class="field">
<%= f.label :website %><br />
<%= f.text_field :website %>
</div>
<div class="field">
<%= f.label :latitude %><br />
<%= f.text_field :latitude %>
</div>
<div class="field">
<%= f.label :longitude %><br />
<%= f.text_field :longitude %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
I want to call "posttofactual" method on this line <%= f.submit %> on the form field.
It seems like your form will post to either create or update method of the controller. There you should extract data from params and call your posttofactual method.

Form_for generates resource path ending with '.1'

I have a resource called :school and when I call form_for(#school) it generates the form action:
/school.1
I'm new to all this so any clues as to why it's doing that would be much appreciated. Sleep deprived and heading for a deadline in 3 hours, arrrggg!
Thanks :)
routes.rb:
resource:school
school.rb:
<%= form_for(#school, :url => school_path) do |f| %>
<% if #school.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#school.errors.count, "error") %> prohibited this school from being saved:</h2>
<ul>
<% #school.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :address1 %><br />
<%= f.text_field :address1 %>
</div>
<div class="field">
<%= f.label :address2 %><br />
<%= f.text_field :address2 %>
</div>
<div class="field">
<%= f.label :address3 %><br />
<%= f.text_field :address3 %>
</div>
<div class="field">
<%= f.label :town %><br />
<%= f.text_field :town %>
</div>
<div class="field">
<%= f.label :county %><br />
<%= f.text_field :county %>
</div>
<div class="field">
<%= f.label :postcode %><br />
<%= f.text_field :postcode %>
</div>
<div class="field">
<%= f.label :local_authority_id %><br />
<%= f.collection_select :local_authority_id, LocalAuthority.all, :id, :name %>
</div>
<% if current_user.person.primary_user? %>
<div class="field">
<%= f.label 'Are you happy for us to send you regular updates about VRH?' %><br />
<%= f.check_box :allow_contact %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
by using the singular resource method you are telling rails that only one of these objects exist, in your routes file I think you need to change your resource :school to...
resources :schools
If however you do want only one school then I think you will need to add the url option to form_for...
<% form_for(#school, :url => school_path) %>
Proposed solution for follow up questions...
I think what you need will be something like this...
# routes.rb
resources :users do
resources :schools
end
resources :schools
# app/controllers/schools_controller.rb
class SchoolsController < ApplicationController
def new
#user = User.find(params[:user_id])
#school = #user.build_school
end
def create
#user = User.find(params[:user_id])
#school = #user.build_school(params[:school])
if #school.save
# success...
else
# fail...
end
end
def edit
#school = School.find(params[:id])
end
def update
#school = School.find(params[:id])
if #school.update_attributes(params[:school])
# success
else
# fail
end
end
end
# app/views/schools/new.html.erb
<%= form_for([#user, #school]) do |f| %>
<!-- fields go here -->
<% end %>
# app/views/schools/edit.html.erb
<%= form_for([#user, #school]) do |f| %>
<!-- fields go here -->
<% end %>
I just had a similar issue with a singular profile resource in my routes.rb file:
resource :profile
It took me a few hours to find a solution so I decided to share it to save someone else the trouble.
I had to remove the "(.:format)" part of the route (shown when running "rake routes"), by specifying a specific format:
constraints :format => "html" do
resource :profile
end
I also had to add the :url option to form_for tags:
<% form_for(#profile, :url => profile_path) %>
and that worked.

Associated model is not saving data when page is refreshed

Rails 3.1 RC4
I have a 1:1 association between User and Profile.
When I submit the new profile form, the data I've entered is displayed just fine (see screenshot: http://i.imgur.com/fY8YU.png), but when I refresh it the data is instantly wiped.
Could anyone tell me what is causing this?
Here's the submit form:
<%= form_for([#user, #user.build_profile]) do |f| %>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :picture %><br />
<%= f.text_field :picture %>
</div>
<div class="field">
<%= f.radio_button(:sex, "male") %>
<%= f.label(:sex, "Male") %>
<%= f.radio_button(:sex, "female") %>
<%= f.label(:sex, "Female") %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Here's the users_controller: https://github.com/imjp/SuperModel/blob/master/app/controllers/users_controller.rb
Here's the profiles_controller: https://github.com/imjp/SuperModel/blob/master/app/controllers/profiles_controller.rb
I'm not sure I agree with your approach. Why don't you do something like this:
In models/user.rb:
accepts_nested_attributes_for :profile
In controllers/users_controller.rb:
def new
#user = User.new
#user.build_profile
end
In views/users/_form.html.erb:
<%= form_for #user do |f| %>
<%= f.text_field :first_name %>
<%= f.fields_for :profile do |pf| %>
<%= pf.text_field :some_profile_field %>
<% end -%>
<%- end -%>
This isn't copied or tested, but it should work. On saving your user, the profile fields are sent along and validated with the user fields and are re-rendered when rendering the form again after a save error. This way you will keep full control over your form and its contents with minimal effort.

Can't get plain old many-to-one nested form to save

I'm on Rails 3. I have a model Client that has an address_id. In my Client form, I have nested Address fields. Here's that the Address part of the form:
<%= f.fields_for #client.address do |address_form| %>
<div class="field">
<%= address_form.label :line1 %><br />
<%= address_form.text_field :line1 %>
</div>
<div class="field">
<%= address_form.label :line2 %><br />
<%= address_form.text_field :line2 %>
</div>
<div class="field">
<%= address_form.label :city %><br />
<%= address_form.text_field :city %>
</div>
<div class="field">
<%= address_form.label :state_id %><br />
<%= select("client[address]", "state_id", State.all.collect {|s| [ s.name, s.id ] }) %>
</div>
<div class="field">
<%= address_form.label :zip %><br />
<%= address_form.text_field :zip %>
</div>
<% end %>
When I try to save my form, I get this:
Address(#23652762896420) expected, got ActiveSupport::HashWithIndifferentAccess(#23652751466220)
I don't understand exactly what that means or why I'm getting it. Here's what params.inspect looks like:
{"commit"=>"Update Client",
"authenticity_token"=>"CBw1fQcsUtXs9x6lKTL4zeoekX1cwuFUrZvZpCShHIc=",
"_method"=>"put",
"utf8"=>"\342\234\223",
"action"=>"update",
"id"=>"16",
"client"=>{"name"=>"Rosie O'Donnell",
"address"=>{"city"=>"Grand Rapids",
"line1"=>"216 Grandville Ave SW",
"zip"=>"49503",
"line2"=>"",
"state_id"=>"1"},
"phone"=>"",
"salon_id"=>"1",
"email"=>""},
"controller"=>"clients"}
Can someone please tell me what's going on?
See here: http://guides.rubyonrails.org/2_3_release_notes.html#nested-object-forms (It's a Rails 2.3 article, but it should apply to Rails 3 as well)
In your Client model you need this line:
accepts_nested_attributes_for :address
Also, change the first line of your nested form to this:
<%= f.fields_for :address do |address_form| %>
Assuming you have the following in your clients class:
accepts_nested_attributes_for :address
and
attr_accessible :address_attributes
I would modify the form as follows:
<%= f.fields_for :address do |address_form| %>
<div class="field">
<%= address_form.label :line1 %><br />
<%= address_form.text_field :line1 %>
</div>
<div class="field">
<%= address_form.label :line2 %><br />
<%= address_form.text_field :line2 %>
</div>
<div class="field">
<%= address_form.label :city %><br />
<%= address_form.text_field :city %>
</div>
<div class="field">
<%= address_form.label :state_id %><br />
<%= select("client[address]", "state_id", State.all.collect {|s| [ s.name, s.id ] }) %> </div>
<div class="field">
<%= address_form.label :zip %><br />
<%= address_form.text_field :zip %>
</div>
<% end %>

Resources