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..
Related
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"
I am looking for the correct way to redirect an entire site to a 404 page in the routes.rb file in a rails 3 application.
I can do a page using: match 'url' => redirect("/404")
But I want to know how to 404 all the pages without using adding a redirect to every route?
You can create a new method in your ApplicationController like below:
class ApplicationController < ActionController::Base
# ... other code
def redirect_to_404
raise ActionController::RoutingError.new('Not Found')
end
end
Then call that function within the controllers which handle the views you want to redirect.
In Rails you can create a method to render 404's in the Application Controller, ActiveRecord and Abstract Controller:
def make_404
raise ActionController::RoutingError.new('404')
end
I'm fairly new to rails, but I have completed a couple of projects before, including the Michael Hartl Tutorial.
I'm building a simple app that stores a virtual wardrobe.
I've got 2 tables - users and items - where a user has_many items and an item belongs_to a user.
I set up the following named route in my routes.rb file:
match "/wardrobe", to: "items#index"
However, when I try to go to /wardrobe in my browser I get a no route match error as follows:
No route matches {:action=>"show", :controller=>"items"}
I'm not sure why rails is trying to route via the show action when I've named the route through the index action.
These are the relevant actions in my ItemsController:
def show
#item = Item.find(params[:id])
end
def index
#items = Item.all
end
The redirect is called on create as follows:
def create
#item = Item.new(params[:item])
if #item.save
flash[:success] = "Item added"
redirect_to wardrobe_path
else
render 'new'
end
end
rake routes provides the following:
wardrobe /wardrobe(.:format) items#index
So, I know the route exists.
Can anyone explain what's going on here? And how I can go about fixing it?
Thanks in advance
It might be because it's rake route is called wardrobe_path rather than wardrobes_path (plural) - when it's singular Rails will default to show action I believe. That might be causing the confusion.
My controller is using the default RESTful routes for creating, adding, editing etc
I want to change the default :id to use :guuid. So what I did was:
# routes.rb
resources :posts
# Post Model
class Post < ActiveRecord::Base
def to_param # overridden
guuid
end
end
This works but my modifed REST controller code has something like this
def show
#post = Post.find_by_guuid(params[:id])
#title = "Review"
respond_to do |format|
format.html # show.html.erb
end
end
When I see this this code ..
Post.find_by_guuid(params[:id])
it would seem wrong but it works.
I don't understand why I can't write it out like this:
Post.find_by_guuid(params[:guuid])
Why do I still have to pass in the params[:id] when I'm not using it?
Looking for feedback on whether my approach is correct or anything else to consider.
Even though it works it doesn't always mean it's right.
Type rake routes in your console, and check the output of the routes. You'll see the fragment ':id' in some of them, that's where the params[:id] comes from. It's a rails convention : when you use resources in your routes, the parameter is named id. I don't know if you can change it (while keeping resources; otherwise you could just go with matching rules), but you shouldn't anyway : even if it seems not very logic, it actually has sense, once your understand how rails routing works.
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.