#YYYY / MM / Title-Slug URL结构,带有#new和#edit上的Friendly_Id解决方案扼流圈

我对我以前的问题有一个部分解决方案,正确显示post#index和posts#show routes,但在创建post后窒息:

PostsController中的ActionController :: UrlGenerationError #create
没有路由匹配{:action =>“show”,:controller =>“posts”}缺少必需的键:[:id,:month,:year]

提取的来源(第32行):
30 respond_to do | format |
31 if @ post.save
32 format.html {redirect_to post_path,注意:’post已成功创建。’ }
33 format.json {render:show,status :: created,location:@post}
34其他
35 format.html {render:new}

…并编辑post:

没有路由匹配[PATCH]“/ blog / example-post / blog / 2015/09 / example-post”

以下是所有相关文件(使用相同的非常简单的脚手架博客):

$ rails new blog [...] $ cd blog # (Add friendly_id to Gemfile & install) $ rails generate friendly_id $ rails generate scaffold post title content slug:string:uniq [...] $ rake db:migrate 

的routes.rb

 Rails.application.routes.draw do scope 'blog' do get '', to: 'posts#index', as: 'posts' post '', to: 'posts#create' get '/new', to: 'posts#new', as: 'new_post' get '/:id/edit', to: 'posts#edit', as: 'edit_post' get '/:year/:month/:id', to: 'posts#show', as: 'post' patch '/:id', to: 'posts#update' put '/:id', to: 'posts#update' delete '/:year/:month/:id', to: 'posts#destroy' end end 

post.rb

 class Post < ActiveRecord::Base extend FriendlyId friendly_id :title, use: :slugged def year created_at.localtime.strftime("%Y") end def month created_at.localtime.strftime("%m") end end 

posts_controller.rb

 class PostsController < ApplicationController before_action :set_post, only: [:show, :edit, :update, :destroy] def index @posts = Post.all end def show @post = Post.friendly.find(params[:id]) end def new @post = Post.new end def edit @post = Post.friendly.find(params[:id]) end def create @post = Post.new(post_params) respond_to do |format| if @post.save format.html { redirect_to post_path, 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 def update respond_to do |format| if @post.update(post_params) format.html { redirect_to post_path, 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 def destroy @post.destroy respond_to do |format| format.html { redirect_to posts_url, 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.friendly.find(params[:id]) end # Never trust parameters from the scary internet, only allow the white list through. def post_params params.require(:post).permit(:title, :content, :slug) end end end 

posts_helper.rb

 module PostsHelper def post_path(post) "blog/#{post.year}/#{post.month}/#{post.slug}" end end 

应用程序/视图/职位/ index.html.erb

 

Listing Posts

Title Content Slug

总之,这是有效的:

  • /博客/指数
  • /博客/ 2015/09 /例如,后
  • 创建一个新post(直到它应该重定向到post的位置#显示当你得到上面提到的UrlGenerationError时)
    • 也就是说,新post被添加到数据库中,所以如果你回到/索引新post将是可见的
  • 摧毁一个post

……什么行不通:

  • 编辑post(带有表单的编辑页面将呈现,但在提交更改后,您将收到上述错误 – 并且更改永远不会进入数据库)
  • 创建新post后完成重定向(前面提到过)。
  • /博客/ 2015 /指数
  • /博客/ 2015/09 /指数

我很激动我已经走到了这一步 – 任何解决这些悬而未决的问题的指导都会非常感激!

编辑

感谢@ brad-werth,通过以下更改修复了post创建:

posts_controller.rb

 def create @post = Post.new(post_params) respond_to do |format| if @post.save format.html { redirect_to post_path(@post.year, @post.month, @post), notice: 'Post was successfully created.' } 

我也尝试过以下方式解决post编辑问题:

将编辑路线更改为get '/:year/:month/:id/edit', to: 'posts#edit', as: 'edit_post'并将以下覆盖添加到posts_helper.rb以防止索引页面中断:

  def edit_post_path(post) "#{post.year}/#{post.month}/#{post.slug}/edit" end 

现在,索引页面中的“编辑”链接将转到正确的URL( /blog/2015/09/example-post/edit – 它曾用于/blog/example-post/edit )并成功呈现编辑页。 但这会导致PATCH中断(实际上,更新不会进入数据库):

 No route matches [PATCH] "/blog/2015/09/example-post/blog/2015/09/example-post" 

我认识到这个重复问题可能在于此edit_post_path覆盖,但以下尝试强制正确的PATCH路由无效:

  1. 更新PATCH路由到patch '/:year/:month/:id', to: 'posts#update'
  2. 将更新的PATCH路由命名as: 'patch'并将POSTCH路径覆盖添加到posts_helper:

     def patch_path(post) "#{post.year}/#{post.month}/#{post.slug}" end 
  3. 将覆盖更改为:

     def patch_path(post) "" end 
  4. 取消名称并更改patch '', to: 'posts#update' PATCH路线patch '', to: 'posts#update'

看看posts_controller,它看起来不像问题,因为它不是重定向不是问题 – 我不明白为什么@post.update(post_params)会有问题:

  def update respond_to do |format| if @post.update(post_params) format.html { redirect_to @post, 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 

因此,据我所知,在PATCH操作之前,URL中的重复发生了,这将我们带回到编辑流程 – 它必须将复制传递给PATCH,在那里它会结束窒息。 想法?

您的错误说明:

No route matches {:action=>"show", :controller=>"posts"} missing required keys: [:id, :month, :year]

正如您从失败的行中看到的format.html { redirect_to post_path, notice: 'Post was successfully created.' } 你正在调用没有参数的post_path

你的路线get '/:year/:month/:id', to: 'posts#show', as: 'post'需要一年,一个月和一个id。 这与您上面的错误消息一致。

要修复,只需提供缺少的参数,如下所示:

format.html { redirect_to post_path(@post.year, @post.month, @post), notice: 'Post was successfully created.' }

在更新和创建操作更改:

 format.html { redirect_to post_path, notice: 'Post was successfully ...' } 

 format.html { redirect_to @post, notice: 'Post was successfully ...' }