Rails 4 match all routes for one controller - ruby-on-rails

I have a controller with a number of static pages and I would ideally like to route them all with a wildcard.
Is it possible to do something like the following?
get 'static/:action'

Why don't you just use the show action:
#config/routes.rb
resources :static, param: :page, only: :show #-> url.com/static/:page
#app/controllers/static_controller.rb
class StaticController < ApplicationController
def show
render "#{params[:page]}"
end
end
This way, you can pass the "page" directly through the link and have it all handled by Rails:
<%= link_to "About", static_path("page") %>

You probably need something like get 'static/:action', to: 'static#show' and then in your StaticController show action render the correct static page based on the params[:action] parameter.
See http://guides.rubyonrails.org/routing.html#defining-defaults for more.

You can route something like
get '*path', to: 'static#show'

Related

How to have custom POST requests

I have a WelcomeController which for the moment only has the action GET#index which does nothing (the view renders a welcome message) and is also the root path.
In this view, I want to have two buttons to perform action1 and action2. I've managed to get the result I want with action1 button by doing this:
class WelcomeController < ApplicationController
def index
end
def action1
... #code
end
end
views/welcome/index.html.slim
h1 = "Welcome"
br
= form_tag url: welcome_index_path do
- if user_signed_in?
= submit_tag "Action1"
And in routes.rb:
get 'welcome/index'
post '/welcome/index', to: 'welcome#action1'
I wanna add now the second button in a similar way, but when I click on it, it performs Action1 (I assume it's because the re-routing of post request for welcome/index in routes.rb.
How do I properly do this, so that I can have as many actions that send POST requests as I want?
You may go this document to learn more about routing in rails.
In this case, you may define your routes.rb like this:
resources :welcome, controller: 'welcome', as: 'welcome', only: [:index] do
collection do
post 'action_1'
post 'action_2'
end
end
Then you view will be:
= form_tag url: welcome_action_1_path do
= submit_tag "Action1"
= form_tag url: welcome_action_2_path do
= submit_tag "Action2"
This is more about routing. Check Rails guide on routing, which will help you a lot.
http://guides.rubyonrails.org/routing.html
For action1, you probably want to set a different route.
get 'welcome/index'
post 'welcome/action1', to: 'welcome#action1'
That means an HTTP POST action to url 'welcome/action1' will map to action1 method in welcome controller.
You can keep on adding these.
post 'welcome/action2', to: 'welcome#action2'
You can also use other HTTP methods. Different HTTP methods to same url can be routed to different methods.
get 'welcome/action3', to: 'welcome#action3_get'
post 'welcome/action3', to: 'welcome#action3_post'
patch 'welcome/action4', to: 'welcome#action4'
delete 'welcome/action5', to: 'welcome#action5'
In addition, you can also set an alias for that route, similar to welcome_index_path, which is, after all, a path generated by rails helper that maps to get 'welcome/index' by default.
post 'welcome/action6', to: 'welcome#action6', as: 'welcome_action6'
Then you can use welcome_action6_path in your form tag too.

Referring to a nested resourse

I have a nested resource:
resources :res1 do
resources :res2
end
And I have a custom action in res2:
def my_action
end
which doesn't appear in the list of the pre-generated paths (there is no res1_res2_my_action_url url). I want to refer to my_action using controller and action notation but the following doesn't work:
url_for(controller: [:res1, :res2], action: :my_action)
Why is that?
The resources directive in your routes file will only create default routes for your controller.
#index
#new
#create
#show
#edit
#update
#destroy
If you want to add custom routes, you'll have to declare them like so:
resources :res1 do
resources :res2 do
get :my_action
end
end
you can hard code a specific route that points to action and controller:
get '/pathname', to: 'controller_name#my_action'
Try running rake routes and see what o/p you get,a try to apply in your view
get 'my_action' => "res2#my_action"
and then write
:url => my_action_path

Rails routing error when routing to slug

I have a the following link that goes to the correct page i.e. /events/tech/schedule but I get a routing error.
<%= link_to "View Schedule", event_sessions_path(#event.slug) %>
Error
ActionController::RoutingError at /events/tech/schedule
Not Found
Routes
resources :events do
resources :sessions, path: "schedule", only: [:index]
end
Sessions Controller
before_filter :find_event
private
def find_event
#event = Event.find_by(slug: params[:id])
##event = Event.find(params[:event_id]) This works if I use <%= link_to event_sessions_path(#event.id) %>
end
I don't get any error if I use the event id to link to but this looks ugly and isnt a very good solution.
Edit - add rake routes
event_sessions GET /events/:event_id/schedule(.:format) sessions#index
Here's your solution:
#event = Event.find_by(slug: params[:event_id])
When using resourceful routes in the structure you have, you'll end up wtih this:
events/:event_id/schedule #-> to schedules#index with params[:event_id]
The name of the variable doesn't matter - it's the content which does. :event_id can hold anything (id or slug), what matters is how you deal with it in the controller
If you change your Event.find_by method to use the event_id param, you'll be able to find what you need
friendly_id
A better way to handle this is with friendly_id
If you use the finders module in friendly_id, you'll be able to search either id or slug like this:
Event.find params[:event_id]

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" } %>

Routing Error - custom controller

I have a has many through association.
Firms have many Users through Follows.
I want Users to be able to Follow Firms. - I am using Devise for the users.
I have the following action in my firms controller.
def follow
#firm.users << current_user
end
in my routes.rb
resources :firms do
post :follow, on: :member
end
and in my firms view
<%= link_to "Follow", follow_firm_path(#firm), method: :post %>
However when I keep getting the following Routing Error in the browser
No route matches {:action=>"follow", :controller=>"firms"}
Rake Routes confirms the following
follow_firm POST /firms/:id/follow(.:format) firms#follow
Any ideas what the problem may be?
Many thanks
Edit: Controller code
class FirmsController < ApplicationController
before_filter :authenticate_user!, :except => [:show, :index]
def index
#firm_names = Firm.all.map &:name
direction = params[:direction]
direction ||= "ASC"
#firms = Firm.order("name #{direction}")
respond_to do |format|
format.html # index.html.erb
format.js
end
end
def follow
#firm.users << current_user
end
I am using the follow action in a partial in the index view.
everything looks good and this should work perfectly. Except that I see a typo in the following line
<%= link_to "Follow", follow_firm_path(#firm), method: :post %>
after the :method there should an => not a : . this will make the link a get request not a post request, that might be the issue, try using a simple link and replace post will get in your routes.rb just to test if the issue is arising due to this.
you can also test route methods from the console
rails c
app.follow_firm_path(2)
I noticed you also have an error in your routes, there should be an => not a : after :on
resources :firms do
post :follow, :on => member
end
You should define methods like this...
resources :firms do
collection
post :follow, on: :member
end
end
I think if this method does not create anything its type should be get.
Try it

Resources