Implementando / AAAA / MM / Estructura URL de Título-Slug con Friendly_Id
Realmente espero que alguien pueda ayudar a este Rails n00b con este problema. En los últimos días, he estado investigando, probando, bloqueando (y quemando) cómo implementar la estructura de URL estándar / AAAA / MM / Title-Slug para un blog que estoy armando. He descubierto e implementado con éxito Friendly_Id para manejar la sluggification (junto con el seguimiento del historial), pero por mi vida no puedo resolver la parte Año / Mes del problema de enrutamiento.
Antes de que me olvide: estoy usando Rails 4.2.3 y Ruby 2.2.1p85 (porque sí, aproveché un montón de cosas de RailsTutorial.org) :-)
Para minimizar la confusión (o el daño colateral), he diseñado una aplicación de blog súper simple para intentar que todo funcione:
$ 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
Hizo los siguientes cambios apost.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
Estos cambios se deben principalmente a la actualización del código Rails3 a partir de esteStackoverflow Q&A ya que eso me ha llevado más lejos de otras opciones que he descubierto. Actualmente me encuentro con la siguiente excepción de controlador:
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]
Otras soluciones que han fallado en otras formas un poco desgarradoras:
"Blog de Rails 4 /: año /: mes /: título con enrutamiento limpio" (ver comentarios para el enlace) - esto parece no funcionar debido a un4.1.2 error que parece no haberse solucionado nunca)"Rails 4.1.2 - to_param escapa slashes (y rompe la aplicación)" (ver comentarios para el enlace) - esto puede funcionar, pero no pude traducir la respuesta para mis propósitos"Slugs Friendly_Id con identificadores o fechas separadas por barras" (ver comentarios para el enlace)Para ser claros: no estoy casado con este enfoque, estoy más que feliz de ir por un camino completamente diferente. Solo me gustaría que mi blog final funcione como:
http://www.example.com/blog/
(para el índice)http://www.example.com/2015/
(para un índice de publicaciones de 2015)http://www.example.com/2015/09/
(para un índice de publicaciones del 15 de septiembre)http://www.example.com/2015/09/pleeze-help-me
(para una publicación individual)¡Muchas gracias de antemano!
EDITAR
Al analizar algunos agujeros de conejo adicionales para obtener una solución a esto, me pregunto si usar la reescritura de URL sería la única. enfoque para este tema. Mi instinto dice que está golpeando una clavija redonda en un agujero cuadrado (especialmente dado que el blog aún no está activo, por lo que no hay posibilidad de que haya enlaces en la naturaleza que apuntan a la estructura de URL actual), pero estoy fallando para encontrar una mejor alternativa
He encontrado dos opciones que podrían ayudar con el enfoque de reescritura: refracción (ver comentarios para el enlace) y reescritura en rack (ver comentarios para el enlace)
¿Alguien tiene alguna entrada sobre este enfoque alternativo y / o estos complementos?
¡Gracias!
PD: parece haber una actualización de los permisos SO que ahora requieren al menos 10 reputación para publicar más de 2 enlaces, por lo que tuve que eliminar todos los enlaces para publicar esta edición. Los moví a los comentarios para poder guardar la edición.