On 7/8/06, Sanjay Tibrewal <stibrewal@gmail.com>
wrote:>
> Folks,
>
> Am new to RoR and am building an example to get myself familiar. I am
> running into a simple issue while creating a user registration page.
>
> I have a User and Address models defined as below (partial/relevant code
> included below). User has_one address and Address belongs_to user. I have a
> foreign key defined in address table that refers to user(id)
>
> In a form I take in username, password, password_confirmation and address
> fields (add_user.rhtml below). I then try to populate the data through an
> add_user action in the user_controller - code included below. For some
> reason I am getting a foreign key violation error as below.
>
>
>
> class User < ActiveRecord::Base
> has_one :address
> # validation stuff here
> def create_addr(params)
> address = Address.new(params[:address])
> end
>
> # Other stuff here
> end
>
> class Address < ActiveRecord::Base
> belongs_to :user
> validates_presence_of :street, :city, :zip
> end
>
> class UserController < ApplicationController
>
> layout "admin"
>
> def add_user
> if request.post?
> @user = User.new(params[:user])
> @user.last_login_at = Time.now
> @user.create_addr(params)
> begin
> logger.info("---------------> Saving user object
> <-----------------")
> @user.save
> flash[:notice] = "User #{@user.username} created from new
function"
>
> @user = User.new
> rescue Exception => e
> flash[:notice] = "Can''t save both address and
user"
> flash[:notice] = e.message
> end
> end
> end
> end
>
>
> add_user.rhtml
>
> <div>
> <%= debug(params) %>
> <%= error_messages_for ''user'' %>
> <%= error_messages_for ''address'' %>
>
> <fieldset>
> <legend>Enter User Details</legend>
>
> <%= start_form_tag %>
> <p>
> UserName: <br />
> <%= text_field(''user'',
''username'') %>
> </p>
>
> <p>
> Password: <br />
> <%= text_field(''user'',
''password'') %>
> </p>
>
> <p>
> Confirm Password: <br />
> <%= text_field(''user'',
''password_confirmation'') %>
> </p>
>
> <p>
> Street: <br />
> <%= text_field(''address'',
''street'') %>
> </p>
>
> <p>
> City: <br />
> <%= text_field(''address'',
''city'') %>
> </p>
>
> <p>
> Zip: <br />
> <%= text_field(''address'',
''zip'') %>
> </p>
>
> <%= submit_tag "Add User", :class =>
"submit" %>
>
> <%= end_form_tag %>
> <p>
> <%= button_to "Have Account", :action => :login
%>
> </p>
> </fieldset>
> </div>
>
>
> I get the following error message on the page from the Exception (and log
> file)
> Mysql::Error: #23000Cannot add or update a child row: a foreign key
> constraint fails: INSERT INTO users (`hashed_pwd`, `last_login_at`, `salt`,
> `username`, `firstname`, `lastname`, `address_id`, `company_id`,
> `login_count`, `created_at`)
> VALUES(''fce4d31d2ddf5b0ffd122189b9d575362f79c9c9'',
> ''2006-07-07 23:29:09'', ''
302121320.0514656016603112'', ''rohant'',
'''', '''', 0,
> 0, 0, ''2006-06-11 01:39:18'')
>
> The output from debug(params) is as below.
>
> --- !ruby/hash:HashWithIndifferentAccess
> user: !ruby/hash:HashWithIndifferentAccess
> password_confirmation: rohant
> username: rohant
> password: rohant
> commit: Add User
> action: add_user
> controller: user
> address: !ruby/hash:HashWithIndifferentAccess
> city: San Jose
> zip: "95125"
> street: 7777 Pitkin Ct
>
> Clearly I am missing something simple here but am not sure what. The part I
> am not clear about is how does Rails pick up the fact that the address
> instance needs to be saved automatically when I save the user instance? I
am
> trying to do something similar to what Dave has done with his Depot example
> in his book but obviously something here is not right.
Truth is that Rails doesn''t know at all most of the time, so your call
to Address.new needs to be followed up by an Address.save unless you
create the address by using the special has_one calls. Rails will
figure it out if you do User.create_address(params[:address]) but if
you create your own address creation function you''ll have to make sure
that you save too.
Check out the has_one/many/habtm functions in the docs, there are a
ton of really awesome prefab functions to do exactly what you''re
working on.
Also, as you would find out after sorting out the saving problem, the
address_id is in the wrong table I believe. foreign_id always lives in
the table that belongs_to the other object. So if address belongs to
user your address row should have user_id rather than the user row
having an address_id. You can change the structure or just switch the
has_one/belongs_to statements. There''s a good snippet about this on
the has_one/many/habtm page of the docs.
http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html
Cheers,
Chuck Vose