Routing to non-restfull controller - ruby-on-rails

I have a controller Sagepay, which have number of custom method (not RESTfull resources). How can I write routes for those actions? So far I tried:
namespace :sagepay, controller: :sagepay, as: :sagepay do
post :notification
get :iframe_breaker
get :accept_payment
end
This however tries mapping to sagepay/sagepay_controller instead simple sagepay_controller.
Obviously I can do this:
match '/sagepay/notification' => 'sagepay#notification', via: :post, as: sagepay_notification
(etc)
which works, but this is not a solution I am looking for. Is there any way I can write it in common block?

The reason you get sagepay/sagepay_controller is the reason why namespaces are used. In order to get sagepay/notification you can define a resource and add collection routes within it, as follows:
# config/routes.rb
resource :sagepay, controller: :sagepay do
collection do
post :notification
get :iframe_breaker
get :accept_payment
end
end
Update:
In order to define only the routes defined within the collection and avoid definition of the seven restful routes that Rails create you can pass in only option to the resource definition as follows:
# config/routes.rb
resource :sagepay, controller: :sagepay, only: [] do
collection do
post :notification
get :iframe_breaker
get :accept_payment
end
end

I think I found the solution:
scope 'sagepay', controller: :sagepay, as: :sagepay do
post :notification
get :iframe_breaker
get :accept_payment
end

Related

Create views in resource in Rails

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

How to remove resource name from route helper?

I have a route:
resources :promo_pages, path: 'promo' do
get :promo_rubizza, on: :collection, path: 'rubizza', as: :rubizza
end
This route is created - rubizza_promo_pages_path
But I'd like to have - rubizza_path.
How to implement it?
I wanted to implement this as resources :promo_pages, path: 'promo', as: '', but it created rubizza__index_path
UPD: output rails routes
rubizza_promo_pages GET /promo/rubizza(.:format) promo_pages#promo_rubizza
In routes, please define the following route (put it on the same level as resources, without nesting):
get 'promo/rubizza', to: 'promo_pages#promo_rubizza', as: 'rubizza'
Then, you should be able to use rubizza_path and rubizza_url.
what you can do is define this path in your application controller:
class ApplicationController < ActionController::Base
...
def rubizza_path
rubizza_promo_pages_path
end
helper_method :rubizza_path
end
in your routes.rb:
resources :promo_pages, path: 'promo' do
get :promo_rubizza, on: :collection, path: 'rubizza', as: :rubizza
end
That way, you can still use rubizza_path in your views, helpers, controllers, etc. but it uses the full nested route instead.
Customising the routes names details are available here.
What about defining the path based on controller and action?
get 'promo_pages/promo_rubizza', to: 'promo_pages#promo_rubizza', as: :rubizza
it will return:
Prefix Verb URI Pattern Controller#Action
rubizza GET /promo_pages/promo_rubizza(.:format) promo_pages#promo_rubizza

Getting 'Unknown action in controller'

I'm getting this error :
"The action 'create' could not be found for ObjectController"
I know it should be obvious but I'm missing something, that's my controller :
class ObjectController < ApplicationController
def index
end
def create
end
end
And that is my routes :
Rails.application.routes.draw do
get 'object/index'
get 'object/create'
match ':controller(/:action(/:id))', :via => :get
resources :objets
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root"
root 'object#index'
You probably want to scrap those routes and try something simpler like
resources :objects, only: [:get, :create, :show]
Then use
$ rake routes
To make sure your routes are as the should be. You will want a POST route to /objects to create a new object etc..
Ok that one was dumb, actually I had two directories and I wasn't modifying the right one, sorry about that...
Your routes could be greatly improved:
#config/routes.rb
Rails.application.routes.draw do
root 'objects#index'
resources :objects
--
Next, the "standard" way to achieve what you're looking for is to use the new action; IE not the "create" action. If you wanted to use the create path name (instead of new), you'll be able to define it in the path_names argument:
#config/routes
resources :objects, path_names: { new: "create", create: "create" } #-> url.com/objects/create
To understand why you should be using new instead of create, you should look up resourceful routing, and how it pertains to object orientated programming.
Finally, your controller should be named in the plural:
#app/controllers/objects_controller.rb
class ObjectsController < ApplicationController
...
end
Whilst you can call it whatever you like, Rails defaults to plural controller names, singular model names.

How to write nested route when function is not for member or collection

I'm working with a home_controller that has dozens of methods, none of which are on instances or collections of Home. How can I write my routes in a block instead listing them in the following manner?:
put 'home/enable_admin', :as => :enable_admin
If I understand you correctly, you want something like this:
resources :home, only: [] do
member do
#some route that does require an :id
end
collection do
put 'enable_admin'
#some route that doesn't require an :id
end
end
This should give a bunch of custom routes with none of the normal rails routes.

Why isn't my 'join' action working, it says the action 'show' can't be found

In my UserController I have:
def join
end
I have a join.html.erb in my /views/user/ folder.
My routes has a :
resources :user
When I go to:
http://localhost:3000/user/join
I get:
The action 'show' could not be found for UserController
Re: why isn't the join action found?
To answer your specific question, what's happening is that you want to have an action "join" for your User model.
Your problem is that you haven't defined a route matching the url http://localhost:3000/user/join
The line resources :user in your routes file only defines routes for the seven standard rest verbs/actions:
index, new, create, show, edit, update, destroy
See: http://apidock.com/rails/ActionController/Resources/resources
Added: to fix, you'll need to add an explicit or generic route. Routing docs
Added: Re: why am I seeing the error message re show? To be ultra-precise, the route selector "GET /usr/:id" (created by your resource call) is being used to select the SHOW action for the User resource. The :id value is being set to "join". Since you don't have a Show method defined in your controller, that's the error that you're seeing.
You're using resources, but have a non-REST action, so you need to add the join action to the route with the appropriate HTTP verb:
map.resources :users, :member => { :join => :get }
Place:
def show
end
in your UserController.
To be certain:
app/controllers/users_controller.rb
def join
end
app/views/users/join.html.erb
config/routes.rb
resources :users

Resources