views:

148

answers:

3

My question is: How do I make the edit/update methods for my profiles controller stop creating new records when I edit a profile page?

I have a user model and profile model.
user has_one :profile.
profile belongs_to :user.

My routes.rb looks like this: map.resources :users, :has_one => :profile

When a visitor to my app creates a user and hits submit, they are directed to the "create profile" screen.

The following controller, creates a profile such that the created profile url is: localhost:3000/users/[user_id]/profile

def new  
    @profile = `current_user.build_profile`  
end

def create
  @profile = current_user.build_profile(params[:profile])
  if @profile.save
    flash[:notice] = 'Profile was successfully created.'
    redirect_to user_profile_path
  else
    flash[:notice] = 'Error.  Something went wrong.'
    render "new"
  end
end

This all works fine.

The problem occurs when I edit a profile.

At first things seems fine. When I go to the "edit profile" view, the url is correct. For example, if the url for the "show profile" view is localhost:3000/users/1/profile, then the "edit profile" view appears as: localhost:3000/users/1/profile/edit

That's good.

When I make a change and click the update button, that seems to work as well. I get directed to the correct "show profile" view and I get a flash notice confirming the change.

So here's the weird part. When I go back to my index of profiles to view all the profiles in the app, it turns out that the app has created a new profile record each time I update the profile. The original profile record is still there, but there are new additional records. Keep in mind that all the profiles in my app are tied to a user, and the user can have only one profile. So if there are 5 users in my app, now there might be 10 different profiles, each with a url that leads to a busted page because the user_id doesn't exist in the database. For example, localhost:3000/users/7/profile, users/8/profile, etc.

The record gets saved to the profile table in my database, but the user_id column shows a NUL.

I figure that the problem is coming from either (a) the edit/update methods in the profiles controller, or (b) the code I'm using to display profiles on my profile index page.

Here's my profile controller for the edit and update methods:

def edit
    @profile = current_user.profile(params[:id])
end

def update
  @profile = current_user.profile.find(params[:id])
  if @profile.update_attributes(params[:profile])
    flash[:notice] = 'Profile was successfully updated.'
    redirect_to(@profile)
  else
    render "edit"
  end

end

Here's the profile index.html.erb view file:

<div id="posts">
  <% @profiles.each do |profile| -%>
    <% unless profile.blank? -%>
    <div class="profiles">
 <div class="right">
            <p><%=h profile.name %></p>
     <p><%=h profile.category %></p>
            </div>
 <div class="bottom">
         <p><%= link_to 'See Profile', user_profile_path(profile) %></p>
            </div>
    <% end -%>
</div>
<% end -%>

To repeat my question: How do I make the edit/update methods for my profiles controller stop creating new records when I edit a profile page?

UPDATE

Looking at the log, it looks like it's calling the Edit method, but then calling the "create" method instead of the "update" method to execute the action. Here's what I'm getting:

Processing ProfilesController#edit (for IP at 2009-08-29 00:46:06) [GET]
Parameters: {"action"=>"edit", "controller"=>"profiles", "user_id"=>"1"}
User Load (0.3ms) SELECT * FROM "users" WHERE ("users"."id" = 1)
Profile Load (0.6ms) SELECT * FROM "profiles" WHERE ("profiles".user_id = 1) LIMIT 1
Rendering template within layouts/application
Rendering profiles/edit
SQL (0.3ms) SELECT count(*) AS count_all FROM "posts" WHERE ("posts".profile_id = 20)
Rendered users/_login (1.2ms)
Completed in 29ms (View: 16, DB: 1) | 200 OK [http://localhost/users/1/profile/edit%5D

Processing ProfilesController#create (for IP at 2009-08-29 00:46:21) [POST]
Parameters: {"commit"=>"Update", "profile"=>{"city"=>"Brooklyn", "address1"=>"Bedford Ave.", "name"=>"Place", "zip"=>"19876", "address2"=>"Apt. 4", "category"=>"Restaurant", "website"=>"http://www.whatever.com", "description"=>"Place is awesome.", "phone"=>"555-1212", "email"=>"[email protected]", "state"=>"NY"}, "action"=>"create", "authenticity_token"=>"[redacted]", "controller"=>"profiles", "user_id"=>"1"}
User Load (0.3ms) SELECT * FROM "users" WHERE ("users"."id" = 1)
Profile Load (0.6ms) SELECT * FROM "profiles" WHERE ("profiles".user_id = 1) LIMIT 1
Profile Update (0.6ms) UPDATE "profiles" SET "updated_at" = '2009-08-29 04:46:21', "user_id" = NULL WHERE "id" = 20
Profile Create (0.6ms) INSERT INTO "profiles" ("name", "address1", "city", "address2", "zip", "category", "updated_at", "website", "description", "category_id", "phone", "user_id", "state", "email", "created_at") VALUES('Place', 'Bedford Ave.', 'Brooklyn', 'Apt. 4', '19876', 'Restaurant', '2009-08-29 04:46:21', 'http://www.whatever.com', 'Place is awesome.', NULL, '555-1212', 1, 'NY', '[email protected]', '2009-08-29 04:46:21')
Redirected to http://localhost%3A3000/users/1/profile
Completed in 45ms (DB: 2) | 302 Found [http://localhost/users/1/profile%5D

UPDATE

I think this is the relevant part, but let me know if you need more. The rest is just the individual fields.

<% @profile.posts.build if @profile.posts.empty? %>  
<% form_for :profile, @profile, :url => { :controller => 'profiles', :action => 'update' } do |profile_form| %>  
<%= profile_form.error_messages %>
A: 

Try this in your edit/update:

def edit
  @profile = current_user.profile
end

def update
  @profile = current_user.profile
  if @profile.update_attributes(params[:profile])
    flash[:notice] = 'Profile was successfully updated.'
    redirect_to(@profile)
  else
    render "edit"
  end
end

In your edit view try this form_for:

form_for @profile do |profile_form|

If this doesn't work post form tag that rails generates as well as any snippets of your routes.rb that reference profiles.

Andy Gaskell
Didn't work. Same result. But see my updated comments above, explaining some more details.
MikeH
I tried your updated fix, but it threw errors. The form that Rails generates in the html currently is: <form action="/users/1/profile" method="post"><input name="authenticity_token" type="hidden" value="[redacted]" />.
MikeH
routes.rb has no profile reference except: map.resources :users, :has_one => :profile
MikeH
I think the big question is: How is the app jumping to the "create" method? The flash notice is showing the confirmation message that is only associated with the "create" method in my controller. So somehow I'm jumping from the "edit" method to the "create" method when it should clearly be going from the "edit" method to the "update" method. I just don't get it.
MikeH
+1  A: 
form_for :profile, @profile, :html => { :method => :put } do |f|

You need to make sure you use the put method to trigger an update.

railsninja
When I make this change, submitting the update throws the following exception: ActionController::MethodNotAllowed (Only get requests are allowed.):
MikeH
A: 

Hey did you get this working? I am trying to do almost the same thing and having problems. That is how to link users to their individual profiles.

If you got this working, please do post your profiles, user and index/show/edit/new views for the profiles. Thanks

Innocuous