How to name nested controllers and routes? - ruby-on-rails

I'm working on creating a wiki app from scratch with the following organization:
Main Controller: Wiki
Nested Controller: WikiCategories
Nested Controller: WikiArticles
In my config/routes.rb I have:
resource :wiki do
resources :wiki_categories, :as => :categories
resources :wiki_articles, :as => :articles
end
I've chosen to name the categories and articles controllers as WikiCategories and WikiArticles to differentiate from other category and article controllers that I want to make in the future under a blog nesting.
This gives me the following routes:
/wiki/wiki_categories/new
/wiki/wiki_articles/new
Is there any way to rewrite the routes to be:
/wiki/categories/new
/wiki/articles/new
... while still using the WikiCategories and WikiArticles controller names?

I've chosen to name the categories and articles controllers as WikiCategories and WikiArticles to differentiate from other category and article controllers that I want to make in the future under a blog nesting.
IMO, it seems like you're bucking convention a bit. As discussed in Controller Namespaces and Routing, why not do:
namespace :wiki do
resources :categories, :articles
end
Which will give you:
wiki_categories GET /wiki/categories(.:format) wiki/categories#index
POST /wiki/categories(.:format) wiki/categories#create
new_wiki_category GET /wiki/categories/new(.:format) wiki/categories#new
edit_wiki_category GET /wiki/categories/:id/edit(.:format) wiki/categories#edit
wiki_category GET /wiki/categories/:id(.:format) wiki/categories#show
PATCH /wiki/categories/:id(.:format) wiki/categories#update
PUT /wiki/categories/:id(.:format) wiki/categories#update
DELETE /wiki/categories/:id(.:format) wiki/categories#destroy
wiki_articles GET /wiki/articles(.:format) wiki/articles#index
POST /wiki/articles(.:format) wiki/articles#create
new_wiki_article GET /wiki/articles/new(.:format) wiki/articles#new
edit_wiki_article GET /wiki/articles/:id/edit(.:format) wiki/articles#edit
wiki_article GET /wiki/articles/:id(.:format) wiki/articles#show
PATCH /wiki/articles/:id(.:format) wiki/articles#update
PUT /wiki/articles/:id(.:format) wiki/articles#update
DELETE /wiki/articles/:id(.:format) wiki/articles#destroy
Then, create namespaced controllers, something like:
app/controllers/wiki/categories.rb
class Wiki::CategoriesController < ApplicationController
...
end
and
app/controllers/wiki/articles.rb
class Wiki::ArticlesController < ApplicationController
...
end

Yes it is by specifying the controller, the resource can then be named whichever way you like.
resource :wiki do
resources :categories, controller: 'wiki_categories'
resources :articles, controller: 'wiki_articles'
end
Please see the guide for further information.

You can use the path: option as follows:
resource :wiki do
resources :wiki_categories, path: 'categories', :as => :categories
resources :wiki_articles, path: 'articles', :as => :articles
end
Which will give you:
/wiki/categories/...
/wiki/articles/...
See Translated Paths section of the guides for further details.

Related

Missing :action key on routes definition Rails

I am getting the following error:
Missing :action key on routes definition, please check your routes.
For this route
resources :groups do
post '/groups/:id/add', on: :member
end
I have looked at several other SO answers on this but am not able to find one that helps me. What action is it missing?
This is not the right way to define routes. Actually router's member/collection accepts a key-value pair to generate the route. As you are defining a member function it will be like:
resources :groups do
member do
post :add
end
end
It will generate a route like: groups/1/add
If you use collection then it will generate: /groups/add
resources :groups do
collection do
post :add
end
end
Hope you get the idea.
Or
You can define specific route for this particular action like below:
match "/groups/:id/add" => "groups#add", via: :post
Key action here means controller action. as in
resources :groups do
post '/groups/:id/add', on: :member, action: "add"
end
Rails can't infer the action from a path. But you can define the action instead and rails will automatically figure out the path:
resources :groups do
post :add, on: :member
end

Rails how to make example.com/post/1 to example.com/blog/post/1

I have a blog with root
root 'posts#index'
And works best with example.com/ to example.com/posts
But what I want is something like this:
example.com/blog/posts/1.
I've tried creating blog Controller and add
resources :blog do
resources :posts
end
But this is making my routes to blog/:id/posts/:id
If you don't have the relationship between the post and the blog as you mentioned, rails gives you the freedom to declare routes as our own.
so, to make the route example.com/posts/1 to, example.com/blog/posts/1, just add a custom route at the last.
get '/blog/posts/:id', to: :show, controller: 'posts'
what this does is over rides the previous route and make this route final.
Now type rake routes and it will give the last route for you as,
GET /blog/posts/:id(.:format) posts#show
Now you can access using,
example.com/blog/posts/1
Reference for rails routing
Just to expand upon #Sravan answer. If you have multiple routes that will start with /blog/ you might want to check Rails guide on routing.
You can add something along the lines of
scope '/blog' do
resources :posts
resources :users
resources :images
end
Which will create corresponding routes under /blog/.
namespace :blog do
resources :posts
resources :users
resources :images
end
And your controller with namespace will look like this: Blog::PostsController

Custom Route to Custom Page in Rails 4

I have an app with a parent resource (has_many) of patterns and a child resource (belongs_to) of snippets. My desire is to build a couple custom routes to specific pages and I am wondering the best way to do that. For now, here is what I have that is working, but I am wondering if there is a better way since the article I read on custom routing tells me this is not good practice.
I have purposefully not nested the resources because the snippets need to stand alone as well as be viewed within the context of their parent pattern.
The goal is to be able to create a few custom views like the following:
http://patterns.dev/patterns/:id/snippets //Got this one working, but incorrectly I believe
http://patterns.dev/patterns/:id/snippets/sort // Show all snippets for pattern to sort
http://patterns.dev/patterns/:id/images // Show all the images for patterns to moderate
routes.rb
Rails.application.routes.draw do
devise_for :users, :path => '', :path_names => {:sign_in => 'login', :sign_out => 'logout'}
resources :patterns
get 'patterns/:id/snippets' => 'patterns#snippets', as: 'pattern_snippets'
resources :snippets
root 'welcome#index'
end
I guess nested resources is what you need. You can specify just index action for nesting and keep all the snippets resources separately. Also you are to add some logic to snippets#index action to check params[:pattern_id]'s existance:
resources :patterns do
# this line will generate the `patterns/:id/snippets` route
# referencing to snippents#index action but within specific pattern.
# Also you have to add pattern_id column to snippets table to define the relation
resources :snippets, only: :index
end
resources :snippets
Use Collection Routes to make Rails to recognize paths like /patterns/:id/snippets/sort
resources :patterns do
resources :snippets, only: :index do
# this line will generate the `patterns/:id/snippets/sort` route
# referencing to snippets#sort action but again within specific pattern.
get :sort, on: :collection
end
end
resources :snippets
If you have Image model you can nest resources the same way like with snippets:
resources :patterns do
resources :images, only: :index
end
If it's just an action in patterns controller you can do:
resources :patterns do
get :images, on: :member
end

rails custom rest route with parameter

I have a questions controller and an associated model and a number of rest routes. Here is how it's set up in routes.rb:
resources :questions
I want to add a custom route that has the format /questions/widget/ID (where ID is the id of the question for which I want to generate a widget). I want this to be processed by the "widget" action in my questions controller. I've tried a number of things such as:
resources :questions do
member do
get 'widget/:id'
end
end
But nothing is working. I'm sure I'm missing something simple. Any ideas? Thanks in advance.
You do not have to specify the id since you are inside resources. It should look like:
resources :questions do
member do
get 'widget'
end
end
You can get more information from the Rails Guide. Look at section 2.9.1.
Edit: I just noticed that you are trying to match get /questions/widget/:id. This will set up a route for get /questions/:id/widget. This is more in line with Rails convention. If you really want it the other way, you need to set up a custom match statement:
match "/questions/widget/:id" => "questions#widget"
However, I would stick with convention.
I know it is old, but looking to fix another routing problem I ended here, it is possible, to do what you are asking for, here is an example
resources :articles do
get 'by_tag/:tag' => :by_tag, on: :collection
get 'by_author/:author' => :by_author, on: :collection
resources :comments, except: :show
end
now you have /artices/by_tag/:tag . The trick was to use on:collection.
Obviously don't forget to add the by_tag action and by_author.
class ArticlesController < ApplicationController
.....
def by_tag
...
end
end
Check this route works with
melardev#local~$ rails routes
Why don't you use this routes:
resources :questions do
resources :widgets
end
it will create path like questions/:question_id/widgets/new for you to create new widget for question with specific id of question.
This is what ended up working for me:
resources :post do
get "author/:author", to: "posts#author", on: :collection, as: "author"
end
Which outputs the following route:
author_posts GET /posts/author/:author(.:format) posts#author
Then in your controller, you need to create the author action:
class PostsController < ApplicationController
def author
#roles = Post.where(author: params[:author])
render :index # to reuse the index view
end
end
Then in your view:
<%= link_to post.author, author_posts_path(post.author), data: { turbo_frame: "_top" } %>

Rails - Routes for Nested Resources

I have a conversations controller and a comments controller.
What I would like to do is have the following (from the logs):
Started POST "/conversations/217/comment_beta" for 127.0.0.1
Post the Comments Controller not the Conversations Controller which is what Rails is trying to do now:
AbstractController::ActionNotFound (The action 'comment_beta' could not be found for ConversationsController):
Here is my routes file:
resources :conversations do
resources :comments, :only => [:create, :update,:destroy, :comment_beta], :constraint => {:context_type => "conversations"} do
collection do
post 'comment_beta'
end
end
collection do
get 'read_updater'
end
end
Suggestions? Thanks
your rails routes is actually doing what it is supposed to do. if you conversations/:id/comment_beta to go to your comments controller, either you should change your routes via match or go to the correct url which is /conversations/:id/comments/:comment_id/comment_beta
If you're posting to create a new comment, why aren't you using RESTful routes?
resources :conversations do
resources :comments do
collection do
post 'comment_beta'
end
end
end
should give you /conversations/:id/comments/comment_beta
collection because you don't need an id

Resources