Rails 4: ActiveRecord::RecordNotFound 在 PostsController#edit

Rails 4: ActiveRecord::RecordNotFound in PostsController#edit

这是一个基本错误,很多人都问过类似的问题,例如:

然而,其中 none 确实帮助我解决了我现在面临的问题。

在我的 Rails 4 应用程序中,我有四个模型:

class User < ActiveRecord::Base
  has_many :administrations
  has_many :calendars, through: :administrations
end

class Calendar < ActiveRecord::Base
  has_many :administrations
  has_many :users, through: :administrations
  has_many: :posts
end

class Administration < ActiveRecord::Base
  belongs_to :user
  belongs_to :calendar
end

class Post < ActiveRecord::Base
  belongs_to :calendar
end

这是我的路线:

Rails.application.routes.draw do

  root to: 'pages#home'

  devise_for :users, :path => 'account'

  resources :calendars do
    resources :posts, shallow: true
  end

end

问题是:当我在日历上时,例如 http://localhost:3000/calendars/11,我显示了属于该日历的所有 post,ShowEditDestroy link 与每个 post.

当我单击 Edit link 时,我被带到 http://localhost:3000/posts/11/edit.5* 并且出现以下错误:

ActiveRecord::RecordNotFound in PostsController#edit
Couldn't find Post with 'id'=11

# Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = Post.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.

注意:我不知道为什么我总是得到这个奇怪的 url,最后是 .5

这是我的PostsController内容:

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all
  end

  # GET /posts/1
  # GET /posts/1.json
  def show
  end

  # GET /posts/new
  def new
    @post = Post.new
  end

  # GET /posts/1/edit
  def edit
    @calendar = Calendar.find(params[:calendar_id])
  end

  # POST /posts
  # POST /posts.json
  def create
    @calendar = Calendar.find(params[:calendar_id])
    @post = @calendar.posts.create(post_params)

    respond_to do |format|
      if @post.save
        format.html { redirect_to calendar_path(@calendar), notice: 'Post was successfully created.' }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /posts/1
  # PATCH/PUT /posts/1.json
  def update
    @calendar = Calendar.find(params[:calendar_id])
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to calendar_path(@calendar), notice: 'Post was successfully updated.' }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /posts/1
  # DELETE /posts/1.json
  def destroy
    @calendar = Calendar.find(params[:calendar_id])
    @post.destroy
    respond_to do |format|
      format.html { redirect_to calendar_path(@calendar), notice: 'Post was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = Post.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def post_params
      params.require(:post).permit(:date, :time, :subject, :format, :copy, :media)
    end
end

更新:根据@Nathan 的评论,这里是 edit.html.erb 视图:

<h1>Editing Post</h1>

<%= render 'form' %>

<%= link_to 'Show', @post %> |
<%= link_to 'Back', posts_path %>

这是其中使用的 _form.html.erb 部分:

<%= form_for(@post) do |f| %>
  <% if @post.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>

      <ul>
      <% @post.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <p>
      <%= f.label :date %><br>
      <%= f.date_select :date %>
    </p>
    <p>
      <%= f.label :time %><br>
      <%= f.time_select :time %>
    </p>
    <p>
      <%= f.label :subject %><br>
      <%= f.text_field :subject %>
    </p>
    <p>
      <%= f.label :format %><br>
      <%= f.text_field :format %>
    </p>
    <p>
      <%= f.label :copy %><br>
      <%= f.text_area :copy %>
    </p>
    <p>
      <%= f.label :media %><br>
      <%= f.text_field :media %>
    </p>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

更新 2:根据@danielricecodes 的回答,这是终端中 运行 rake routes 的结果:

Prefix Verb   URI Pattern                                 Controller#Action
                   posts GET    /posts(.:format)                            posts#index
                         POST   /posts(.:format)                            posts#create
                new_post GET    /posts/new(.:format)                        posts#new
               edit_post GET    /posts/:id/edit(.:format)                   posts#edit
                    post GET    /posts/:id(.:format)                        posts#show
                         PATCH  /posts/:id(.:format)                        posts#update
                         PUT    /posts/:id(.:format)                        posts#update
                         DELETE /posts/:id(.:format)                        posts#destroy
                    root GET    /                                           pages#home
        new_user_session GET    /account/sign_in(.:format)                  devise/sessions#new
            user_session POST   /account/sign_in(.:format)                  devise/sessions#create
    destroy_user_session DELETE /account/sign_out(.:format)                 devise/sessions#destroy
           user_password POST   /account/password(.:format)                 devise/passwords#create
       new_user_password GET    /account/password/new(.:format)             devise/passwords#new
      edit_user_password GET    /account/password/edit(.:format)            devise/passwords#edit
                         PATCH  /account/password(.:format)                 devise/passwords#update
                         PUT    /account/password(.:format)                 devise/passwords#update
cancel_user_registration GET    /account/cancel(.:format)                   devise/registrations#cancel
       user_registration POST   /account(.:format)                          devise/registrations#create
   new_user_registration GET    /account/sign_up(.:format)                  devise/registrations#new
  edit_user_registration GET    /account/edit(.:format)                     devise/registrations#edit
                         PATCH  /account(.:format)                          devise/registrations#update
                         PUT    /account(.:format)                          devise/registrations#update
                         DELETE /account(.:format)                          devise/registrations#destroy
       user_confirmation POST   /account/confirmation(.:format)             devise/confirmations#create
   new_user_confirmation GET    /account/confirmation/new(.:format)         devise/confirmations#new
                         GET    /account/confirmation(.:format)             devise/confirmations#show
             user_unlock POST   /account/unlock(.:format)                   devise/unlocks#create
         new_user_unlock GET    /account/unlock/new(.:format)               devise/unlocks#new
                         GET    /account/unlock(.:format)                   devise/unlocks#show
          calendar_posts GET    /calendars/:calendar_id/posts(.:format)     posts#index
                         POST   /calendars/:calendar_id/posts(.:format)     posts#create
       new_calendar_post GET    /calendars/:calendar_id/posts/new(.:format) posts#new
                         GET    /posts/:id/edit(.:format)                   posts#edit
                         GET    /posts/:id(.:format)                        posts#show
                         PATCH  /posts/:id(.:format)                        posts#update
                         PUT    /posts/:id(.:format)                        posts#update
                         DELETE /posts/:id(.:format)                        posts#destroy
               calendars GET    /calendars(.:format)                        calendars#index
                         POST   /calendars(.:format)                        calendars#create
            new_calendar GET    /calendars/new(.:format)                    calendars#new
           edit_calendar GET    /calendars/:id/edit(.:format)               calendars#edit
                calendar GET    /calendars/:id(.:format)                    calendars#show
                         PATCH  /calendars/:id(.:format)                    calendars#update
                         PUT    /calendars/:id(.:format)                    calendars#update
                         DELETE /calendars/:id(.:format)                    calendars#destroy

更新 3:根据@Nathan 的第二条评论,这是我的 show.html.erb 日历视图的内容:

<h2><%= @calendar.name %> Calendar</h2>

<h3>Posts</h3>
<% if @calendar.posts.any? %>
    <table>
        <tr>
            <th>Date</th>
            <th>Time</th>
            <th>Subject</th>
            <th>Format</th>
            <th>Copy</th>
            <th>Media</th>
        </tr>
  <% @calendar.posts.each do |post| %>
        <tr>
        <td><%= post.date %></td>
            <td><%= post.time %></td>
            <td><%= post.subject %></td>
            <td><%= post.format %></td>
            <td><%= post.copy %></td>
            <td><%= post.media %></td>
        <td><%= link_to 'View', post %></td>
        <td><%= link_to 'Update', edit_post_path(@calendar, post) %></td>
        <td><%= link_to 'Delete', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        </tr>
    </table>
  <% end %>
<% else %>
<p>This calendar does not contain any post yet: just create one with the form below.</p>
<% end %>

<h3>Add a post to <%= @calendar.name %> Calendar:</h3>
<%= form_for([@calendar, @calendar.posts.build]) do |f| %>
  <p>
    <%= f.label :date %><br>
    <%= f.date_select :date %>
  </p>
  <p>
    <%= f.label :time %><br>
    <%= f.time_select :time %>
  </p>
  <p>
    <%= f.label :subject %><br>
    <%= f.text_field :subject %>
  </p>
  <p>
    <%= f.label :format %><br>
    <%= f.text_field :format %>
  </p>
  <p>
    <%= f.label :copy %><br>
    <%= f.text_area :copy %>
  </p>
  <p>
    <%= f.label :media %><br>
    <%= f.text_field :media %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>


<%= link_to 'Edit', edit_calendar_path %> |
<%= link_to 'Back', calendars_path %>

更新 4:这是我从 post 资源中删除浅选项时的路线:

Prefix Verb   URI Pattern                                 Controller#Action
                   posts GET    /posts(.:format)                            posts#index
                         POST   /posts(.:format)                            posts#create
                new_post GET    /posts/new(.:format)                        posts#new
               edit_post GET    /posts/:id/edit(.:format)                   posts#edit
                    post GET    /posts/:id(.:format)                        posts#show
                         PATCH  /posts/:id(.:format)                        posts#update
                         PUT    /posts/:id(.:format)                        posts#update
                         DELETE /posts/:id(.:format)                        posts#destroy
                    root GET    /                                           pages#home
        new_user_session GET    /account/sign_in(.:format)                  devise/sessions#new
            user_session POST   /account/sign_in(.:format)                  devise/sessions#create
    destroy_user_session DELETE /account/sign_out(.:format)                 devise/sessions#destroy
           user_password POST   /account/password(.:format)                 devise/passwords#create
       new_user_password GET    /account/password/new(.:format)             devise/passwords#new
      edit_user_password GET    /account/password/edit(.:format)            devise/passwords#edit
                         PATCH  /account/password(.:format)                 devise/passwords#update
                         PUT    /account/password(.:format)                 devise/passwords#update
cancel_user_registration GET    /account/cancel(.:format)                   devise/registrations#cancel
       user_registration POST   /account(.:format)                          devise/registrations#create
   new_user_registration GET    /account/sign_up(.:format)                  devise/registrations#new
  edit_user_registration GET    /account/edit(.:format)                     devise/registrations#edit
                         PATCH  /account(.:format)                          devise/registrations#update
                         PUT    /account(.:format)                          devise/registrations#update
                         DELETE /account(.:format)                          devise/registrations#destroy
       user_confirmation POST   /account/confirmation(.:format)             devise/confirmations#create
   new_user_confirmation GET    /account/confirmation/new(.:format)         devise/confirmations#new
                         GET    /account/confirmation(.:format)             devise/confirmations#show
             user_unlock POST   /account/unlock(.:format)                   devise/unlocks#create
         new_user_unlock GET    /account/unlock/new(.:format)               devise/unlocks#new
                         GET    /account/unlock(.:format)                   devise/unlocks#show
          calendar_posts GET    /calendars/:calendar_id/posts(.:format)     posts#index
                         POST   /calendars/:calendar_id/posts(.:format)     posts#create
       new_calendar_post GET    /calendars/:calendar_id/posts/new(.:format) posts#new
                         GET    /posts/:id/edit(.:format)                   posts#edit
                         GET    /posts/:id(.:format)                        posts#show
                         PATCH  /posts/:id(.:format)                        posts#update
                         PUT    /posts/:id(.:format)                        posts#update
                         DELETE /posts/:id(.:format)                        posts#destroy
               calendars GET    /calendars(.:format)                        calendars#index
                         POST   /calendars(.:format)                        calendars#create
            new_calendar GET    /calendars/new(.:format)                    calendars#new
           edit_calendar GET    /calendars/:id/edit(.:format)               calendars#edit
                calendar GET    /calendars/:id(.:format)                    calendars#show
                         PATCH  /calendars/:id(.:format)                    calendars#update
                         PUT    /calendars/:id(.:format)                    calendars#update
                         DELETE /calendars/:id(.:format)                    calendars#destroy
MacBook-Pro-de-Thibaud:calendy TXC$ rake routes
                  Prefix Verb   URI Pattern                                      Controller#Action
                    root GET    /                                                pages#home
        new_user_session GET    /account/sign_in(.:format)                       devise/sessions#new
            user_session POST   /account/sign_in(.:format)                       devise/sessions#create
    destroy_user_session DELETE /account/sign_out(.:format)                      devise/sessions#destroy
           user_password POST   /account/password(.:format)                      devise/passwords#create
       new_user_password GET    /account/password/new(.:format)                  devise/passwords#new
      edit_user_password GET    /account/password/edit(.:format)                 devise/passwords#edit
                         PATCH  /account/password(.:format)                      devise/passwords#update
                         PUT    /account/password(.:format)                      devise/passwords#update
cancel_user_registration GET    /account/cancel(.:format)                        devise/registrations#cancel
       user_registration POST   /account(.:format)                               devise/registrations#create
   new_user_registration GET    /account/sign_up(.:format)                       devise/registrations#new
  edit_user_registration GET    /account/edit(.:format)                          devise/registrations#edit
                         PATCH  /account(.:format)                               devise/registrations#update
                         PUT    /account(.:format)                               devise/registrations#update
                         DELETE /account(.:format)                               devise/registrations#destroy
       user_confirmation POST   /account/confirmation(.:format)                  devise/confirmations#create
   new_user_confirmation GET    /account/confirmation/new(.:format)              devise/confirmations#new
                         GET    /account/confirmation(.:format)                  devise/confirmations#show
             user_unlock POST   /account/unlock(.:format)                        devise/unlocks#create
         new_user_unlock GET    /account/unlock/new(.:format)                    devise/unlocks#new
                         GET    /account/unlock(.:format)                        devise/unlocks#show
          calendar_posts GET    /calendars/:calendar_id/posts(.:format)          posts#index
                         POST   /calendars/:calendar_id/posts(.:format)          posts#create
       new_calendar_post GET    /calendars/:calendar_id/posts/new(.:format)      posts#new
      edit_calendar_post GET    /calendars/:calendar_id/posts/:id/edit(.:format) posts#edit
           calendar_post GET    /calendars/:calendar_id/posts/:id(.:format)      posts#show
                         PATCH  /calendars/:calendar_id/posts/:id(.:format)      posts#update
                         PUT    /calendars/:calendar_id/posts/:id(.:format)      posts#update
                         DELETE /calendars/:calendar_id/posts/:id(.:format)      posts#destroy
               calendars GET    /calendars(.:format)                             calendars#index
                         POST   /calendars(.:format)                             calendars#create
            new_calendar GET    /calendars/new(.:format)                         calendars#new
           edit_calendar GET    /calendars/:id/edit(.:format)                    calendars#edit
                calendar GET    /calendars/:id(.:format)                         calendars#show
                         PATCH  /calendars/:id(.:format)                         calendars#update
                         PUT    /calendars/:id(.:format)                         calendars#update
                         DELETE /calendars/:id(.:format)                         calendars#destroy

知道如何解决这个问题吗?

这个错误让我认为您在视图模板中构建的 link 存在问题。我会提供更多帮助,但我没有看到视图文件或 rake routes 的输出。没有这两件事,我很难告诉你为什么你的应用程序会生成一个有趣的 url - 但它通常意味着视图模板没有调用正确的 url_helper。

他的问题与 edit_post_path 有关。对于浅嵌套,编辑路由在父范围之外。 .5 是添加到 url 的 Post ID,但不是有效的 url 参数,因为日历中已经有一个 ID 参数。根据您的路线设置方式,您似乎需要在 link 中将 id 设置为参数,如下所示:

link_to "edit post", edit_post_path(post)

正在为需要一个参数的命名路径 (edit_post) 传递两个参数。当控制器操作 set_post 试图确定在查找要设置为 @post 的记录时使用哪个 :id 时,这会导致问题。

这也是为什么您将 .5 神秘地附加到 URL 末尾的原因 — 我相信 5post:id(在这种情况下),11@calendar:id

edit_post_path 只需要知道你要编辑的 post 的 :id,所以你可以通过将 <%= link_to 'Update', edit_post_path(@calendar, post) %> 更改为 <%= link_to 'Update', edit_post_path(post) %> 来解决这个问题(注意删除了 @calendar.

如果您确实想要将此post编辑为嵌套在日历下的资源(在路径/calendars/<calendar_id>/posts/<post_id>/edit),请查看您的config/routes.rbshallow: true 选项(您在 :calendars 下嵌套 :posts 时使用的)是阻止创建嵌套 :edit 路径的原因。

您需要提供嵌套的 :edit 路径,然后您可以像现在一样传递两个参数(类似于 edit_calendar_post_path(@calendar, post))。