Please see UPDATES at the bottom of the question...
For reference, this problem evolved out of some fixes I made based on a previous problem I was having here: http://stackoverflow.com/questions/1298846/associating-two-models-in-rails-user-and-profile
I'm building an app that has a user model and a profile model.
I want to associate these models such that:
- After the user creates an account, he is automatically sent to the "create profile" page, and the profile he creates is connected to only that particular user.
- Only the user who owns the profile can edit it.
I generated the user model using nifty_generators. When the user hits submit for the account creation, I redirect him to the "new profile" view to create a profile. I did this by editing the redirect path in the user controller. The user controller looks like this:
def new
@user = User.new
end
def create
@user = User.new(params[:user])
if @user.save
session[:user_id] = @user.id
flash[:notice] = "Thank you for signing up! You are now logged in."
redirect_to new_user_profile_path(:user_id => @user)
else
render :action => 'new'
end
end
When I click 'submit' to create a new user, it now sends me to the following url, which seems right: localhost:3000/users/6/profile/new. But it throws the following exception:
NoMethodError in ProfilesController#new
You have a nil object when you didn't expect it!
The error occurred while evaluating nil.build
The trace indicates that the problem is in the profiles controller, in the New method. The profiles controller looks like this:
def index
@user = User.find(params[:user_id])
@profile = @user.profile(:order => "created_at DESC")
end
def show
@user = User.find(params[:user_id])
@profile = @user.profile.find(params[:id])
end
def new
@user = User.find(params[:user_id])
@profile = @user.profile.build
end
def edit
@user = User.find(params[:user_id])
@profile = @user.profile.find(params[:id])
end
def create
@user = User.find(params[:user_id])
@profile = @user.profile.build(params[:profile])
if @profile.save
flash[:notice] = 'Profile was successfully created.'
redirect_to(@profile)
else
flash[:notice] = 'Error. Something went wrong.'
render :action => "new"
end
end
Additionally, the app also throws an exception when I try to view the index page of the profiles (there are currently no profiles because I can't get past the user creation step to create one). This is the exception:
ActiveRecord::RecordNotFound in ProfilesController#index
Couldn't find User without an ID
This is what the log is telling me:
Processing ProfilesController#index [GET]
Parameters: {"action"=>"index", "controller"=>"profiles"}
ActiveRecord::RecordNotFound (Couldn't find User without an ID):
app/controllers/profiles_controller.rb:5:in `index'
To give you the rest of the details on the app, the models have the following associations:
Profile belongs _to :user
User has _one :profile
I have this in the routes.rb file: map.resources :users, :has_one => :profile
In the view for the new profile page that's throwing the first exception listed above, I have this:
<% form_for([@user, @profile]) do |f| %>
<%= f.error_messages %>
....
<% end %>
In the view for the profile index that's throwing the second exception explained above, I have this:
<% @profiles.each do |profile| %>
<div class="post">
<div class="left">
<p>Store: </p>
<p>Category: </p>
</div>
<div class="right">
<p><%=h profile.name %></p>
<p><%=h profile.category %></p>
</div>
<div class="bottom">
<p><%= link_to 'Go to profile', user_profile_path(@user, profile) %></p>
<p><%= link_to 'Edit', edit_user_profile_path(@user, profile) %></p>
<p><%= link_to 'Destroy', user_profile_path(@user, profile), :confirm => 'Are you sure?', :method => :delete %></p>
</div>
<% end %>
I've spent hours trying to track down the problem myself as a learning exercise, but at this point I have no idea how to fix this. Appreciate the help!
UPDATE:
jdl, per your request:
profiles/new.html.erb:
<% form_for([@user, @profile]) do |f| %>
<%= f.error_messages %>
<%= f.label :name %>
<%= f.text_field :name %>required
<%= f.label :category %>
<%= f.text_field :category %>required
<%= f.label :address1 %>
<%= f.text_field :address1 %>
<%= f.label :address2 %>
<%= f.text_field :address2 %>
<%= f.label :city %>
<%= f.text_field :city %>
<%= f.label :state %>
<%= f.text_field :state %>
<%= f.label :zip %>
<%= f.text_field :zip %>required
<%= f.label :phone %>
<%= f.text_field :phone %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :website %>
<%= f.text_field :website %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.submit 'Create' %>
<% end %>routes.rb:
ActionController::Routing::Routes.draw do |map|
map.signup 'signup', :controller => 'users', :action => 'new'
map.logout 'logout', :controller => 'sessions', :action => 'destroy'
map.login 'login', :controller => 'sessions', :action => 'new'
map.resources :sessions
map.resources :users, :has_one => :profile
map.root :controller => "home"
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
end
PROFILES CONTROLLER (as of 8/20/09, 8pm EST)
class ProfilesController < ApplicationController
def index
@users = User.all(:order => "created_at DESC")
end
def show
@user = User.find(params[:user_id])
end
def new
@user.profile = Profile.new
end
def edit
@user = User.find(params[:user_id])
@profile = @user.profile.find(params[:id])
end
def create
@user = User.find(params[:user_id])
@profile = @user.profile.build(params[:profile])
if @profile.save
flash[:notice] = 'Profile was successfully created.'
redirect_to(@profile)
else
flash[:notice] = 'Error. Something went wrong.'
render :action => "new"
end
end
def update
@profile = Profile.find(params[:id])
if @profile.update_attributes(params[:profile])
flash[:notice] = 'Profile was successfully updated.'
redirect_to(@profile)
else
render :action => "edit"
end
end
def destroy
@profile = Profile.find(params[:id])
@profile.destroy
redirect_to(profiles_url)
end
end
Cody, the index page below is throwing the following exception:
NoMethodError in Profiles#index
Showing app/views/profiles/index.html.erb where line #14 raised:
undefined method `name' for #
<div id="posts">
<% @users.each do |profile| %>
Store:
Category:
<%=h profile.name %>
<%=h profile.category %>
<%= link_to 'Go to profile', user_profile_path(@user, profile) %>
<%= link_to 'Edit', edit_user_profile_path(@user, profile) %>
<%= link_to 'Destroy', user_profile_path(@user, profile), :confirm => 'Are you sure?', :method => :delete %>