Реализация структуры URL / YYYY / MM / Title-Slug с Friendly_Id
Я действительно надеюсь, что кто-то может помочь этому Rails n00b с этой проблемой. В течение последних нескольких дней я исследовал, пробовал, сбоил (и сжигал) способы реализации стандартной структуры URL-адреса / YYYY / MM / Title-Slug для блога, который я собираю. Я обнаружил и успешно реализовал Friendly_Id для обработки слагалификации (вместе с отслеживанием истории), но на всю жизнь я не могу решить часть года / месяца, связанную с проблемой маршрутизации.
Прежде чем я забыл: я использую 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
Эти изменения в основном связаны с обновлением кода Rails3 из этогоStackoverflow Q & A поскольку это сделало меня самым дальним из всех вариантов, которые я обнаружил. Я в настоящее время сталкиваюсь со следующим исключением контроллера:
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 /: год /: месяц /: заголовок с чистой маршрутизацией» (см. Комментарии для ссылки) - похоже, это не работает из-за4.1.2 ошибка, которая, кажется, никогда не была исправлена)«Rails 4.1.2 - to_param избегает слешей (и разрывает приложение)» (см. Комментарии для ссылки) - это может сработать, но я не смог перевести ответ для своих целей«Слизни Friendly_Id с идентификаторами или датами, разделенными косой чертой» (см. Комментарии для ссылки)Чтобы было ясно: я не предан этому подходу - я более чем счастлив идти совершенно другим путем. Я бы хотел, чтобы мой последний блог функционировал как:
http://www.example.com/blog/
(для индекса)http://www.example.com/2015/
(для индекса 2015 постов)http://www.example.com/2015/09/
(для индекса сообщений с 15 сентября)http://www.example.com/2015/09/pleeze-help-me
(за отдельный пост)Спасибо заранее!
РЕДАКТИРОВАТЬ
В поисках некоторых дополнительных кроличьих ям, чтобы найти решение этой проблемы, мне интересно, будет ли использование перезаписи URL единственным? подход к этому вопросу. У меня интуиция говорит, что он вбивает круглый колышек в квадратную дыру (особенно учитывая, что блог еще не запущен, поэтому нет никаких шансов, что есть дикие ссылки, указывающие на текущую структуру URL), но я не могу найти лучшую альтернативу.
Я нашел два варианта, которые могли бы помочь с подходом перезаписи: рефракция (см. Комментарии для ссылки) и перезапись стойки (см. Комментарии для ссылки)
Есть ли у кого-нибудь мнение об этом альтернативном подходе и / или этих плагинах?
Спасибо!
PS - Похоже, есть обновление для SO-разрешений, которые теперь требуют как минимум 10 репутации, чтобы опубликовать более 2 ссылок, поэтому мне пришлось удалить все ссылки, чтобы опубликовать это редактирование. Я переместил их в комментарии, чтобы сохранить изменения.