all, i need to do this as the following
require 'sinatra'
require 'app_env'
get '/home' do
'home page'
end
get '/about' do
'about page'
end
get '/docs' do
'docs page'
end
I not sure which route will be the root route, maybe the home, about, or docs page. So, i have to set the root page in a file app_env.rb with a line like this route_map '/home' => '/' .
Now, how do i write the method/function route_map
or anything else to implement my requirement for mapping the route dynamically.
EDIT : MY ANSWER
HOMEPAGE = '/home_page'
get '/' do
status, headers, body = call! env.merge("PATH_INFO" => HOMEPAGE)
end
If you are looking to reroute requests for '/' to '/home' then all that you need to do is:
get '/'
redirect '/home'
end
If you do not want to redirect you could do this:
get '/foo' do
status, headers, body = call env.merge("PATH_INFO" => '/bar')
[status, headers, body.map(&:upcase)]
end
get '/bar' do
"bar"
end
See this for details.
Related
I’m using Ruby 2.3 with Rails 5. If someone visits the login page in my application and they are already signed in, I want to redirect them to their user home page. However, following this link — Redirect user after log in only if it's on root_path, I can’t get it to work. I added these to my config/routes.rb file
root :to => "users/", :constraints => {user_signed_in?}
root :to => redirect('/login')
And I created the file lib/authenticated_user.rb with this content
class AuthenticatedUser
def self.matches?(request)
user_signed_in?
end
end
However, when I visit my root page, I get this error
/Users/nataliab/Documents/workspace/sims/config/routes.rb:17: syntax error, unexpected '}', expecting =>
root :to => "users/", :constraints => {user_signed_in?}
What else do I need to do to get this working?
Edit: This is my complete config/routes.rb file, edited after the answer given
Rails.application.routes.draw do
get '/signup', to: 'users#new'
get '/forgot_password', to: 'users#forgot_password'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
get '/dashboard' => 'users#show', as: :dashboard
resources :users
resources :scenarios do
get :download
resources :confidential_memos
end
resources :scenario_files, :only => %i[ show ]
root :to => "/dashboard", constraints: lambda { |user| user.user_signed_in? }
root :to => redirect('/login')
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
I have this defined in app/helpers/sessions_helper.rb
def current_user
#current_user ||= User.find_by(id: session[:user_id])
end
# Returns true if the user is logged in, false otherwise.
def logged_in?
!current_user.nil?
end
Your basic problem is that you are providing a Boolean within braces which is invalid syntax. Braces signify either a hash or a block. The Rails Routing Guide section 3.10, available here, explains what you probably want to do. There are other options within section 3 that might provide a solution.
Per the guide, and the information you provided, one solution would be
root :to => "users/", constraints: lambda { |request| user_signed_in?(request) }
Depending upon your security solution, this has the concern that the user_signed_in? method must be available and it must be able to identify the user using the HTTP request.
EDIT:
I worked with your route table, making changes to it until Rails liked it. It didn't like the leading slash and it didn't like having two root paths, even with the constraint. Here is a recommended configuration, though you might need to modify it to make sure that it is doing exactly what you want:
get 'signup', to: 'users#new'
get 'forgot_password', to: 'users#forgot_password'
get 'login', to: 'sessions#new'
post 'login', to: 'sessions#create'
delete 'logout', to: 'sessions#destroy'
get 'dashboard' => 'users#show', as: :dashboard
resources :users
resources :scenarios do
get :download
resources :confidential_memos
end
resources :scenario_files, :only => %i[ show ]
get '/', to: 'users#show', constraints: lambda { |request| user_signed_in?(request) }
root :to => redirect('/login')
This has the concerns I mentioned above in that the user_signed_in? method must be available and it must be able to identify the user using the HTTP request.
Recommendation:
root to: 'sessions#check'
And there:
def check
if logged_in?
return redirect_to user_profiles_path
else
# You could execute the new method here, or:
return redirect_to user_login_path
end
end
This is not exactly RESTful, and it could instead be integrated into sessions#new if you would rather do that.
Alternate, based on Duyet's suggestion:
root to: 'sessions#new'
And, then in sessions only:
before_action :user_authenticated, only: [:new]
def user_authenticated
if logged_in?
return redirect_to user_profiles_path
end
end
If you are using gem devise. There 2 ways to do it.
Solution 1: Config your routes.rb
devise_scope :user do
authenticated :user do
root "users#profiles", as: :authenticated_root
end
unauthenticated do
root "users#login", as: :unauthenticated_root
end
end
Note: The path maybe not correct. Just idea.
Solution 2: Use method after_sign_in_path_for of devise. Reference to it at here
Update1
Could you try to add new method on application.rb
before_action :user_authenticated
def user_authenticated
if logged_in?
return redirect_to user_profiles_path
else
return redirect_to user_login_path
end
end
Update 2
NOTE:
If you add method user_authenticated to application.rb, all page will require user login. If you don't want that. Just add that to which controller/action you want.
Another way: Could u show code of method check user authenticate? I think you can add a redirect link at that.
I'm trying to make a single page website with sinatra in the backend. I want all GET-requests with preferred accept-header "text/html" to return the same page, BUT all requests that wants json to get json-data.
Example:
A GET call to '/users' with accept set to 'text/html' should return index.html.
A GET call to '/users' with accept set to 'application/json' should return the JSON-data with users.
I have tried using a catch-all method for html and using accept-checks like this:
# Generic html giver for angular routing
get //, :provides => 'html' do
pass unless request.preferred_type.to_str == 'text/html'
erb :index
end
# Give users as JSON
get '/users', :provides => 'json' do
pass unless request.preferred_type.to_str == 'application/json'
'["dummy", "array"]'
end
...but it doesn't seem to pass to the second route when preferred_type isn't text/html.
Note: I'm useing the string check on preferred_type, since using request.accept? catches all with browsers giving "*/*" as last accept header.
Oh, it seems like the culprit is:
:provides => 'json'
Without it, the passing works as expected. I guess it's a bug then.
Working on building an API and would like to use RESTful routes.
I got it to work just fine like this:
http://www.mysite.com/events.json // returns json results with my events
http://www.mysite.com/events/123.json // returns json results with event of id '123'
BUT - I want to be able to do this using an 'api' prefix.
So, I added the api Routing prefix:
Configure::write('Routing.prefixes', array('admin', 'api'));
And changed my actions from 'view' and 'index' to 'api_view' and 'api_index'.
But now it doesn't work. (eg. I have to write the action name or it won't find the correct one based on HTTP.
The end goal would be to be able to do something like this:
GET http://www.mysite.com/api/1.0/events.json // loads events/api_index()
GET http://www.mysite.com/api/1.0/events/123.json // loads events/api_view($id)
DELETE http://www.mysite.com/api/1.0/events/123.json // loads events/api_delete($id)
...etc
I ended up having to just write the routes manually:
Router::parseExtensions('json', 'xml');
Router::connect('/api/:version/:controller/:id/*',
array('[method]'=>'GET', 'prefix'=>'api', 'action'=>'view'),
array('version'=>'[0-9]+\.[0-9]+', 'id'=>'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'));
Router::connect('/api/:version/:controller/*',
array('[method]'=>'GET', 'prefix'=>'api', 'action'=>'index'),
array('version'=>'[0-9]+\.[0-9]+'));
Router::connect('/api/*', array('controller'=>'events', 'action'=>'index', 'ext'=>'html'));
Notes:
The [method] is what forces the HTTP type (eg. RESTful)
The parseExtensions() makes it so you can have it display the data in different formats automatically by changing the extension in your URL.
The last Router:: line was just a catchall for anything /api/ that didn't match - it forwarded it to the homepage. Eventually I'll probably just route this to an API error page.
The 'ext'=>'html' of the last Router:: line was to keep parseExtensions from trying to use whatever extension was in the URL - if it's redirecting for reasons they made the call wrong, I just want it to go back to the homepage (or whatever) and use the normal view.
Try something like this.
Router::connect('/:api/:apiVersion/:controller/:action/*',
array(),
array(
'api' => 'api',
'apiVersion' => '1.0|1.1|'
)
);
With prefix routing
Router::connect('/:prefix/:apiVersion/:controller/:action/*',
array(),
array(
'prefix' => 'api',
'apiVersion' => '1.0|1.1|'
)
);
Will match only valid API versions like 1.0 and 1.1 here. If you want something else use a regex there.
I know this is an old post, but there is a routing method called mapResources which creates the special method based routing for you.
http://book.cakephp.org/2.0/en/development/rest.html
You put it in routes.php like so:
Router::mapResources(array('controller1', 'controller2'));
The docs have a nice little table showing how the requests are mapped to different actions, which you can always override if you need to.
How to redirect user defined error page for not found and server error pages to user define page Mojolicious lite
You can add a template for your custom page named exception.html.ep or not_found.html.ep at the end of your liteapp.
For example:
use Mojolicious::Lite;
get '/' => sub {
my $self = shift;
$self->render(text => "Hello.");
};
app->start;
__DATA__
## not_found.html.ep
<!DOCTYPE html>
<html>
<head><title>Page not found</title></head>
<body>Page not found <%= $status %></body>
</html>
For a reference, see the Mojolicious rendering guide.
The renderer will always try to find exception.$mode.$format.* or
not_found.$mode.$format.* before falling back to the built-in default
templates.
I wanted to run some code in my 404 page so borrowing from here
https://groups.google.com/forum/#!topic/mojolicious/0wzBRnetiHo
I made a route that catches everything and placed it after all my other routes, so urls that don't match routes fall through to this:
any '/(*)' => sub {
my $self = shift;
$self->res->code(404);
$self->res->message('Not Found');
# 404
$self->stash( {
# ... my stuff in the stash ...
} );
$self->render('mytemplate', status => 404);
};
I had an API that wanted to send back 404 errors as it would any other error—same JSON format and whatnot.
I had this snippet at the end of startup (full app, not lite). Since this is the last defined route, it only picks up anything not already handled. And, since this handles all that, Mojo never gets the chance to use its own 404 handling by looking for templates:
$self->routes->any('/*')->to(
controller => 'Base',
action => 'not_found'
);
I have a simple Sinatra proxy, which when an endpoint is called, will redirect to another endpoint on the same Sinatra proxy.
When I make a request with a header, the proxy doesn't seem to pass this header through to the second endpoint when the request redirects in the first. This is my code:
get '/first' do
# get the header from the request
username = env['HTTP_USERNAME']
# set the header for the response
response['username'] = username
redirect '/second'
end
get '/second' do
# This doesn't exist when redirected from /first
puts env['HTTP_USERNAME']
# Here is a list of all headers
env.each_key do |key|
puts "KEY: #{key} VALUE: #{env[key]}" unless key.nil?
end
"DONE"
end
Any tips would be greatly appreciated.
Thanks
That is intentionally. redirect triggers an HTTP redirect, a new request will be fired. Also, passing on env values is done via modifying env, not response.
The main question is, what do you mean by header? Request header or response header? From your example I figure you mean request header, therefore response['username'] = username should be request.env['username'] = username. You could then replace redirect '/second' with request.path_info = '/second'; pass to do some sort of internal redirect. If you don't pass the value on to another Rack middleware/endpoint, you could also store the user name in an instance variable.
get '/first' do
request.path_info = '/second'
pass
end
get '/second' do
puts request.env['HTTP_USERNAME']
"DONE"
end