Rails: Remove Controller from URL - ruby-on-rails

I've read a couple of posts, but I haven't found a clear solution.
I want to remove the controller from the URL. I'm getting this:
localhost:3000/pages/services
But I want this:
localhost:3000/services
This is my routes file right now:
Rails.application.routes.draw do
root 'pages#index'
get 'pages/services'
get 'pages/specials'
get 'pages/events'
get 'pages/about'
end
I suspect that I need to do something here, but I haven't been able to find a decent tutorial. Any suggestions?

Try this:
match 'services' => "pages#services", :as => :services
You can specify a name for any route using the :as option.
See here

I would just replace it with this:
Rails.application.routes.draw do
root '#index'
end

Related

Route Controller#show method like how Controller#index would in Rails

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.
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'
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 %>.

creating custom routes in rails

I am creating a custom route like:
namespace :admin do
root 'users#index'
resources :users do
get 'admin_login' => 'users#admin_login'
end
end
But when I see with rake routes:
admin_user_admin_login GET /admin/users/:user_id/admin_login(.:format) admin/users#admin_login
Why :user_id is added here?
I just want it without :user_id.
Because you are creating a custom route within the users resource. Rails is doing exactly what you are telling it to do. You would like to show the "admin_login" route for a specified user (that's what you're currently telling rails to do).
Move the:
get 'admin_login' => 'users#admin_login'
Line of code outside of the resources block and you'll be able to create your custom route.
You need to specify an on option to tell Rails that it works on a collection and not a member resource. According to the official Rails routing guide
You can leave out the :on option, this will create the same member
route except that the resource id value will be available in
params[:photo_id] instead of params[:id].
You can also remove the => 'users#admin_login' part as that is the default behavior.
So the solution to your problem is to add on: :collection or place it inside a block like
namespace :admin do
root 'users#index'
resources :users do
collection do
get 'admin_login'
end
end
end

How can I define multiple url helpers for same route entry in Rails?

I am working on Rails 4.
I have the following entry in my routes:
get 'dashboard', as: :dashboard, to: "dashboard#index"
which generates for me the url helpers: dashboard_path and dashboard_url
How can I define extra url helpers for same route? I would like to have, for example, the url helpers: signed_in_defalt_path and signed_in_default_url (in addition to the ones with dashboard prefix).
So, I would like to be able to do something like that:
get 'dashboard', as: [:dashboard, :signed_in_default], to: "dashboard#index"
but obviously this does not work.
Any clue what might be the best approach on this problem?
#kunashir is mentioning the right thing -
if its necessary to have one route available through more named routes you need to define them individually.
But it can be DRY as follows:
[:dashboard, :signed_in_default].each do |helper|
get 'dashboard', as: helper, to: "dashboard#index"
end
I think, You may add extra record to route.rb:
get 'signed_in_defaout', as: :signed_in_default, to: "dashborad#inded".

Rails 3: How do I route a controllers index and show actions to root while sending new/edit/destroy to /admin?

First off, I'm using rails 3.0.8 with friendly_id 3.2.1.1.
I'd like to be able to view the posts at website.com/:title, so drop the "/posts".
But I'd also like to have an /admin view. From there, a user should be able to create/edit/destroy posts. I already have a admin.html.erb view with links to various actions.
Right now my routes file look like:
MyApp::Application.routes.draw do
root :to => 'posts#index'
resources :posts
match "/:id" => "posts#show"
match "/admin" => "posts#admin"
end
This works for website.com/:title, but for website.com/admin I get an error:
Couldn't find Post with ID=admin
.... which makes sense. But I'm not sure how to solve this problem.
The rules are run through top to bottom. So put your admin rule on top of the resource definition.
If you put /admin first then it will work (as noted by cellcortex). You can also use :constraints if you can neatly separate your :id from 'admin'; for example, if your :id values are numeric, then something like this should work:
match '/:id' => 'posts#show', :constraints => { :id => /\d+/ }
match '/admin' => 'posts#admin'
In a simple case like yours, putting things in the right order will work fine. However, if your routing is more complicated, then the :constraints approach might work better and avoid a some confusion and chaos.
Use this
resource :posts, :path => '/'
with this all of your article will be directly under root
So in Posts Class you may add this:
def to_param
"#{id}-#{title.parameterize}"
end

Rails3 Routes - Passing parameter to a member route

I would like to pass an extra parameter to a member route of a resource
something like:
resources :events do
member do
get 'register/:participant_type_id'
end
end
I could only accomplish it using a static match statement
Looking around the internet I saw that this might be possible in Rails 3.0.2. I'm using 3.0.1 and it certanlly is not.
Am I doing something wrong? or is it really not possible?
thanks
Try this:
resources :events do
member do
get 'register/:participant_type_id', :action => 'register'
end
end
Just to complete the answer with my little findings. It also confused me for quite a while.
In Rails3, the member route with parameters will not have the automatic generated xx_yy_path helper. You need to add it providing the :as => part, omitted the resources name.
Regarding the example provided, to get register_event_path and register_event_url, you need to define it like the following:
resources :events do
member do
get 'register/:participant_type_id', :action => 'register', :as => 'register'
end
end

Resources