一旦我实现了friendly_id,我如何让所有动作都能很好地发挥作用?

时间:2014-09-02 09:51:58

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

我已在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

这里发生了一些事情。

检查旧版网址并执行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。每当我尝试创建子帖子时,请使用与此类似的网址: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行是new中的PostsController动作......即:

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

这两个问题都与friendly_id实施相关联。

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

1 个答案:

答案 0 :(得分:1)

<强> Friendly_id

首先,你必须意识到friendly_id并不是一件大事。

它适用于changing your .find ActiveRecord method,并且您可以将路线助手与slugs一起使用。

这意味着您所拥有的任何混淆都不应该与friendly_id有关 - 如果有任何问题,应该更多地处理您的系统(如果您设置正确,那么friendly_id不应该包含任何内容)你的电话等)


<强>修正

您需要考虑几个问题:

  
      
  1. 重定向
  2.   
  3. ID
  4.   

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

我相信我之前回答了一个问题 - 你需要处理应用程序 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参数或任何内容。它只会ping你的数据库idslug - 没什么大不了的。

你大量过度复杂 - 你只需要将/posts/***重定向到/:id(无论如何都会转到posts控制器)。这样,您的:id仍然会以与没有 friendly_id集成

相同的方式处理