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" } %>
Related
I am a beginner working with Rails: I have this routes.rb:
Rails.application.routes.draw do
resources :requirements
root "department#index"
get "department/about"
end
How can I create a view that has a path like requirements/major?
Thank you so much!
You can extend resources and add custom actions, like this:
resources :requirements do
collection do
get :major
end
end
You'll need an action in the RequirementsController that matches, e.g.
class RequirementsController < ApplicationController
def major
# set up whatever resource 'major' corresponds to
end
...
end
That's at least one way of doing it. You could also have a controller that directly supports the nested 'major' resource, which would be similar to above - just with a controller: 'name of controller' directive inline..
It'd probably pay to get your head around the "Rails Routing from the Outside In" guide: https://guides.rubyonrails.org/routing.html
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
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.
I'm trying to call a custom controller action shuffle for a resource that is nested within another resource. I can't seem to get the method call right.
routes.rb
resources :templates do
resources :items
end
match "/templates/:template_id/items/shuffle" => "items#shuffle"
I have a link in my items#index view:
<%= link_to 'Shuffle', shuffle_template_items_path(#template) %>
When I click on the link, I get the following error:
undefined method `shuffle_template_items_path' for #<#<Class:0x42577c8>:0x3e77578>
I have also tried <%= link_to 'Shuffle', template_items_shuffle_path(#template) %> and that did not work.
How do I correctly call this custom action?
You probably want this:
resources :templates do
resources :items do
get :shuffle, :on => :collection
end
end
If you want your custom action to have a name, you need to provide it:
match "/templates/:template_id/items/shuffle" => "items#shuffle", :as => :suffle_template_items
I think the best way to write shuffle is in collection as per the documentation of Rails Routes:
So it would looks like this:
resources :templates do
resources :items do
collection do
get :shuffle
end
end
end
when you try rake routes you will find shuffle_template_items GET /templates/:template_id/items/shuffle(.:format) items#shuffle.
Let's say I have a receipts model, and I want to offer a controller action to print one... The un-restful way would be to do:
# receipt_controller.rb
def print
...
end
#routes.rb
resources :receipts do
get :print, :on => :member
end
... The restful way would be:
# receipt_printings_controller.rb
def create
...
end
#routes.rb
resources :receipts
resources :receipt_printings, :only => :create
My question is..... Let's say I wanted to have the following structure:
/app
/controllers
receipts_controller.rb
/receipt
printings_controller.rb
That would mean my class would look like:
class Receipt::PrintingsController < ActiveRecord::Base
def create
...
end
end
But I don't know how to properly route in this context because I still need to be able to do:
receipt_printings_path(123) to get /receipts/123/printings
The only way I know how to accomplish this is to do:
#routes.rb
match "/receipts/:id/printings" => "receipt/printings#create", :as => :receipt_printings
resources :receipts
But, I am wondering if there is a better way?
I think you can do something like this:
resources :receipts do
resources :printings, :controller => "receipt/printings", :only => :create
end
It will generate :
receipt_printings POST /receipts/:receipt_id/printings(.:format) receipt/printings#create
Then to access to your route :
receipt_printings_path(:receipt_id => #receipt.id)
I hope it helps
If i'm right, you need a nested resource, have look in this rails guide
You can use nest routes, but the way I read your question it sounds to me like you want namespaces. Namespaces might look like the following:
resources :receipts
namespace :receipts do
resources :printings
end
This would route /receipts/printings/:id to app/receipt/printings_controller.rb with an id for the printing (not the receipt).
You might really want nested routes. If you want to use the receipt id, and have only one print action (per receipt), you could use a singular resource.
resources :receipts do
resource :printing
end
This will route /receipts/:id/print to app/printings_controller.rb as show.
To organize the printings controller in a namespace, I would leave it out of the routes, because that will try to insert another receipts namespace in the URL. Instead, use,
resources :receipts do
resource :printing, :controller => "receipt/printings"
end
This is how to be RESTful. However, you might not have a RESTful case. Is printing really doing a create? Is it really doing a show or update? If it's a service which doesn't fit into a CRUD operation, then it's time to deviate from the golden path, and go ahead and use a non-RESTful verb.