2

Hi guys I am new to rails. Sorry if I can't define this question properly.

What I wanted is for:

domain.com/posts/1-sample-post

to be routed like this:

domain.com/1-sample-post

How do I achieve this in rails routes? I've tried searching for this for almost 3 hours. This is very easy in PHP frameworks. I thought this is easy in Rails too.

I forgot to mention I have High_voltage gem installed in my app for my static pages.

Did this:

#routes.rb
resources :posts
get '/:id' => 'posts#show'

Now my High_voltage pages could not be rendered.

Update Solution:

So here is what we did in the routes:

Rails.application.routes.draw do
  resources :authors
  constraints(lambda { |req| Author.exists?(slug: req.params["id"]) }) do
     get '/:id' => 'authors#show'
  end

  devise_for :users

  resources :posts
  constraints(lambda { |req| Post.exists?(slug: req.params["id"]) }) do
    get '/:id' => 'posts#show'
  end
end

Note that it is important to only use an exists? query here as it is very fast than other methods, so it won't eat that much loading time to render a record.

Special thanks to the guys below who helped a lot. Nathanvda, rwold, and Tai.

Ricardo Green
  • 1,058
  • 1
  • 11
  • 27

2 Answers2

1

So the other answer correctly suggested something like

get '/:id', to: 'posts#show'

But this is a catch-all route and if there are no other routes defined this will catch all routes, also your HighVoltage, if it is configured to serve pages on root. You now have two catch-alls: one to find a static page and one to find a post.

Best solution in this case, imho is to make the static pages explicit (since I am assuming there will not be that many?)

get '/about' => 'high_voltage/pages#show', id: 'about'
get '/:id' => 'posts#show'

If you have a lot of pages, it seems easiest to just present the high-voltage on a different route? E.g. something like

get '/pages/:id' => 'high_voltage/pages#show' 
get '/:id' => 'posts#show' 

In both of these cases, since we use explicit routing, you would have to disable the default routing in the high-voltage initializer:

# config/initializers/high_voltage.rb
HighVoltage.configure do |config|
  config.routes = false
end

[UPDATE: add special controller to consider both posts and pages]

Add a HomeController like this:

class HomeController < ApplicationController

  # include the HighVoltage behaviour --which we will partly overwrite 
  include HighVoltage::StaticPage    

  def show
    # try to find a post first 
    @post = Post.where(id: params[:id).first 
    if @post.present? 
      render 'posts/show'
    else 
      # just do the high-voltage thing
      render(
        template: current_page,
        locals: { current_page: current_page },
      )
    end 
  end 
end 

Of course I did not test this code, but I think this should get you started. Instead of doing the rendering of the post, you could also redirect to the posts-controller which is maybe easier (and you will use the PostsController fully) but adds a redirect and will change the url.

In your routing you will then have to write

get '/:id', 'home#show'   
nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • Thanks for this answer @nathanvda. Unfortunately the project requires that both dynamic and static pages from High_voltage be rendered from the first segment of the url. We do have numerous static pages and moving high-voltage to a separate route is not accepted by the boss. – Ricardo Green Feb 13 '18 at 10:41
  • 1
    Then you will have to write your own home-controller me thinks, that will first look up a page and then look up a post (or vice-versa). That is not too hard at all. Does that make sense or do you need an example how to solve this? – nathanvda Feb 13 '18 at 11:17
  • Sorry for my being a newbie but please add an example, I'd really appreciate this. I just cant conceptualize how this would solved this problem. Sorry If I'm asking for more time from you sir. – Ricardo Green Feb 13 '18 at 11:22
  • 1
    I added an example, without testing, but which should work (hopefully). It will first try to find the post and render it, and otherwise does what high voltage normally does. – nathanvda Feb 13 '18 at 11:50
  • 1
    Thanks for this @nathanvda. This is sort of similar to the solution our team went for, except instead of creating an extra Controller where the checking if the Post exists is done, the checking is done in the routes.rb file. Like this: `constraints(lambda { |req| Post.exists?(req.params["id"]) }) do get '/:id' => 'posts#show', as: :article end`. So technically this is the closest answer. Thank you very much! – Ricardo Green Feb 14 '18 at 02:48
  • 1
    You should answer your own question because that is indeed an excellent way which I forgot to think off (even though I have used it before, doh!) – nathanvda Feb 14 '18 at 06:44
0

In your routes.rb file:

get '/:id-sample-post', to: 'posts#show', as: :sample_post

assuming that posts is your controller and show is the action that calls the view for your article with the given id.

EDIT AFTER OP COMMENT: The as: :sample_post clause should create a helper sample_post_path that can be invoked as <%= link_to "Show", sample_post %>.

rwold
  • 2,216
  • 1
  • 14
  • 22
  • Ok, it's not obvious what's going wrong here. Could you post 1) your entire routes.rb file 2)The file `config/initializers/high_voltage.rb`. 3) Some sort of example of how you're trying to access a static page, including the route you're calling and the directory path of your static pages? – rwold Feb 13 '18 at 10:14
  • Sorry I am not clear in describing this. I wanted this: `<%= link_to 'Show', post %>` to render a link to `domain.com/1-sample-post` instead of the default which is this: `domain.com/posts/1-sample-post`. – Ricardo Green Feb 13 '18 at 10:29
  • How do I that, the should create a helper part? – Ricardo Green Feb 13 '18 at 10:48
  • Just like I wrote in the post, you don't need to do anything more. I said "should" because I haven't tested if that works! – rwold Feb 13 '18 at 10:49
  • Okay thanks. I just thought I should ask cause it feels like its the last thing I need to know now to solve this problem, I'm very new to Rails and I don't know how to do that. Anyways thanks. – Ricardo Green Feb 13 '18 at 10:53
  • Ok, let me know if it works. To weigh in on your discussion with @nathanvda, you changed the route path from `/:id-sample-post` to `:id` in your post. I think he's absolutely right that this change could be what's breaking your static pages. – rwold Feb 13 '18 at 10:59