I am trying to add a constraints to our error-routes so that requests to certain routes would not get redirected to a 404-page if we're working on our app in development.
match '*unmatched_route', :to => 'application#handle_404', via: :all, constraints: lambda { |request| !request.url["/rails/info"] }
This is the rule we currently have in place. All "invalid" routes being redirected to a 404-page. Now I want to upgrade this to only allow access to /rails/info/* if the app is in development-mode.
I tried the following:
match '*unmatched_route', :to => 'application#handle_404', via: :all, constraints: lambda { |request| !request.url["/rails/info"] && !Rails.env.development? }
I am not sure where exactly the problem is. The addition inside the constraint does not seem to have any effect, thus I believe I am using the constraint entirely wrong.
Thanks in advance!
Might not be as elegant, but you could put the route inside a unless block, like this:
unless Rails.env.development?
match '*unmatched_route', :to => 'application#handle_404', via: :all, constraints: lambda { |request| !request.url["/rails/info"] }
end
Related
How can I route all subdomains to a controller in a Rails app?
I though something like this would work, but it doesn't:
constraints :subdomain => '*' do
get '/', :to => 'frontend#index'
mount API => '/api'
end
Subdomains like
foo.example.com
bar.example.com
should be directed to frontend#index while
foo.example.com/api
bar.example.com/api
should call the Grape API.
Use a regular expression:
constraints :subdomain => /./ do...
Haven't tested it, but something like that should work.
I would like a rails route that takes 2 constraints into consideration. How can this be done? The two constraints
match ':id' => 'pages#temp', :constraints => { :uuid => /[A-Za-z\d]([-\w]{,498}[A-Za-z\d])?/ }
root :to => 'pages#temp', :constraints => lambda {|r| r.env["warden"].authenticate? }
How can I have one route like so with both of the constraints in place? Thanks
match ':id' => 'pages#temp', :constraints =>
I guess you will have to make a custom constraints class and put all your constraints there. Refer the advanced constraints in rails guides(Link below) for more information.
http://guides.rubyonrails.org/routing.html#advanced-constraints
I had to use multiple constraints for subdomains and usernames. I used a block to solve the issues:
constraints subdomain: ['survey', 'survey.staging'] do
match "/(:username)", to: "responses#index", constraints: { username: /[0-z\.\-\_]+/ }, :via => [:get, :post]
end
So you might try something like this:
constraints id: { uuid: /[A-Za-z\d]([-\w]{,498}[A-Za-z\d])?/ } do
match '/:id' to: 'pages#temp', constraints: lambda {|r| r.env["warden"].authenticate? }
end
My app used to run on foo.tld but now it runs on bar.tld. Requests will still come in for foo.tld, I want to redirect them to bar.tld.
How can I do this in rails routes?
This works in Rails 3.2.3
constraints(:host => /foo.tld/) do
match "/(*path)" => redirect {|params, req| "http://bar.tld/#{params[:path]}"}
end
This works in Rails 4.0
constraints(:host => /foo.tld/) do
match "/(*path)" => redirect {|params, req| "http://bar.tld/#{params[:path]}"}, via: [:get, :post]
end
This does the job of the other answer. Though in addition, it preserves query strings as well. (Rails 4):
# http://foo.tld?x=y redirects to http://bar.tld?x=y
constraints(:host => /foo.tld/) do
match '/(*path)' => redirect { |params, req|
query_params = req.params.except(:path)
"http://bar.tld/#{params[:path]}#{query_params.keys.any? ? "?" + query_params.to_query : ""}"
}, via: [:get, :post]
end
Note: If you're dealing with full domains instead of just subdomains, use :domain instead of :host.
similar to other answers, this one worked for me:
# config/routes.rb
constraints(host: "foo.com", format: "html") do
get ":any", to: redirect(host: "bar.com", path: "/%{any}"), any: /.*/
end
The following solution redirects multiple domains on GET and HEAD requests while returning http 400 on all other requests (as per this comment in a similar question).
/lib/constraints/domain_redirect_constraint.rb:
module Constraints
class DomainRedirectConstraint
def matches?(request)
request_host = request.host.downcase
return request_host == "foo.tld1" || \
request_host == "foo.tld2" || \
request_host == "foo.tld3"
end
end
end
/config/routes.rb:
require 'constraints/domain_redirect_constraint'
Rails.application.routes.draw do
match "/(*path)", to: redirect {|p, req| "//bar.tld#{req.fullpath}"}, via: [:get, :head], constraints: Constraints::DomainRedirectConstraint.new
match "/(*path)", to: proc { [400, {}, ['']] }, via: :all, constraints: Constraints::DomainRedirectConstraint.new
...
end
For some reason constraints Constraints::DomainRedirectConstraint.new do didn't work for me on heroku but constraints: Constraints::DomainRedirectConstraint.new worked fine.
Bit more modern approach:
constraints(host: 'www.mydomain.com') do
get '/:param' => redirect('https://www.mynewurl.com/:param')
end
constraints(host: /subdomain\.domain\.com/) do
match '/(*path)' => redirect { |params, req|
"https://www.example.com#{req.fullpath}"
}, via: [:get, :head]
end
I use this when using custom domains on Heroku and I want to redirect from the myapp.herokuapp.com -> www.example.com.
I'm trying to write a catch-all route in Rails 3, but I want to reserve some terms in it. I'm specifically following the example put forth in this post, in the answer by David Burrows: Dynamic routes with Rails 3
The syntax I am using is the following:
match '*path' => 'router#routing', :constraints => lambda{|req| (req.env["REQUEST_PATH"] =~ /(users|my-stuff)/).nil? }
Now, that syntax works just fine - if a user visits a page with "user" or "my-stuff" in the path, it falls through the catch-all and goes to a specific place. If the user goes to any other URL, it goes to my routing logic.
My question is more about readability - is there a way I can match the route against something other than a regex? Is there a way to provide an array of terms to match against? Also, is there a way to match specific segments of the route, as opposed to the entire thing?
Obviously Rails has built-in routing, but this project has a requirement that for certain routes, the controller not be present in the URL. Hence, the catch-all.
Thanks for any help
Here's the updated routes file per the answer below:
class RouteConstraint
RESERVED_ROUTES = ['users', 'my-stuff']
def matches?(request)
!RESERVED_ROUTES.map {|r| request.path.include?(r)}.empty?
end
end
App::Application.routes.draw do
resources :categories
resources :sites
match '*path' => 'router#routing', :constraints => RouteConstraint.new
devise_for :users, :path_names =>{ :sign_in => 'login', :sign_out => 'logout', :registration => 'register' }
root :to => "router#routing"
end
You can use a class to specify the constraints if you want something cleaner once you have multiple routes to try:
class MyConstraint
BYPASSED_ROUTES = ['users', 'my-stuff']
def matches?(request)
BYPASSED_ROUTES.map {|r| request.path.include?(r)} .empty?
end
end
TwitterClone::Application.routes.draw do
match "*path" => "router#routing", :constraints => MyConstraint.new
end
This example is adapted from the rails routing guide.
It's taking a lambda; you can use whatever criteria you want.
First off, I'm using rails 3.0.8 with friendly_id 3.2.1.1.
I'd like to be able to view the posts at website.com/:title, so drop the "/posts".
But I'd also like to have an /admin view. From there, a user should be able to create/edit/destroy posts. I already have a admin.html.erb view with links to various actions.
Right now my routes file look like:
MyApp::Application.routes.draw do
root :to => 'posts#index'
resources :posts
match "/:id" => "posts#show"
match "/admin" => "posts#admin"
end
This works for website.com/:title, but for website.com/admin I get an error:
Couldn't find Post with ID=admin
.... which makes sense. But I'm not sure how to solve this problem.
The rules are run through top to bottom. So put your admin rule on top of the resource definition.
If you put /admin first then it will work (as noted by cellcortex). You can also use :constraints if you can neatly separate your :id from 'admin'; for example, if your :id values are numeric, then something like this should work:
match '/:id' => 'posts#show', :constraints => { :id => /\d+/ }
match '/admin' => 'posts#admin'
In a simple case like yours, putting things in the right order will work fine. However, if your routing is more complicated, then the :constraints approach might work better and avoid a some confusion and chaos.
Use this
resource :posts, :path => '/'
with this all of your article will be directly under root
So in Posts Class you may add this:
def to_param
"#{id}-#{title.parameterize}"
end