#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路由无效:
- 更新PATCH路由到
patch '/:year/:month/:id', to: 'posts#update'
-
将更新的PATCH路由命名
as: 'patch'
并将POSTCH路径覆盖添加到posts_helper:def patch_path(post) "#{post.year}/#{post.month}/#{post.slug}" end
-
将覆盖更改为:
def patch_path(post) "" end
- 取消名称并更改
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 ...' }