【问题标题】:Once I implement friendly_id, how do I get all actions to play nicely?一旦我实现了friendly_id,我怎样才能让所有的动作都能很好地发挥作用?
【发布时间】:2014-09-02 09:51:58
【问题描述】:

我已经在我的PostsController 上实现了friendly_id。

这就是我的PostsController 的样子:

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]
  load_and_authorize_resource

  def index
    @posts = Post.all.order("created_at desc")
  end

  def show
  end

  def new
    @post = Post.new(parent_id: params[:parent_id])
  end

  def edit
  end

  def create
    @post = current_user.posts.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])

      # If an old id or a numeric id was used to find the record, then
      # the request path will not match the post_path, and we should do
      # a 301 redirect that uses the current friendly id.

      if request.path != post_path(@post)
          return redirect_to @post, :status => :moved_permanently
      end
    end

    def post_params
      params.require(:post).permit(:status, :title, :photo, :file, :body, :parent_id)
    end
end

这里发生了一些事情。

检查旧 URL 并执行 301 重定向的重定向代码会干扰控制器的其他操作 - 例如edit,可以在这里看到:

      if request.path != post_path(@post)
          return redirect_to @post, :status => :moved_permanently
      end

当我尝试编辑帖子时,会发生以下情况:

Started GET "/pnpyo-saddened-at-passing-of-roger-clarke/edit" for 127.0.0.1 at 2014-09-02 04:46:49 -0500
Processing by PostsController#edit as HTML
  Parameters: {"id"=>"pnpyo-saddened-at-passing-of-roger-clarke"}
  Post Load (1.2ms)  SELECT  "posts".* FROM "posts"  WHERE "posts"."slug" = 'pnpyo-saddened-at-passing-of-roger-clarke'  ORDER BY "posts"."id" ASC LIMIT 1
Redirected to http://localhost:3000/pnpyo-saddened-at-passing-of-roger-clarke
Filter chain halted as :set_post rendered or redirected
Completed 301 Moved Permanently in 13ms (ActiveRecord: 1.2ms)

另外,出现的另一个问题是我安装了ancestry gem。每当我尝试创建子帖子时,使用类似于此的 URL:http://localhost:3000/new?parent_id=pnpyo-saddened-at-passing-of-roger-clarke

这是产生的错误:

Started GET "/new?parent_id=pnpyo-saddened-at-passing-of-roger-clarke" for 127.0.0.1 at 2014-09-02 04:47:52 -0500
Processing by PostsController#new as HTML
  Parameters: {"parent_id"=>"pnpyo-saddened-at-passing-of-roger-clarke"}
  User Load (0.4ms)  SELECT  "users".* FROM "users"  WHERE "users"."id" = 1  ORDER BY "users"."id" ASC LIMIT 1
   (0.4ms)  SELECT COUNT(*) FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))  [["user_id", 1]]
  Post Load (0.3ms)  SELECT  "posts".* FROM "posts"  WHERE "posts"."id" = $1 LIMIT 1  [["id", 0]]
Completed 404 Not Found in 35ms

ActiveRecord::RecordNotFound - Couldn't find Post with 'id'=pnpyo-saddened-at-passing-of-roger-clarke:

() app/controllers/posts_controller.rb:19:in `new'

第 19 行是 PostsController 中的 new 操作...即:

@post = Post.new(parent_id: params[:parent_id])

这两个问题都与friendly_id 实现有关。

如何一劳永逸地解决这两个问题?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 routing friendly-id


    【解决方案1】:

    Friendly_id

    首先,您必须明白friendly_id 并不是什么大不了的事。

    它由changing your .find ActiveRecord method 工作,并让您能够通过slugs 使用路线助手。

    这意味着您的任何困惑都不应该真正与 friendly_id 有关 - 如果有的话,它应该更多地与您的系统有关(如果您正确设置了它,friendly_id 不应该出现在您的任何电话等)


    修复

    您需要考虑几个问题:

    1. 重定向
    2. 身份证

    首先,不要在控制器中处理重定向。

    我相信我之前回答过你一个问题 - 你需要在应用程序的 routes 部分处理重定向。为什么?这就是 路由 发生的地方。

    尝试在控制器中处理重定向违反了MVC principles (IMO) - 您最好按如下方式处理重定向:

    #config/routes.rb
    resources :posts, path: ''
    get 'posts/:id' => redirect("/%{id}")
    
    #get '/:id', to: 'posts#show' -> NOT NEEDED. Will be covered by the resources directive
    #get 'posts/:id', to: 'posts#show' -> NOT NEEDED. Will be covered by redirect
    
    #app/models/post.rb
    class Post < ActiveRecord::Base
       extend FriendlyId
       friendly_id :slug, use: [:slugged, :finders]
    end
    
    #app/controllers/posts_controller.rb
    class PostsController < ApplicationController
       def show
          @post = Post.find params[:id]
       end
    end
    

    这将解决您的所有问题。

    如果您使用friendly_id finders 模块,则不需要区分任何自定义:friendly_id 参数或任何东西。它只会为idslug ping 您的数据库 - 没什么大不了的。

    您过于复杂了-您只需将任何/posts/*** 重定向到/:id(无论如何都会转到posts 控制器)。这样一来,您的 :id 仍将以与 没有 friendly_id 集成的方式相同的方式处理

    【讨论】:

    • 您确实回答了另一个问题...所以谢谢您:) 这确实有效。我没有为:friendly_id 使用:finders 模块,因此这也可能导致常规.find(params[:id]) 不起作用。
    • 我想我注意到的一个有点奇怪的行为是,如果我在我的应用程序中转到post/26/,它不会重定向到friendly_id URL。它只是停留在/26/....而控制器中的旧重定向功能确实将其完全重定向到长URL。我如何通过routes.rb 中的重定向来做到这一点?
    • 重定向是针对/posts/的,对吧?当然,这意味着您最好使用/posts/26
    • 我的意思是,friendly_id 将所有丑陋的 URL(例如 posts/26/ 转换为更多的 SEO 和人类友好的 URL(例如 posts/some-awesome-post-title)。但是,使用当前重定向它不会如果有人输入 /26/,则重定向/屏蔽 URL,它只是停留在 /26/,而不是重定向到 some-awesome-post-title,这是我的 posts_controller 中的那个小 if 方法所做的。换句话说,当前重定向routes.rb 文件并没有完全取代我的控制器中重定向的功能 - 当我想要它时。
    猜你喜欢
    • 1970-01-01
    • 2017-05-20
    • 1970-01-01
    • 2021-09-02
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多