I have a Rails app that acts as a backend for an iOS app. It was developed by a third party, and I've never used Rails, so trying to learn as I go here. I want to make the app web-accessible for users, with a homepage front-end for giving prospective users some info about the app.
Sounds easy enough, but the app is using Devise for user authentication and when I hit the site root I get the following error message:
You need to sign in or sign up before continuing.
In the routes.rb file I have the following:
root :to => "visitors#index"
devise_for :users
resources :users
In my visitors controller I added a before_filter to try to open up the site index:
class VisitorsController < ApplicationController
before_filter :authenticate_user!, :except => [:index]
end
but this made no difference. Is there something obvious I'm missing here, or some concept that I'm not grasping? Basically I want a user to hit the site homepage, then click on a 'Login' link, after which they'll have access to the rest of the site.
EDIT:
My ApplicationController:
class ApplicationController < ActionController::Base
respond_to :html, :json
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :null_session, :if => Proc.new { |c| c.request.format == 'application/json'}
before_action :configure_permitted_parameters, if: :devise_controller?
acts_as_token_authentication_handler_for User
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :name
devise_parameter_sanitizer.for(:account_update) << :name
end
end
From Devise's how to guide which seems to describe your example. You can create two roots in your routes.rb file. One for authenticated user's and one for non-authenticated users:
authenticated :user do
root :to => 'visitors#some_action', :as => :authenticated_root
end
root :to => 'visitors#index'
However, please post your ApplicationController because your example code should work, the issue may be there.
In case anyone else has the same problem - the culprit was the following line in application_controller.rb:
acts_as_token_authentication_handler_for User
It's part of the simple_token_authentication Gem (https://github.com/gonzalo-bulnes/simple_token_authentication)
To fix enable anonymous access to the root page, I changed it to the following:
acts_as_token_authentication_handler_for User, :except => [:index]
Related
I want to allow authorized users to create (and destroy) user accounts. I have gotten this part working according to hints I found in this and other questions.
But I also want to prevent unauthorized users from creating and destroying accounts.
I have my own registration_controller:
class RegistrationsController < Devise::RegistrationsController
skip_before_action :require_no_authentication, only: [:new, :create, :destroy]
skip_before_action :authenticate_scope!, only: [:destroy]
before_action :authenticate_user!, only: [:new, :create, :destroy] # why doesn't this work?
def new
super
end
def sign_up(resource_name, resource)
# don't sign in as the new user
end
def destroy
User.find(params[:id]).destroy
redirect_to(users_path)
end
end
And have directed my routes to use it in routes.rb:
# Standard devise setup but allow registration when logged in
# https://stackoverflow.com/a/31946248/1404185
devise_for :users, controllers: {:registrations => "registrations"}
# Work around already-existing session controller
# https://stackoverflow.com/a/21024350/1404185
devise_scope :user do
post '/sessions/user', to: 'devise/sessions#create', via: :post
delete '/users/:id', to: 'registrations#destroy', via: :delete
end
# Show and index for users
# https://stackoverflow.com/a/32056094/1404185
resources :users, :only => [:show,:index]
For some reason before_action :authenticate_user! does not work... unauthenticated users can still invoke these actions. I've also tried prepend_before_action :authenticate_user!, and I've tried putting the filters in different orders-- invoking the before_action first in my controller.
I've just upgraded my app to rails 6.0.3.5 and added devise 4.7.1.
Why do I want this unusual setup? This is a hobby project and only my girlfriend and I are users. We don't want just anybody on the internet to sign up. But we occasionally may want to give another person access, who will be sitting next to us (pandemic permitting) when creating their account.
I do have a workaround for now: Since the site will have an obfuscated URL and since it is an extremely low value target (I can't imagine anyone would be interested in our home inventory) I simply don't provide a link to the signup page unless someone is logged in. This opens the possibility that a knowledgeable hacker could craft a request manually, but the risk is very very low.
But I still like to do things the "right" way, so I am asking this question. I have looked at devise_invitable but that seems way too complex for my needs.
UPDATE: One experiment I tried was instead of instead of inheriting from Devise::RegistrationsController and overriding methods, I just copied it to my registrations_controller and edited it. Then I deleted the :require_no_authenticaton and :authenticate_scope! prepend_before_actions and replaced them with prepend_before_action :authenticate_user!
This should eliminate doubt about whether the before_actions were being processed in the wrong order and ensure that only :authenticate_user! was being called.
The experiment failed. Apparently :authenticate_user! always returns true at this point whether or not a user is really authenticated. Why?
Apparently this has been an issue with devise for a long time.
The workaround is to change the before_action to:
prepend_before_action -> {authenticate_user!(force:true)}, only: [:new, :create, :destroy]
as suggested in this issue comment.
I am currently using https://github.com/thoughtbot/clearance
for authentication.
It allows me to sign-up & sign-in using password and email.
But I was wondering how I can configure it to have a CRUD pages for the generated users model, because I actually want to see a list of registered users.
You can use a regular Users controller, subclassed from clearance.
class UsersController < Clearance::UsersController
def index
#logged_in_users = User.where(blah) #whatever logic you need to retrieve the list of users
end
end
I created my Users controller first, then ran the clearance generator, and then the routes generator. After generating the default routes, you can modify to point to your own controller.
rails g clearance:install
rails g clearance:routes
resources :users, controller: "users" do
resource :password,
controller: "clearance/passwords",
only: [:create, :edit, :update]
end
get "/sign_in" => "clearance/sessions#new", as: "sign_in"
delete "/sign_out" => "clearance/sessions#destroy", as: "sign_out"
get "/sign_up" => "clearance/users#new", as: "sign_up"
I have a problem with the devise gem, I have this controller.
class AdminController < ApplicationController
before_action :authenticate_user!
def index
end
def per
end
def po
end
end
When redirect to sign_in form , shows nothing
sign_in form
These are my routes:
match 'po' => 'admin#po', :via => :get
match 'per' => 'admin#per', :via => :get
match 'admin' => 'admin#index', :via => :get
match 'admin/index' => 'admin#index', :via => :get
match 'admin/per' => 'admin#per', :via => :get
match 'admin/po' => 'admin#po', :via => :get
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
root 'home#index'
I have three templates: application, admin and home
I overwrite the default route after log in
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
#before_action :authenticate_user!
def after_sign_in_path_for(resource)
#request.env['omniauth.origin'] || stored_location_for(resource) || admin_path
admin_path
end
end
My last gem installed:
gem 'bootstrap-sass'
You need to run the generator for Devise views which will copy the necessary files in your views folder:
Run:
rails g devise:views
There is more information on configuring the Devise views here
Your problem probably isn't with Devise, it looks systemic to me.
#config/routes.rb
namespace :admin do
root "application#index" #->
resources :model_controller, path: "", only: :index do #-> url.com/admin/...
collection do
get :po #-> you shouldn't really have this
get :per #-> you shouldn't really have this
end
end
end
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
This will give you the following:
#app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ApplicationController
before_action :authenticate_user!
def index
# do something here
end
end
This gives you the ability to create a custom "dashboard" type page for your admin area, from which you'll be able to use controllers bound to models.
Your po and per actions really shouldn't be there - they are not part of the CRUD system
In regards to your Devise views, the other answers are correct in that you would be best to generate the Devise views in your app:
rails generate devise:views
This won't solve your problem (hence why I downvoted the other answers). It will simply put the views in your app. It will do nothing apart from put code in a different place.
You will need to debug the issue:
Check the action you're seeing at /users/sign_in
Check the code in the <body> tags (which you haven't shown)
If the HTML is there, there will be some other issue preventing it from loading
If there is no HTML, it will likely mean a problem with the core of Devise
What I would recommend you do is the following:
Generate your views
From your screenshot, show us the contents of the <body> tag
Screenshot your console log (this will show any errors)
Update your question with the above
This will give you a much clearer perspective on what the potential issue will be, and allow other community members to better define the solution.
I'm new to Rails. With rails running, opening localhost:3000 takes me to default "welcome aboard" page.
Rake routes command puts out a message that I don't have any routes defined, but I didn't change anything in config/routes.rb.
I tried to download back my github repository, but the problem persists. Any idea, please?
#MarcinAdamczyk, #RichPeck. I should say that localhost did work before. this is what I have:
1)
Pinteresting::Application.routes.draw do
resources :pins
devise_for :users
devise_for :installs
root "pages#home"
get "about" => "pages#about"
2)
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
def home
end
3)
class PagesController < ApplicationController
def home
end
def about
end
end
If you are using Rails <4 then you need to remove index.html from public folder and set root to: 'controller#method' in config/routes.rb
If its Rails 4 then only setting root route should be enough.
Routes
You'll need to change your routes to have the following:
#config/routes.rb
root "application#index"
You can then create & corresponding controller action:
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def index
end
end
#app/views/application/index.html.erb
Test
This should fix your immediate issue, judging from what you've posted.
I would like to do a new user signup via JSON but I get an invalid authenticity token error.
I would like to not turn the forgery check for all controller. Any suggestions on how to override the registrationcontroller to do this?
Here is my code:
class Api::MobileRegistrationsController < Devise::RegistrationsController
skip_before_filter :verify_authenticity_token
respond_to :json
def create
super
end
end
Routes:
Whitney::Application.routes.draw do
resources :apps
devise_for :users
namespace :api do
resources :tokens, :only => [:create, :destroy]
resources :MobileRegistrations, :only => [:create]
end
I get an error:
Routing Error
uninitialized constant Api::MobileRegistrationsController
I can't encourage you in this way, because your app will be vulnerable to CSRF attacks.
A good resource to understand CSRF : Understanding the Rails Authenticity Token
You should rather include the authenticity_token in your POST request. This is discussed in some questions on SO, like there (read all the answers) : rails - InvalidAuthenticityToken for json/xml requests
The idea :
Retrieve the token with <%= form_authenticity_token %>
Add a authenticity_token POST param to your request with the token.
If you pass the param by URI, don't forget to encoded the token value :
url += "&authenticity_token=" + encodeURIComponent( <%= form_authenticity_token %> );
You could buil your own controller that does not derive from a devise controller.
def UserSignupApiController < ApplicationController
skip_before_filter :authenticate_user!
respond_to :json
def create
#user = User.create(params[user])
respond_with(#user)
end
end
I think you get the idea. You just instantiate your User just like you would do in Rails console. I do not recommend this kind of practice though
For your error
Routing Error uninitialized constant
Api::MobileRegistrationsController
it indicates your controller is not in the correct folder.
Because you are using
namespace :api do
resources :tokens, :only => [:create, :destroy]
resources :MobileRegistrations, :only => [:create]
end
You need to put your MobileRegistrations into controllers/api folder. or you can use
scope "/api" do
resources :MobileRegistrations, :only => [:create]
end