How do I route based on a url parameter in sinatra? - ruby

I am using Sinatra and I want to use something like a referrer code in my urls that will somewhat control access and identify the provenance of a given URL.
/secret-code/rest/of/path
should be rejected if "secret-code" is not in a predetermined list.
I want to use route conditions
set(:valid_tag) { |tag| condition { tag === 'abcd' } }
get '/:tag', :valid_tag => params[:tag] do
'Hello world!'
end
but params is not in scope. Do I need to dispatch in the block? What is the best way to handle multiple routes without having to duplicate the tag checking logic in each one?
/secret/route1/
/secret/route1/blah
/secret/route2/
Is there a way to chain handlers? Can I do
get /:tag/*
# check :tag
redirect_to_handler(params[:splat])

By the sounds of things it looks like you're trying to make use of Sinatra's named parameters. Params is only in scope within the block:
get '/:secret_code/*' do
redirect_to_handler unless secret_codes.include? params[:secret_code]
end
The code above assumes you have a collection of 'secret_codes' that you're going to check with the secret_code from the URL.

(Answering my own question)
Sinatra matches the lexically first rule and you can pass onto the next matching rule using 'pass'. So something like this works as long as it is the first rule that would match.
get '/:tag/*' do
halt_if_bad_tag params[:tag]
pass
end
get '/:tag/route1' do
'hello world'
end

Related

How to remove the :id Part when doing a Concern

My routes file contains:
concern :generic_table do
get 'search_suggestions' => 'search_suggestions'
end
get 'human_resources/' => 'human_resources#index'
namespace :human_resources do
get 'settings/' => 'settings#index'
namespace :settings do
resources :constants do
concerns :generic_table
end
end
end
And it produces:
/human_resources/settings/constants/:constant_id/search_suggestions(.:format)
human_resources/settings/search_suggestions#search_suggestions
I am trying to remove the /:constant_id/ part and it point to the controller action:
human_resources/settings/constants/search_suggestions#search_suggestions
So in finality it would be
/human_resources/settings/constants/search_suggestions(.:format)
human_resources/settings/constants/search_suggestions#search_suggestions
How can I remove the /:constant_id/ part; and point it directly to my controllers action so my search bar my access the search suggestion for AJAX?
I think you just need to replace the resources block by a namespace one. It is the resources block that generates the parameter.
See also the member block if you need id instead of constant_id.
One extra point: This may not generate the route helpers you want. There are extra options to pass to namespace and related to tailor the helpers.

ruby middleware add stack adding middlware

I am trying to add/append middleware to the stack (in config.ru) on certain requests (where request.path == "/hi")
I was trying to do that with Rack::Builder
But i seem to fail at it.
Rack::Builder.new do
use added_middleware1
use added_middleware2
end.call(#env) if #request.path == "/something"
I am not sure if that makes my problem clear.
The #request variable should only be available when an actual request is happening, but the code you posted is probably getting run at configuration time when the server starts up. There is example code on the front page of the Rack::Builder documentation showing how to do something like you would want:
app = Rack::Builder.new {
use Rack::CommonLogger
use Rack::ShowExceptions
map "/lobster" do
use Rack::Lint
run Rack::Lobster.new
end
}
The stack should look more like this:
use CommonMiddleware
map '/something' do
use SpecialMiddleware
run TheApp.new
end
map '/' do
run TheApp.new
end
Alternatively, you could write a middleware that looks at the request path and runs the other special middleware as needed - sort of like a wrapper for it. The machinery would look something like this:
def initialize app, special_middleware
#app, #special_middleware = app, special_middleware
end
def call env
if route_matches?(env)
#special_middleware.new(#app).call(env) # assumes special_middleware initializer takes no extra parameters
else
#app.call(env)
end
end
def route_matches? env
# examine the rack environment hash, return true or false
end
And the config for using it would look like this:
use RouteMatchingMiddleware, SpecialMiddleware
run TheApp.new

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

Trouble creating custom routes in Ruby on Rails 3.1

I can't seem to set up a custom URL. All the RESTful routes work fine, but I can't figure out how to simply add /:unique_url to the existing routes, which I create in the model (a simple 4 character random string) and will serve as the "permalink" of sorts.
Routes.rb
resources :treks
match ':unique_url' => 'treks#mobile'
Controller
.
.
def mobile
#trek = trek.find(params[:id])
end
Is this because I'm trying to define a custom action on an existing resource? Can I not create custom methods on the same controller as one with a resource?
By the way, when I change routes.rb to match 'treks/:id/:unique_url' => treks#mobile it works fine, but I just want the url to simply be /:unique_url
Update It seems like find_by_[parameter] is the way to go...
I've been playing in console and I can't seem to get any methods to come forward...I can run Trek.last.fullname for example, but cannot run #trek = Trek.last...and then call...#trek.lastname for example. Any clues why? I think this is my issue.
So is there a field on Trek which stores its unique url? If so you should be doing something like this:
#trek = Trek.find_by_url(params[:unique_url])
trek.find_by_unique_url( params[:unique_url] ) # should do the trick
#pruett no, the find_by_XXX methods are generated on-the-fly via Ruby's method_missing call! So instead of XXX you can use any of the attributes which you defined in a model.
You can even go as far as listing multiple attributes, such as:
find_by_name_and_unique_url( the_name, the_unigue_url)
Check these pages:
http://guides.rubyonrails.org/active_record_querying.html
http://m.onkey.org/active-record-query-interface
if you get a undefined method ... for nil:NilClass , it means that the object you are trying to call that method on does not exist, e.g. is nil.
You probably just missed to put an if-statement before that line to make sure the object is non-nil
Hmm. I usually would do something like this:
map.connect "/:unique_url", :controller => "treks", :action => "mobile"
Then in that controller the ID isn't going to be applicable.. you'd need to change it to something like this:
def mobile
#trek = trek.find_by_unique_url(params[:unique_url])
end
(that's if unique_url is the column to search under)

Rails -- use RSpec "get" and "response" methods in Rake task

I know RSpec has useful methods "get" and "response.should" to run integration tests - I want to know how I can use these (or other methods to achieve the same result) in a Rake task:
desc "Check all content items with type 0 and do something"
task :my_task => :environment do
ContentItem.where("content_type = ?", 0).each do |obj|
get "/my_path/"+obj.value
if (response has a certain html tag)
perform some action on obj
end
end
end
I know that I can't just run rspec methods like that, but this is effectively what I need to do, and I need to be able to process information returned when /my_path/obj.value is opened. Does anyone have any suggestions?
why do you need to go through the url to do this action with your ContentItem ? Why not just use the local obj and do stuff?
Basically it looks like you're mixing up view-code with model code here... the model's object should not depend on values in the html... if there is some information being figured out in the view... put it into a method on the ContentItem model and call that code either from the view... or from this rake task.
Edit:
Ok.... well if you really need to GET a URL - look into Ruby's Net::Http gem - that will literally fetch URLs. Rails doesn't do that as standard... even for local URLs.
You might then be able to use a parser such as hpricot or nokogiri to parse the results to find the tag you need.

Resources