marcamillion
marcamillion

Reputation: 33795

How do I capture two routes for a URL generated by friendly_id?

I have setup friendly_id perfectly, and whereas my old URLs used to look like:

/posts/1....now they look like: /posts/article-title-here.

I was able to get rid of the posts in the URL altogether...so that it it just looks like: /article-title-here, by doing this in my routes:

  resources :posts, path: ''
  get '/:friendly_id', to: 'posts#show'

But what I want to happen now is if someone goes to /posts/article-title-here it automatically redirects them to /article-title-here and doesn't throw an error like it does now.

How do I do that?

Update:

This is my 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
    # Use callbacks to share common setup or constraints between actions.
    def set_post
      @post = Post.friendly.find(params[:id])          
    end

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

Update 2:

When I try the suggestion of @rich-peck of this:

  get '/:friendly_id', to: 'posts#show'
  get 'posts/:friendly_id', to: 'posts#show' 
  get '/posts/:id' => redirect("/%{id}")

This is the result:

Started GET "/posts/pnpyo-saddened-at-passing-of-roger-clarke" for 127.0.0.1 at 2014-09-02 02:29:14 -0500
  ActiveRecord::SchemaMigration Load (1.0ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by PostsController#show as HTML
  Parameters: {"friendly_id"=>"pnpyo-saddened-at-passing-of-roger-clarke"}
Completed 404 Not Found in 93ms

ActiveRecord::RecordNotFound - Couldn't find Post without an ID:

Upvotes: 1

Views: 78

Answers (2)

Richard Peck
Richard Peck

Reputation: 76774

Just do this:

#config/routes.rb
resources :posts, path: "" #-> domain.com/:id
get "/posts/:id" => redirect("/%{id}")

You can read up more on redirection here

Updated by OP:

This is what my final routes looks like - that actually works:

  #config/routes.rb
  resources :posts, path: ''
  get 'posts/:id' => redirect("/%{id}")
  get '/:friendly_id', to: 'posts#show'
  get 'posts/:friendly_id', to: 'posts#show' 

It is important that the redirect happens before the friendly_id routes, otherwise this won't work.

Upvotes: 2

Michał Młoźniak
Michał Młoźniak

Reputation: 5556

Set standard resources route:

resources :posts
get '/:friendly_id', to: 'posts#show'

And in controller:

def show
  if request.path.start_with?('/posts')
    redirect_to "/#{params[:id]}"
  end

  # load post
end

Upvotes: 0

Related Questions