ruby-on-rails - namespace - routes rails examples
/ YYYY/MM/Estructura de URL de Title-Slug con Friendly_Id Solution Chokes en#edit (1)
De acuerdo con la orientación que recibí en mi pregunta anterior al resolver mi problema original para implementar la estructura de URL YYYY / MM / Slug , espero obtener ayuda para resolver un error que recibo al intentar editar una publicación:
Ninguna ruta coincide con [PATCH] "/ blog / 2015/09 / example-post / blog / 2015/09 / example-post"
Aquí están todos los archivos en cuestión (trabajando en el mismo blog andamiado muy simple):
$ 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 ''/:year/:month/: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(@post.year, @post.month, @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_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
def edit_post_path(post)
"#{post.year}/#{post.month}/#{post.slug}/edit"
end
end
app / views / posts / 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_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 %>
En resumen, esto es lo que funciona:
- / blog / index
- / blog / 2015/09 / example-post
- Creando una nueva publicación
- Destruyendo una publicación
... Lo que no funciona:
- Editar una publicación (se procesará la página de edición con el formulario, pero después de enviar los cambios obtendrá el error antes mencionado y los cambios nunca llegarán a la base de datos)
Reconozco que este problema de duplicación probablemente recae en esta modificación de edit_post_path, pero los siguientes intentos de forzar la ruta PATCH correcta no tienen ningún efecto:
- Actualice la ruta PATCH al
patch ''/:year/:month/:id'', to: ''posts#update''
Asigne un nombre a la ruta PATCH actualizada
as: ''patch''
y agregue la ruta de acceso PATCH a posts_helper:def patch_path(post) "#{post.year}/#{post.month}/#{post.slug}" end
Cambiar la anulación a:
def patch_path(post) "" end
- Des-nombre y cambie la ruta PATCH al
patch '''', to: ''posts#update''
Al mirar el controlador posts_controller, no parece que el problema esté allí, ya que no es la redirección el problema, y no veo por qué @post.update(post_params)
sería problemático:
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
Así que, por lo que puedo decir, la duplicación en la URL está ocurriendo antes de la acción PATCH, lo que nos lleva de regreso al flujo de EDITAR - debe estar pasando la duplicación a PATCH donde termina estrangulándose. Ideas? ¡Gracias por adelantado!
EDITAR
edit.html.erb
<h1>Editing Post</h1>
<%= render ''form'' %>
<%= link_to ''Show'', @post %> |
<%= link_to ''Back'', posts_path %>
_form.html.erb
<%= form_for(@post) do |f| %>
<% if @post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@post.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% @post.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :title %><br>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.label :content %><br>
<%= f.text_field :content %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Parece que el problema principal está en el ayudante. Las rutas devueltas deben comenzar con una barra inclinada:
module PostsHelper
def post_path(post)
"/blog/#{post.year}/#{post.month}/#{post.slug}"
end
def edit_post_path(post)
"/blog/#{post.year}/#{post.month}/#{post.slug}/edit"
end
end
Sin la barra diagonal inicial, el navegador los trata como rutas relativas, virando hacia la ruta actual (por lo que termina con /blog/2015/09/example-post/blog/2015/09/example-post
al enviar la editar formulario).
También necesitarás asegurarte de que tus rutas de patch
y de envío sean consistentes:
get ''/:year/:month/:id'', to: ''posts#show'', as: ''post''
patch ''/:year/:month/:id'', to: ''posts#update''
put ''/:year/:month/:id'', to: ''posts#update''
delete ''/:year/:month/:id'', to: ''posts#destroy''
Y, por último, el controlador debe incluir PostsHelper
y utilizar sus métodos para redirigir las URL en la create
y update
:
class PostsController < ApplicationController
include PostsHelper
...
def create
@post = Post.new(post_params)
respond_to do |format|
if @post.save
format.html { redirect_to post_path(@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_path(@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
...
end