Rails 5.1 Routes: dynamic :action parameters - ruby-on-rails-5

Rails 5.0.0.beta4 introduced a deprecation warning on routes containing dynamic :action and :controller segments:
DEPRECATION WARNING: Using a dynamic :action segment in a route is deprecated and will be removed in Rails 5.1.
The commit message from this PR states:
Allowing :controller and :action values to be specified via the path
in config/routes.rb has been an underlying cause of a number of issues
in Rails that have resulted in security releases. In light of this
it's better that controllers and actions are explicitly whitelisted
rather than trying to blacklist or sanitize 'bad' values.
How would you go about "whitelisting" a set of action parameters? I have the following in my routes file, which are raising the deprecation warning:
namespace :integrations do
get 'stripe(/:action)', controller: 'stripe', as: "stripe"
post 'stripe/deactivate', controller: 'stripe', action: 'deactivate'
end

Though it's a bit cumbersome, the best approach seems to be to explicitly define the routes:
namespace :integrations do
namespace 'stripe' do
%w(auth webhook activate).each do |action|
get action, action: action
end
end
post 'stripe/deactivate', controller: 'stripe', action: 'deactivate'
end

Is not the same case as you, but I did this:
class PagesController < ApplicationController
def index
render params[:path]
end
end
Routes:
get ':path', to: 'pages#index'
I suppose if I want a nested path I will use *:
get '*path', to: 'pages#index'

It works like this:
get 'stripe(/:action)', controller: 'stripe', action: :action, as: "stripe"

Related

Routing error rails 3

I have a Rails 2.3.5 app with many controllers, models etc. which I'm trying to upgrade to Rails 3.2.21. I'm having some troubles with my routes. I tried to follow the Rails 3 new routing format but it doesn't seem to work. I'm getting two problems (which I guess all indicate one fundamental issue with my routing):
In the root ('/') I'm getting the generic "Welcome abroad" Rails
page. My routes (see below) have defined routing for root.
For some controllers I get No route matches [GET] "/study" message. My route shows this route, but for some reason doesn't define the GET method.
Here's my config/routes.rb code:
Myapp::Application.routes.draw do
root :to => 'study#index'
match 'login' => 'login', :protocol => 'https://'
resources :study_maps do
get :clone, :on => :member
end
# Route report create actions to the report controller
match 'report/create', :as => 'report'
match ':controller(/:action(/:id))(.:format)'
end
If I'm running rake routes I'm getting:
root / study#index
login /login(.:format) login#login {:protocol=>"https://"}
clone_study_map GET /study_maps/:id/clone(.:format) study_maps#clone
study_maps GET /study_maps(.:format) study_maps#index
POST /study_maps(.:format) study_maps#create
new_study_map GET /study_maps/new(.:format) study_maps#new
edit_study_map GET /study_maps/:id/edit(.:format) study_maps#edit
study_map GET /study_maps/:id(.:format) study_maps#show
PUT /study_maps/:id(.:format) study_maps#update
DELETE /study_maps/:id(.:format) study_maps#destroy
report /report/create(.:format) report#create
/:controller(/:action(/:id))(.:format) :controller#:action
Here's my StudyController#index code:
require 'myapp/studymgr'
require 'project_user'
require_dependency 'myapp/controller_extensions/report_manager'
class StudyController < ApplicationController
include PaginatorController
before_filter(:authenticate, :except => [:todo])
before_filter(:authorize,
:only => [:update, :destroy, :edit, :prune, :select_experiments ])
def index
#tags = Stag.find(:all).collect { |stag| stag.tag }
...
#include_ext = true
end
end
Can someone advise on what I'm missing?
Finally found a solution - my views had .rhtml extension. I found that this format is no longer supported under Rails 3 (What is the difference Between .erb , .rhtml and .html.erb?), so I changed all views extensions to .html.erb and then the routes worked with no need to specify explicit resource for each controller, just using the generic route: match ':controller(/:action(/:id))'.
As for the issue in the root route (#1 above), where I always got the Rails "Welcome abroad" page, despite having explicit route in my routes.rb, turns out I had to remove public/index.html which is loaded for root by Rails, and then my view was loaded.

how can I make a simple route on rails and can I use it for an ajax form?

Ive been trying to create a simple route on rails, following this instructions
http://guides.rubyonrails.org/routing.html
my problem is that when I want to enter to my method I get a weird error.
I have a controler user and on my routes I wrote something like this
resources :users do
match "/custom/" => "user#custom"
end
So, at my controller I add this code
def custom
#user = User.find(params[:user_id])
end
but when I try to enter doing localhost:3000/users/1/custom I get an error like
uninitialized constant UserController
doing rake routes I can see
user_custom /users/:user_id/custom(.:format) user#custom
Any idea how to solve this problem?
I want this route to submit a form... is it possible to use this route (if i make it run) for use ajax? I want to submit a form.
Thanks
Change your route to:
resources :users do
match "/custom/" => "users#custom"
end
You should avoid the use of match though, since it will be deprecated in Rails 4. Try this instead
resources :users do
get :custom, on: :member
end
get is the verb, :custom the route and on: :member means that you are looking for a /users/:id/custom route instead of a /users/custom one. If you are looking for the latter, do this:
resources :users do
get :custom, on: :collection
end
Another way to do it is like this, which I prefer:
resources :users do
get 'custom', on: :collection
end
That gives you a route of /users/custom. If you were do use on: :member, then it would give you a route of /users/:id/custom.
You can also use a block for defining multiple custom actions for collections or members.
For example:
resources :users do
collection do
get 'custom'
post 'some_other_method'
end
member do
get 'some_action'
end
end

Ruby on Rails 3 nested routes: wrong action route

I have two models: team and project
routes.rb
resources :teams do
resource :projects
end
And two questions!
1- According to http://guides.rubyonrails.org/routing.html, I expect to get teams/:team_id/projects/:id path. However, this is not the case.
rake routes
team_projects POST /teams/:team_id/projects(.:format) projects#create
new_team_projects GET /teams/:team_id/projects/new(.:format) projects#new
edit_team_projects GET /teams/:team_id/projects/edit(.:format) projects#edit
GET /teams/:team_id/projects(.:format) projects#show
PUT /teams/:team_id/projects(.:format) projects#update
DELETE /teams/:team_id/projects(.:format) projects#destroy
so I had to name route to get it working
match 'teams/:team_id/projects/:id' => 'projects#show', :via => [:get], :as => :show_project
so how can take advantage of rails helper methods instead of naming them?
2- In project show action view, the debugger throws these parameters for me:
action: show
controller: projects
team_id: '1'
which is fine. but when I click on "new_team_projects_path" url, it redirects me to the same view and the debugger throws these parameters:
controller: projects
action: show
team_id: '1'
id: new
It doesn't redirect me to the new action, but it took "new" as an ID! why?
You need to use
resources :teams do
resources :projects
end
Note the plural! resource produces a singular route without id.
won't be relevant anymore with the first fix.

Redirecting from a namespaced controller using a hash

I have a double namespace situation, where my controllers look like this:
CandidateController
Candidate::PerformanceController
Candidate::Performance::ReviewController
In Rails 2, I was able to use redirect_to from the Candidate::Performance::ReviewController controller in order to redirect to an action in the CandidateController, like so:
class Candidate::Performance::ReviewController < ApplicationController
before_filter :ensure_manager
# ...
def ensure_manager
if !current_user.manager?
flash[:warning] = t(:must_be_manager)
redirect_to :controller => '/candidate', :action => :index
end
end
end
The / in controller => '/candidate' would allow Rails to redirect from app.com/performance/reviews to app.com/candidate.
However, this seems to not work the same in Rails 3.1. Instead, my redirect_to goes to app.com/candidate//candidate. What is the correct way to specify a "absolute" controller within a redirect_to hash (ie. without using a path helper)?
Update: I know this would be infinitely easier if I just use named route helpers (ie. candidate_path). Unfortunately, there is a lot of legacy code in our codebase which doesn't use RESTful routing and instead uses the default "catch-all" route; ie. we have a lot of actions with no named route to fallback on.
I wonder if something else is wrong. In the doc:
In particular, a leading slash ensures no namespace is assumed. Thus,
while url_for :controller => ‘users‘ may resolve to
Admin::UsersController if the current controller lives under that
module, url_for :controller => ’/users‘ ensures you link to
::UsersController no matter what.
And I don't think it changed...
Also, shouldn't the catch-all routes be after the default routes in your config?
I think that redirect_to :controller => ... uses url_for to build the url, so in the end, if your custom routes catches /candidates, I don't really see the difference.
Some people have the same problem: https://github.com/rails/rails/issues/2575
Patching actionpack/lib/action_dispatch/routing/route_set.rb line 434
as follows fixes this: if !named_route && different_controller? &&
!controller.starts_with?('/')
If anyone else runs into this problem, it seems to be a known issue (unsure whether they consider it a bug or not, given the lack of response on the issue page from anyone working on Rails).
Until they patch it (assuming they do), I've added the following little monkey patch into an initializer, based on the code given in the original post of that issue:
module ActionDispatch
module Routing
class RouteSet
class Generator
def use_relative_controller_with_absolute_paths!
return if controller.starts_with?('/')
use_relative_controller_without_absolute_paths!
end
alias_method_chain :use_relative_controller!, :absolute_paths
end
end
end
end
Hope this can help someone else!
Update: It seems that this was fixed in Rails here.

respond_with and namespaced controller

I'm trying to make use of rails 3's respond_to/respond_with mechanism for restful controllers. I'm finding that when I try and use those features within a namespaced controller the redirects fail and i have to specify the optional location: parameter on the respond_with.
So right now I have:
def Admin::FooController
respond_to :html, :xml
def create
#foo = Foo.new(params[:foo])
#foo.save
respond_with(#foo, location: admin_foo_path(#foo))
end
end
If I don't provide the location parameter it attempts to redirect to just foo_path(#foo)
Any ideas as to why this would be / if I'm doing something wrong or does rails 3's default responder just not handle namespaced URL routes?
respond_with(:admin, #foo)
This blog has more..