使用 Friendly_Id 实现 /YYYY/MM/Title-Slug URL 结构
Implementing /YYYY/MM/Title-Slug URL structure with Friendly_Id
我真的希望有人能帮助 Rails n00b 解决这个问题。在过去的几天里,我一直在研究、尝试、崩溃(-和-燃烧)如何为我正在整理的博客实施标准 /YYYY/MM/Title-Slug URL 结构。我已经发现并成功实施了 Friendly_Id 来处理 sluggification(以及历史记录跟踪),但对于我来说,我无法解决路由问题的 Year/Month 部分。
在我忘记之前:我正在使用 Rails 4.2.3 和 Ruby 2.2.1p85(因为,是的,我利用了 RailsTutorial.org 中的一堆东西):- )
为了最大程度地减少混淆(或附带损害),我搭建了一个超级简单的博客应用程序以尝试使其全部正常运行:
$ 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
对 post.rb 进行了以下更改:
class Post < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
def year
created_at.localtime.year
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.order('created_at DESC').all
end
def show
end
def new
@post = Post.new
end
def edit
end
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to @post, 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, 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
def set_post
@post = Post.friendly.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content, :published_at, :slug)
end
end
index.html.erb
<p id="notice"><%= notice %></p>
<h1>Listing Posts</h1>
<table>
<thead>
<tr>
<th>Title</th>
<th>Content</th>
<th>Slug</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
<td><%= post.slug %></td>
<td><%= link_to 'Show', post_date_path(post) %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Post', new_post_path %>
routes.rb:
Rails.application.routes.draw do
get '/posts', to: 'posts#index', as: :posts_path
get '/posts/:year', to: 'posts#index', as: :posts_year,
constraints: { year: /\d{4}/ }
get '/posts/:year/:month', to: 'posts#index', as: :posts_month,
constraints: { year: /\d{4}/, month: /\d{1,2}/ }
get '/posts/:year/:month/:slug', to: 'posts#show', as: :post_date,
constraints: { year: /\d{4}/, month: /\d{1,2}/, slug: /[a-z0-9\-]+/ }
resources :posts
end
这些更改主要来自更新此 Whosebug Q&A 中的 Rails3 代码,因为这让我从我发现的其他选项中脱颖而出。我目前 运行 遇到以下控制器异常:
Showing […]/app/views/posts/index.html.erb where line #24 raised:
No route matches {:action=>"show", :controller=>"posts", :month=>nil, :slug=>nil, :year=>#<Post id: 23, title: "test", content: "", slug: "test-4", created_at: "2015-09-01 21:05:48", updated_at: "2015-09-01 21:05:48">} missing required keys: [:month, :slug, :year]
其他以其他稍微令人心碎的方式失败的解决方案:
- "Rails 4 Blog /:year/:month/:title with clean routing"(参见 link 的注释)- 这似乎不起作用,因为 4.1.2 bug that appears to never having been fixed)
- "Rails 4.1.2 - to_param escapes slashes (and breaks app)"(请参阅 link 的评论)- 这可能有效,但我无法出于我的目的翻译答案
- "Friendly_Id slugs with ids or dates separated by slashes"(查看 link 的评论)
需要说明的是:我并不拘泥于这种方法——我非常乐意采用完全不同的方法。我只想让我的最终博客发挥作用:
http://www.example.com/blog/
(为索引)
http://www.example.com/2015/
(对于 2015 posts 的索引)
http://www.example.com/2015/09/
(对于从 2015 年 9 月开始的 post 的索引)
http://www.example.com/2015/09/pleeze-help-me
(个人post)
非常感谢!
编辑
为了解决这个问题,我想知道使用 URL 重写是否是唯一的方法?这个问题的方法。我的直觉说它是在把一个圆钉敲进一个方孔(特别是考虑到博客还没有上线,所以不可能有 link 指向当前 URL 结构),但我找不到更好的选择。
我发现了两个可能有助于重写方法的选项:折射(参见 link 的注释)和机架重写(参见 link 的注释)
有人对这种替代方法有任何意见吗and/or这些插件?
谢谢!
PS - 似乎对 SO 权限进行了更新,现在需要至少 10 个声望到 post 超过 2 links,所以我不得不删除所有links 为了 post 这个编辑。我已将它们移到评论中,以便保存编辑内容。
我有一个部分工作的解决方案,可以在我刚刚创建的 中查看。索引和个别帖子按需要呈现,但我 运行 在创建和编辑帖子时遇到问题,我没有年度索引 e.g., http://www.example.com/2015/
和每月索引 e.g., http://www.example.com/2015/09/
的解决方案。
非常感谢在新问题中解决这些悬而未决的问题!
可以在 的已接受答案中找到完整的工作实现。
我真的希望有人能帮助 Rails n00b 解决这个问题。在过去的几天里,我一直在研究、尝试、崩溃(-和-燃烧)如何为我正在整理的博客实施标准 /YYYY/MM/Title-Slug URL 结构。我已经发现并成功实施了 Friendly_Id 来处理 sluggification(以及历史记录跟踪),但对于我来说,我无法解决路由问题的 Year/Month 部分。
在我忘记之前:我正在使用 Rails 4.2.3 和 Ruby 2.2.1p85(因为,是的,我利用了 RailsTutorial.org 中的一堆东西):- )
为了最大程度地减少混淆(或附带损害),我搭建了一个超级简单的博客应用程序以尝试使其全部正常运行:
$ 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
对 post.rb 进行了以下更改:
class Post < ActiveRecord::Base
extend FriendlyId
friendly_id :title, use: :slugged
def year
created_at.localtime.year
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.order('created_at DESC').all
end
def show
end
def new
@post = Post.new
end
def edit
end
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to @post, 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, 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
def set_post
@post = Post.friendly.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :content, :published_at, :slug)
end
end
index.html.erb
<p id="notice"><%= notice %></p>
<h1>Listing Posts</h1>
<table>
<thead>
<tr>
<th>Title</th>
<th>Content</th>
<th>Slug</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% @posts.each do |post| %>
<tr>
<td><%= post.title %></td>
<td><%= post.content %></td>
<td><%= post.slug %></td>
<td><%= link_to 'Show', post_date_path(post) %></td>
<td><%= link_to 'Edit', edit_post_path(post) %></td>
<td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
<br>
<%= link_to 'New Post', new_post_path %>
routes.rb:
Rails.application.routes.draw do
get '/posts', to: 'posts#index', as: :posts_path
get '/posts/:year', to: 'posts#index', as: :posts_year,
constraints: { year: /\d{4}/ }
get '/posts/:year/:month', to: 'posts#index', as: :posts_month,
constraints: { year: /\d{4}/, month: /\d{1,2}/ }
get '/posts/:year/:month/:slug', to: 'posts#show', as: :post_date,
constraints: { year: /\d{4}/, month: /\d{1,2}/, slug: /[a-z0-9\-]+/ }
resources :posts
end
这些更改主要来自更新此 Whosebug Q&A 中的 Rails3 代码,因为这让我从我发现的其他选项中脱颖而出。我目前 运行 遇到以下控制器异常:
Showing […]/app/views/posts/index.html.erb where line #24 raised:
No route matches {:action=>"show", :controller=>"posts", :month=>nil, :slug=>nil, :year=>#<Post id: 23, title: "test", content: "", slug: "test-4", created_at: "2015-09-01 21:05:48", updated_at: "2015-09-01 21:05:48">} missing required keys: [:month, :slug, :year]
其他以其他稍微令人心碎的方式失败的解决方案:
- "Rails 4 Blog /:year/:month/:title with clean routing"(参见 link 的注释)- 这似乎不起作用,因为 4.1.2 bug that appears to never having been fixed)
- "Rails 4.1.2 - to_param escapes slashes (and breaks app)"(请参阅 link 的评论)- 这可能有效,但我无法出于我的目的翻译答案
- "Friendly_Id slugs with ids or dates separated by slashes"(查看 link 的评论)
需要说明的是:我并不拘泥于这种方法——我非常乐意采用完全不同的方法。我只想让我的最终博客发挥作用:
http://www.example.com/blog/
(为索引)http://www.example.com/2015/
(对于 2015 posts 的索引)http://www.example.com/2015/09/
(对于从 2015 年 9 月开始的 post 的索引)http://www.example.com/2015/09/pleeze-help-me
(个人post)
非常感谢!
编辑
为了解决这个问题,我想知道使用 URL 重写是否是唯一的方法?这个问题的方法。我的直觉说它是在把一个圆钉敲进一个方孔(特别是考虑到博客还没有上线,所以不可能有 link 指向当前 URL 结构),但我找不到更好的选择。
我发现了两个可能有助于重写方法的选项:折射(参见 link 的注释)和机架重写(参见 link 的注释)
有人对这种替代方法有任何意见吗and/or这些插件?
谢谢!
PS - 似乎对 SO 权限进行了更新,现在需要至少 10 个声望到 post 超过 2 links,所以我不得不删除所有links 为了 post 这个编辑。我已将它们移到评论中,以便保存编辑内容。
我有一个部分工作的解决方案,可以在我刚刚创建的 e.g., http://www.example.com/2015/
和每月索引 e.g., http://www.example.com/2015/09/
的解决方案。
非常感谢在新问题中解决这些悬而未决的问题!
可以在