1

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
Community
  • 1
  • 1
  • https://github.com/plataformatec/devise – Julius Dzidzevičius Dec 15 '16 at 17:34
  • @Natalia See my modified answer with the updated route table. – Richard_G Dec 15 '16 at 18:46
  • @Natalia I knew something was bothering me. The constraint's lambda block is going to pass the HTTP request and not the user. You will need to code the user_signed_in? method to identify the user and user's status based on the request. I updated the answer to correct that issue. – Richard_G Dec 15 '16 at 19:16
  • @Natalia That last change makes this complicated. I know you are not using Devise. Are you using a gem and which one? It might present a rationale solution. Alternatively, send root in all cases to a controller#action where you can actively check for the user's status and redirect appropriately. – Richard_G Dec 15 '16 at 19:43
  • @Natalia Please see my edit within two answers. The second one, labeled alternate, is a version based on Duyet's recommendation. I think that alternative is good. – Richard_G Dec 16 '16 at 13:13

2 Answers2

0

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.

Duyet Nguyen
  • 543
  • 3
  • 11
  • I'm not using devise. Given that, how would I do what I was intending? –  Dec 11 '16 at 18:31
  • oh, i just asked on other comment are u using Devise? :) So if not, you must construct your own authentication system. I would suggest to use Devise - easy peasy – Julius Dzidzevičius Dec 15 '16 at 17:21
  • I see. I have current_user defined in a "app/helpers/session_helper.rb" file. Is that of any value? –  Dec 15 '16 at 18:20
  • @DuyetNguyen I like the idea, but I believe there is a flaw. With this code in application.rb, it will affect every request of any sort to any controller. It will not be isolated to the root path. Even isolating to or away from any controller will not have the desired result. Root needs routed to a controller#action, such as the sessions controller. – Richard_G Dec 16 '16 at 12:56
0

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
Richard_G
  • 4,700
  • 3
  • 42
  • 78
  • Thanks, but now I'm getting an error, "Missing :controller key on routes definition, please check your routes.". This might be a separate issue so I'll open a separate question about it. –  Dec 15 '16 at 15:20
  • @Natalia Please post the new code here as well so I can take a look. Thanks. OBTW, you can just edit the original post to add it. – Richard_G Dec 15 '16 at 15:38
  • @R_G, I added teh line just as you have it, 'root :to => "users/", constraints: lambda { |user| user.user_signed_in? }' and got the error. However, I also tried '/dashboard', since that's the normal URL I use and got teh smae error. I put my complete config/routes.rb file in my question. –  Dec 15 '16 at 17:30
  • but if u are you not using Devise you can not use its methods, like `user_signed_in?` – Julius Dzidzevičius Dec 15 '16 at 17:32
  • @J.D. Well, that's not hardly necessarily so. In one of my largest applications, I don't use Devise because I didn't need its complexity. I happen to use Sorcery. Even so, a developer can produce the same functionality without the use of any gem whatsoever, should they so choose of course. The OP showed user_signed_in? on the users path and that is the base we are addressing. – Richard_G Dec 15 '16 at 18:24
  • Oh, u are right... I wasn't aware of that you define it in your route... My bad. Apologies... – Julius Dzidzevičius Dec 15 '16 at 19:48
  • True I'm not using devise -- I have a helpers file, app/helpers/sessions_Helper.rb in which I define a "logged_in?" function. I thought I coudl replace user_signed_in? withi SessionsHelper.logged_in? but when I do that I get an error, "undefined method `logged_in?' for SessionsHelper:Module". –  Dec 15 '16 at 21:22
  • @Natalia Helpers are generally available in views and that's their function. What I would do would be to route root to a controller#action, check there and redirect as appropriate. – Richard_G Dec 15 '16 at 21:27