Global before filter in padrino - how is it done? - padrino

The padrino docs let you know how to do a before filter in the context of a controller, but I'm trying to do a global filter.
The problem I'm trying to solve is that my domain name should be forwarded to the www. version, but godaddy isn't doing it properly. So now I want to manually redirect in my code - and hence the global before filter.
Or should I be looking at 'middleware' instead?

Try to use rack-rewrite gem
In your config.ru add something like
require 'rack/rewrite'
use Rack::Rewrite do
r301 %r{.*}, 'http://www.your-domain.com$&',
:if => Proc.new { |rack_env| rack_env['SERVER_NAME'] != 'www.your-domain.com' }
end
Dont forget to include gem 'rack-rewrite' into your Gemfile.

First result in google http://logbook.route19.com/post/9018495987/sinatra-redirect-www-to-non-www
Just make the opposite of that link. Try something like that :
before do
redirect "www.#{request.url}" unless request.host =~ /^www/
end

I've added my global before filters to app.rb. Not sure if this is the correct way, but it works just the same as adding the before filter in my controller.
In your app.rb file
before do
# Code goes here
end

Related

Forward request using Rack & Faraday

I want to write a Rack app that forwards requests to a different domain. The Faraday gem might work well for this. Something like this would be nice:
My config.ru file:
...
my_app = lambda do |env|
conn = Faraday.new(env)
conn.url = "http://some-other-domain.com"
env.get? ? conn.get : conn.post
end
run my_app
Could it be this simple? Any ideas?
You might want to look at rack-rewrite (https://github.com/jtrupiano/rack-rewrite). You can use it to define and apply rewrite and redirect rules. A possible use of rack-rewrite that fits your use case is as follows:
require 'rack/rewrite'
use Rack::Rewrite do
r301 %r{.*}, 'http://mynewdomain.com$&', :if => Proc.new {|rack_env|
rack_env['SERVER_NAME'] != 'mynewdomain.com'
}
end
# rest of your app
The signature of a rewrite rule is rewrite_method(request_url_expression, rewrite_url_expression, options). In this example, the method #r301 will provide a permanent redirect for all request urls matching the given regex to the new domain with the request URI (using the $& substitution operator). There're info more in the documentation.

Rack middleware how to redirect to a view in my Rails application

In my Rails 3.1 app I created a Rack Middleware to verify access. If access is not approved user is to be redirected to a page. Specifically it will be a page I already have in my views. Suppose I am trying to redirect to dummy.html.erb with I have defined in my routes.rb as
match '/dummy', to :'page#dummy'
with page being my controller.
I've tried the following but I appear to be stuck in some redirect loop.
My Rack middleware located in /lib :
class AccessVerifier
def initialize(app)
#app = app
end
def call (env)
#....
#....do some type of verification here and redirect if fail verification
#....
[301, {"Location" => '/dummy', "Content-Type" => "text/html"}, []]
end
end
In application.rb I have
config.autoload_paths += %W(#{config.root}/lib)
config.middleware.use "AccessVerifier"
I also tried calling a controller in my middleware but again I am caught in some redirect loop. I called the controller from my middleware class like this:
def call (env)
...
status,headers,response=PageController.action("validateAccess").call(env)
end
and in my controller:
class PageController < ApplicationController
def validateAccess
redirect_to :controller => 'page', :action => "dummy"
end
...
end
I've seen redirecting done successfully without the use of Rack Middleware, for example only with controllers, but please note that I need to do this in middleware before my application is run.
The answer is so simple I felt silly. The problem is that when I redirect to somewhere say /dummy that in turns causes another pass through the Rack middleware and goes through my AccessVerifier code all over again which redirects to /dummy and does this over and over again thus causing the redirect loop. To fix it I force a stopping point by checking if the incoming path is included in the list of my stopping points(with /dummy being in that list) then stop. So an example in pseudo code
if path in ListOfAcceptableStoppingPoints
#app.call(env)
This fixes the redirect loop issue but now I am questioning if it would be better for my specific case to not use rake middleware as I have found that now I am filtering other things out such as assets. Sure I could try to go through and pick out everything I think I need to allow to go through but this seems too tedious and not correct. It seems like ultimately, I need to do my filtering at the rails level not at the rack level.
I don't have an answer off of the top of my head to directly answer your question. However, I would suggest using the cancan gem to handle authorization instead of creating a homegrown solution. See https://github.com/ryanb/cancan

Rails 3: How to intercept any http request

Lets say I have an image at app/assets/images/privateimages/myrestrictedimage1.jpg
If I try to go directly to the image via url say with something like
http://localhost:5555/assets/privateimages/myrestrictedimage1.jpg
I am able to view the image.
I would like to have a way to inspect any http request to decide if the user is allowed access to it.
I know I can use before_filter in controllers to do some preprocessing before continuing onto any of the controller actions but I dont think this will help me because I need to be attempting to do a controller action for this to take effect.
I have heard I might be able to do it with a rake task but after much searching I haven't found anything like what I am trying to do. Perhaps I have to create a ruby gem to do this but I have no clue how to do this.
Can anyone point me in the right direction? Thanks.
I used Rack Middleware
The middleware class looks like this:
class MyChecker
def initialize(app)
#app = app
end
def call(env)
if (docheck)
#do stuff here such as check the path.
#For example #path = env['PATH_INFO'] and compare against your okay paths
#if youre good and are able to continue then
#app.call(env)
else
#redirect such as
[301, {"Location" => /somewhere, "Content-Type" => "text/html"}, []]
end
end
end
make sure to make your middleware visible by adding the following to application.rb
class Application < Rails::Application
...
config.autoload_paths += %W(#{config.root}/lib) #if MyChecker is located in lib othewise substitute lib with wherever you have your middleware class
config.middleware.use "MyChecker"
end
You want to look at Rack (not rake).

How can I create a Rails 3 route that will match all requests and direct to one resource / page?

I have a rails app (Rails 3.0) that I need to temporarily take out of service. While this is in effect, I want to create a new route that will direct all requests to a single piece of static content. I have a controller set up to serve my static pages.
I tried something like this:
match '*' => 'content#holding'
and
match '*/*' => 'content#holding'
to match a wildcard route as described here:Rails 3 route globbing without success.
This is probably a really simple answer, but I couldn't figure it out.
/EDIT/
Forgot to mention that I did have this rule at the very top of my routes.rb file.
Rails needs to bind the url parameters to a variable, try this:
match '*foo' => 'content#holding'
If you also want to match /, use parenthesis to specify that foo is optional:
match '(*foo)' => 'content#holding'
I did this just yesterday and first came up with the solution that klochner shows.
What I didn't like about this is the fact that whatever you enter in the URL, stays there after the page loads, and since I wanted a catch all route that redirects to my root_url, that wasn't very appealing.
What I came up with looks like this:
# in routes.rb
get '*ignore_me' => 'site#unknown_url'
# in SiteController
def unknown_url
redirect_to root_url
end
Remember to stick the routes entry at the very bottom of the file!
EDIT:
As Nick pointed out, you can also do the redirect directly in the routes file.
I ran into something like this where I had domain names as a parameter in my route:
match '/:domain_name/', :to => 'sitedetails#index', :domain_name => /.*/, :as =>'sitedetails'
The key piece to this was the /.*/ which was a wildcard for pretty much anything. So maybe you could do something like:
match '/:path/', :to => 'content#holding', :path=> /.*/, :as =>'whatever_you_want'
Where in "routes.rb" is this line located?
To have priority over other routes, it has to be placed first.
As an alternative, you can look into this: http://onehub.com/blog/posts/rails-maintenance-pages-done-right/
Or this: Rails: admin-only maintenance mode

Get absolute (base) url in sinatra

Right now, I do a
get '/' do
set :base_url, "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
# ...
haml :index
end
to be able to use options.base_url in the HAML index.haml.
But I am sure there is a far better, DRY, way of doing this. Yet I cannot see, nor find it. (I am new to Sinatra :))
Somehow, outside of get, I don't have request.env available, or so it seems. So putting it in an include did not work.
How do you get your base url?
You can get it using request.base_url too =D (take a look at rack/request.rb)
A couple things.
set is a class level method, which means you are modifying the whole app's state with each request
The above is a problem because potentially, the base url could be different on different requests eg http://foo.com and https://foo.com or if you have multiple domains pointed at the same app server using DNS
A better tactic might be to define a helper
helpers do
def base_url
#base_url ||= "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}"
end
end
If you need the base url outside of responding to queries(not in a get/post/put/delete block or a view), it would be better to set it manually somewhere.

Resources