ActiveRecord :: RecordNotFound - не удалось найти пользователя без идентификатора - PullRequest
11 голосов
/ 20 августа 2009

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

Для справки, эта проблема возникла из-за некоторых исправлений, которые я сделал на основе предыдущей проблемы, с которой я столкнулся здесь: Связывание двух моделей в 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

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

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

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

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
Не удалось найти пользователя без идентификатора

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

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

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

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

У меня есть это в файле rout.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, по вашему запросу:
profile / 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 => 'session',: action => 'destroy'
map.login 'login',: controller => 'session',: action => 'new'
map.resources: сеансы

  map.resources :users, :has_one => :profile  

  map.root :controller => "home"   
  map.connect ':controller/:action/:id'  
  map.connect ':controller/:action/:id.:format'  
end  

КОНТРОЛЛЕР ПРОФИЛЕЙ (по состоянию на 20.08.09, 20:00 EST)
Класс ProfilesController

  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

Коди, на индексной странице ниже выдается следующее исключение:
NoMethodError в профилях # index
Отображение app / views / profile / index.html.erb, где поднята строка # 14:
неопределенное имя метода для #

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

Ответы [ 4 ]

5 голосов
/ 20 августа 2009

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

@profile = @user.profile.build

@user.profile - ноль.

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

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

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

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

Похоже, вы пытаетесь использовать действие Profile # index для отображения списка пользователей. Это нормально, не совсем чистый отдых. Тем не менее, я ожидаю увидеть что-то более подобное.

<% @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 -%>
1 голос
/ 21 августа 2009

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

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

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

@user.build_profile
@user.create_profile

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

0 голосов
/ 01 июля 2013

Делай одну вещь

В ProfileController введите session[:user_id], а не params[:user_id]

def show <br>

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

Я надеюсь, что это работает!

0 голосов
/ 20 августа 2009

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

Это можно исправить, создав новый объект профиля с помощью

@user.profile = Profile.new

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

Также в вашем ProfilesController действия #index и #show довольно странные. Условно, действие #index возвращает «список объектов», а #show должен отображать только один объект, конкретный с данным идентификатором. Однако ваш #index возвращает очень специфический объект, потому что он выполняет User.find с определенным идентификатором. Более того, поскольку у пользователя есть только один объект Profile, не имеет смысла загружать его объект 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...