ActiveRecord:: RecordNotFound - Не удалось найти пользователя без ID

Пожалуйста, просмотрите ОБНОВЛЕНИЯ внизу вопроса...

Для справки эта проблема возникла из некоторых исправлений, которые я сделал на основе предыдущей проблемы, которую я имел здесь: Связывание двух моделей в Rails (пользователь и профиль)

Я создаю приложение с моделью пользователя и моделью профиля.

Я хочу связать эти модели так, что:
- После того, как пользователь создал учетную запись, он автоматически отправляется на страницу "создать профиль", а создаваемый им профиль подключается только к определенному пользователю.
- Только пользователь, которому принадлежит профиль, может его редактировать.

Я создал модель пользователя, используя nifty_generators. Когда пользователь нажимает "Отправить" для создания учетной записи, я перенаправляю его на "новый профиль", чтобы создать профиль. Я сделал это, отредактировав путь перенаправления в пользовательском контроллере. Пользовательский контроллер выглядит следующим образом:

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

Когда я нажимаю "submit", чтобы создать нового пользователя, он теперь отправляет меня на следующий URL-адрес, который кажется правильным: localhost: 3000/users/6/profile/new. Но это вызывает следующее исключение:

NoMethodError в ProfilesController # new У вас есть ниль, если вы этого не ожидали! Ошибка при оценке nil.build

Трассировка указывает, что проблема находится в контроллере профилей в методе "Новый". Контроллер профилей выглядит следующим образом:

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

Кроме того, приложение также генерирует исключение, когда я пытаюсь просмотреть страницу индекса профилей (в настоящее время нет профилей, потому что я не могу пройти шаг создания пользователя, чтобы создать его). Это исключение:
ActiveRecord:: RecordNotFound в профиле ProfilesController #
Не удалось найти пользователя без идентификатора

Это то, что говорит мне журнал:

Обработка профилейКонтроллер # index [GET] Параметры: { "Действие" = > "Индекс", "controller" = > "profiles" }

ActiveRecord:: RecordNotFound (не удалось найти пользователя без ID):
приложение/контроллеры/profiles_controller.rb: 5: в `Индекс"

Чтобы предоставить вам остальную информацию о приложении, модели имеют следующие ассоциации:
  Профиль принадлежит _to: пользователь
  Пользователь _one: профиль

У меня это в файле routes.rb: map.resources: users,: has_one = > : profile

В представлении новой страницы профиля, которая бросает первое исключение, указанное выше, у меня есть следующее:

<% form_for([@user, @profile]) do |f| %>
  <%= f.error_messages %>
....
<% end %>  

В представлении для индекса профиля, который бросает второе исключение, описанное выше, у меня есть следующее:

<% @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>

Я потратил часы, пытаясь отследить проблему самостоятельно как упражнение, но на данный момент я понятия не имею, как это исправить. Цените помощь!

ОБНОВЛЕНИЕ:

jdl, по вашему запросу:
profiles/new.html.erb:

<% form_for([@user, @profile]) do |f| %>
  <%= f.error_messages %>



<div class="left">
  <p>
    <%= f.label :name %><br />
    <%= f.text_field :name %>required
  </p>
    <p>
    <%= f.label :category %><br />
    <%= f.text_field :category %>required
  </p>
  <p>
    <%= f.label :address1 %><br />
    <%= f.text_field :address1 %>
  </p>
  <p>
    <%= f.label :address2 %><br />
    <%= f.text_field :address2 %>
  </p>
  <p>
    <%= f.label :city %><br />
    <%= f.text_field :city %>
  </p>
  <p>
    <%= f.label :state %><br />
    <%= f.text_field :state %>
  </p>
  <p>
    <%= f.label :zip %><br />
    <%= f.text_field :zip %>required
  </p>
  <p>
    <%= f.label :phone %><br />
    <%= f.text_field :phone %>
  </p>
  <p>
    <%= f.label :email %><br />
    <%= f.text_field :email %>
  </p>

  </div>

  <div class="right">
  <p>
    <%= f.label :website %><br />
    <%= f.text_field :website %>
  </p>
  <p>
    <%= f.label :description %><br />
    <%= f.text_area :description %>
  </p>
  </div>

  <p>
    <%= f.submit 'Create' %>
  </p>
    <% 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  

КОНТРОЛЛЕР ПРОФИЛЕЙ (по состоянию на 8/20/09, 8 вечера 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, индексная страница ниже бросает следующее исключение:
NoMethodError в профилях # index
Отображение приложения /views/profiles/index.html.erb, где строка # 14 поднята:
undefined метод `name 'для #

    <div id="posts">
<% @users.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>
  </div> 

Ответ 1

Ошибка говорит вам, что в этой строке:

@profile = @user.profile.build

@user.profile - nil.

Поскольку вы еще не создали профиль, это имеет смысл. Вместо этого перейдите к чему-то вроде этого.

@profile = Profile.new(:user_id => @user.id)

Re: страница индекса, генерирующая исключение.

Вы определяете @users в своем контроллере, а затем ссылаетесь на @user в своих помощниках пути. Кроме того, итерация над @users должна давать вам объекты User, а не объекты Profile.

Похоже, вы пытаетесь использовать действие индекса профиля #, чтобы показать список пользователей. Такого рода - ОК, в не совсем чистом виде. Тем не менее, я ожидал бы увидеть нечто подобное.

<% @users.each do |user| -%>
  <% unless user.profile.blank? -%>
    <%= h user.profile.name %>
    <%= h user.profile.category %>
    <%= link_to 'Go to profile', user_profile_path(user, user.profile) %>
  <% end -%>
<% end -%>

Ответ 2

hmm.. Я думал, что когда у пользователя много профилей, вы можете использовать:

@user.profiles.build
@user.profiles.create

когда пользователь имеет один профиль, вы должны использовать:

@user.build_profile
@user.create_profile

Неверно, проверьте API

Ответ 3

@jdl был прав в том, что в профиле ProfilesController # new нет объекта @user.profile, поэтому вызов @user.profile.build выдаст исключение nil.

Вы можете исправить это, создав новый объект Profile с помощью

@user.profile = Profile.new

Позже, если @user будет сохранен, он будет запускать файл @user.profile, и внешние ключи будут установлены соответствующим образом.

Также в вашем ProfilesController действия #index и #show выглядят странно. Обычно действие #index возвращает "список объектов", а #show - отображение только одного объекта, определенного для идентификатора. Однако ваш #index возвращает очень специфический объект, потому что он имеет User.find с определенным идентификатором. Кроме того, поскольку пользователь имеет только один объект профиля, не имеет смысла также загружать свой объект Profile с помощью ORDER BY. Там должен быть только один, поэтому порядок не требуется. Кроме того, его дискуссионный вопрос, нужно ли явно загружать объект профиля, поскольку вы можете просто получить к нему доступ через @user.profile, и ActiveRecord загрузит его по требованию. Итак, ваш новый #index выглядит примерно так:

def index
  @users = User.paginate(:all, :order = "created_at desc", :page => 1, :per_page => 10)
end

Предполагается, что у вас есть плагин WillPaginate, но суть в том, что вы загружаете список объектов, а не только один. На ваш взгляд, если вы выполняете итерацию над @users и вызываете .profile в элементе этого списка, тогда ActiveRecord будет загружать связанный профиль на лету.

То же самое для #show - нет необходимости явно загружать профиль.

def show
  @user = User.find(params[:user_id])
end

Ответ 4

Сделайте одно -

В ProfileController укажите session[:user_id] not params[:user_id]

def show <br>

@user = User.find(session[:user_id])<br>
@profile = @user.profile <br>
end <br>

Надеюсь, это сработает!