shallow rails namespace examples concern ruby-on-rails ruby-on-rails-4 rails-routing

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:

  1. Actualice la ruta PATCH al patch ''/:year/:month/:id'', to: ''posts#update''
  2. 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

  3. Cambiar la anulación a:

    def patch_path(post) "" end

  4. 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