Rails understands GET request but not POST request - ruby-on-rails

When I access /users/registration/sign_up in my app via the browser (GET) a page renders. When I do the same thing via POST (either by submitting a form w/ the target /users/registration/sign_up or with ajax) my app returns the following error:
Unknown action
The action 'registration' could not be found for UsersController
I am using devise for authentication and creating a devise route for my User model using:
devise_for :users
This path should route to the devise/registrations_controller where i expect it to execute the new method (it currently does for a GET request). Maybe rails, understanding the request is a POST request automatically directs it to the create method but I don't think this is the issue because I start the debugger first thing in the create method and the debugger is not starting in my terminal before I receive this error.
Can anyone with experience with devise decipher what's going on? I'm happy to provide more info if necessary. Thanks.

Devise adds routes to your Rails app, which you can see by running rake routes from a terminal:
new_user_session GET /users/sign_in(.:format)
user_session POST /users/sign_in(.:format)
destroy_user_session GET /users/sign_out(.:format)
user_password POST /users/password(.:format)
new_user_password GET /users/password/new(.:format)
edit_user_password GET /users/password/edit(.:format)
PUT /users/password(.:format)
user_registration POST /users(.:format)
new_user_registration GET /users/sign_up(.:format)
edit_user_registration GET /users/edit(.:format)
PUT /users(.:format)
DELETE /users(.:format)
root /(.:format)
And as you discovered, there is a GET /users/sign_up but no POST /users/sign_up. When creating Devise expects POST /users, for which you can use the helper method user_registration_path. This gets handled by Devise::RegistrationsController#create.

Related

OAuth2::Error, invalid_request: redirect_uri does not match application configuration

I'm working on a rails app that authenticates using Bungie OAuth using this gem. My configurations in initializers/devise.rb are as follows:
config.omniauth :bungie, ENV['CLIENT_ID'], ENV['CLIENT_SECRET'], ENV['X_API_KEY'], ENV['REDIRECT_URL']
Bungie's developer portal requires a redirect URL with HTTPS, so I've pushed my application to Heroku and used a redirect to force authentication back to localhost for testing. Using this method, everything works fine. However, when I push the app to production, the response back to my application from Bungie fails with OAuth2::Error, invalid_request: redirect_uri does not match application configuration. The redirect_url is the exact same thing in both my application's env variables and on Bungie's development portal.
Seeing as it's in production, I'm limited to the logs that I can see. I've tried tracking the requests in the network tab of the dev tools in my browser, but everything looks as it should.
I've tried working with the developer of the bungie-oauth2 gem, but we have not been able to come to a resolution (and his prod apps work fine with it).
Is there anything that might cause the redirect_url to differ once in Heroku?
As requested, here is my route for omniauth:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
Output from rake routes:
users_sign_out GET /users/sign_out(.:format) devise/sessions#destroy
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_bungie_omniauth_authorize GET|POST /users/auth/bungie(.:format) users/omniauth_callbacks#passthru
user_bungie_omniauth_callback GET|POST /users/auth/bungie/callback(.:format) users/omniauth_callbacks#bungie
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
and my controller:
def bungie
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
#user.remember_me = true
sign_in_and_redirect #user, :event => :authentication
else
session["devise.bungie_data"] = request.env["omniauth.auth"]
redirect_to root_path
end
end
Full source can be found at https://github.com/destiny-aviato/destinder.
Encoding of redirect_uri param in your auth request to bungie jumps out:
https%25253A%25252F%25252Fdestinder.herokuapp.com%25252Fusers%25252Fauth%25252Fbungie%25252Fcallback
To read it in plain, I had to decode it thrice. Normally params are encoded just once
URI.decode(URI.decode(URI.decode("https%25253A%25252F%25252Fdestinder.herokuapp.com%25252Fusers%25252Fauth%25252Fbungie%25252Fcallback")))
Not sure if this is what causing the issue. Can you check how many times request_uri gets encoded when you hit it from local. If it's less than 3, then during heroku deployment your request_uri gets encoded one extra time.
To get request_uri for local, logout from bungie, click on "Sign in with bungie" on your local. The url in browser would have request_uri.
replace redirect url of your Heroku application in credential

Redirecting after sign in with Devise

I know this question has been asked quite a few times, but somehow it's not working for me. I would like the user to be redirected to a specific page after log in (using Devise). I'm using Rails 3.2 and Ruby 4.
As it is the user get redirected to:
- After login they get redirected to the root, if the user got to the login page from one of the pages controlled by the controller of which the root path is part of. These pages do not require authorization.
- After login they get redirected to the requested page, if the user automatically got to the login page by clicking on a page that requires authorization.
To redirect the user after login to a specific page, I understand that you need to add to the controller some lines. To the controller that is controlling the pages that required authorization I added:
class AccountsController < ApplicationController
before_filter :authenticate_user!
def user1_home
end
def user2_home
end
def user3_home
end
protected
def after_sign_in_path_for(resource)
'accounts/user1_home'
end
end
However, this didn't change anything. I also tried it with def after_sign_in_path_for(resource) 'accounts#user1_home_path' end
Should I perhaps also change something in routes.rb?
My routes are:
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
user_confirmation POST /users/confirmation(.:format) devise/confirmations#create
new_user_confirmation GET /users/confirmation/new(.:format) devise/confirmations#new
GET /users/confirmation(.:format) devise/confirmations#show
toc GET /toc(.:format) pages#toc
stakeholder GET /stakeholder(.:format) pages#stakeholder
about GET /about(.:format) pages#about
doelgroep_onderneming GET /doelgroep_onderneming(.:format) pages#doelgroep_onderneming
doelgroep_ngo GET /doelgroep_ngo(.:format) pages#doelgroep_ngo
doelgroep_se GET /doelgroep_se(.:format) pages#doelgroep_se
partnership GET /partnership(.:format) pages#partnership
contact GET /contact(.:format) pages#contact
account_stakeholder GET /account/stakeholder(.:format) accounts#stakeholder_home
account_business GET /account/business(.:format) accounts#business_home
account_admin GET /account/admin(.:format) accounts#admin_home
root / pages#index
You definitely shouldn't be defining methods per user in the Accounts controller.
Devise has instructions on github for accomplishing this: https://github.com/plataformatec/devise/wiki/How-To:-redirect-to-a-specific-page-on-successful-sign-in
You need to move after_sign_in_path_for to the ApplicationController class and you shouldn't have 'accounts/user1_home'. To go to the right url for each use you should have something along the lines of user_path(#user) but I don't have enough of your code to know exactly what to use. You should run in a console window the rake routes command to see what you routes you have made available. Read more about routing at: http://guides.rubyonrails.org/routing.html
Yes. Set the following at any point (before or after login):
session["user_return_to"] = request.original_url # Will redirect the user to where they came from
If it's an authenticated page they tried to access before logging in you want to redirect to then you can simply do it this way in your ApplicationController:
def after_sign_in_path_for(resource)
if session[:user_return_to] == nil
your_actual_next_path
else
super
end
end

Rails: What's the logic 'behind' the Devise form.submit button?

I'm trying to get to grips with Rails and I'm stuck on getting an 8 question multi-choice question quiz working.
I think I understand the MVC side of things. Requests from the browser come through a controller. It asks for info from models, sends it to the views and returns the content to the browser (please correct me if I'm wrong).
I DON'T understand (very clearly, at least) how pages 'know' where to link to. I think, when you generate a resource, you're given a plethora of routes mapped to paths. I don't understand when those paths are relevant.
Could someone please explain to me (step-by-step, if necessary) how the submit button in a Devise form 'knows' where to link to?
My form, so far, looks like this:
<%= form_for([current_user]) do |f| %>
<p>
<%= f.check_box :quiz_answers %>
</p>
<p>
<%= f.submit("Get my results!") %>
</p>
<% end %>
I see nothing in there that NAMES a path or a route. How, then, is the link generated?
I have checked rake routes, but I don't think I'm appreciating what is significant about that list. If someone could explain the MEANING behind it, that would be great.
I will try to explain it.
There are several types of methods that you can send through web page:
-GET
-POST
-DELETE
-PUT
Get sends parameters through link. you can see its parameters in URL, for instance www.google.ba?you_are=user, you_are is parameter and its value is user.
Post sends parameters through package so you can't see anything in the url, yet informations are there.
Other methods are variations for POST method for restful service.
For your question, devise creates by default some routes that are not clearly visible in routes.rb. Any request that comes across your webpage goes to the routes.rb, checks where should it be delegated then send that to corresponding controller. Controller then takes parameters do some logic(delegates it to services and other things), prepares models for show and then delegates it to template. Then, template with all informations(rendered) is sent to web browser.
There is one thing to mention, resource or devise creates default actions for every method for corresponding action. In this case you just need to set model and it knows where to delegates it.
Here are my routes for devise ( some of them are custom):
new_user_session GET /users/sign_in(.:format) user_sessions#new
user_session POST /users/sign_in(.:format) user_sessions#create
destroy_user_session DELETE /users/sign_out(.:format) user_sessions#destroy
user_password POST /users/password(.:format) passwords#create
new_user_password GET /users/password/new(.:format) passwords#new
edit_user_password GET /users/password/edit(.:format) passwords#edit
PATCH /users/password(.:format) passwords#update
PUT /users/password(.:format) passwords#update
cancel_user_registration GET /users/cancel(.:format) users#cancel
user_registration POST /users(.:format) users#create
new_user_registration GET /users/sign_up(.:format) users#new
edit_user_registration GET /users/edit(.:format) users#edit
PATCH /users(.:format) users#update
PUT /users(.:format) users#update
DELETE /users(.:format) users#destroy
user_confirmation POST /users/confirmation(.:format) confirms#create
new_user_confirmation GET /users/confirmation/new(.:format) confirms#new
GET /users/confirmation(.:format) confirms#show
Use rake routes command in terminal to find out all your routes.

Ruby on Rails - Should I separate the dashboard for each use type or just have one?

I'm setting up my first rails application and I have a question for an experienced developer. I use devise for my user authentication system. I'm not up on the verbiage yet, so forgive me.
The user will have a dashboard when they log in. Is it better to use the generate scaffold tool to setup a single controller for the dashboard (and use if statements to differentiate), or create the dashboard page under the /students and /teachers (having two separate controllers)?
I'm looking to avoid wasting time or having to backtrack my application if I notice one method won't allow me to achieve something down the road. I'm leaning towards separating them.
Here is my rake routes for you to see how I've got stuff setup so far:
rake routes
Prefix Verb URI Pattern Controller#Action
landing_index GET /landing/index(.:format) landing#index
new_teacher_session GET /teachers/sign_in(.:format) devise/sessions#new
teacher_session POST /teachers/sign_in(.:format) devise/sessions#create
destroy_teacher_session DELETE /teachers/sign_out(.:format) devise/sessions#destroy
teacher_password POST /teachers/password(.:format) devise/passwords#create
new_teacher_password GET /teachers/password/new(.:format) devise/passwords#new
edit_teacher_password GET /teachers/password/edit(.:format) devise/passwords#edit
PATCH /teachers/password(.:format) devise/passwords#update
PUT /teachers/password(.:format) devise/passwords#update
cancel_teacher_registration GET /teachers/cancel(.:format) devise/registrations#cancel
teacher_registration POST /teachers(.:format) devise/registrations#create
new_teacher_registration GET /teachers/sign_up(.:format) devise/registrations#new
edit_teacher_registration GET /teachers/edit(.:format) devise/registrations#edit
PATCH /teachers(.:format) devise/registrations#update
PUT /teachers(.:format) devise/registrations#update
DELETE /teachers(.:format) devise/registrations#destroy
new_student_session GET /students/sign_in(.:format) devise/sessions#new
student_session POST /students/sign_in(.:format) devise/sessions#create
destroy_student_session DELETE /students/sign_out(.:format) devise/sessions#destroy
student_password POST /students/password(.:format) devise/passwords#create
new_student_password GET /students/password/new(.:format) devise/passwords#new
edit_student_password GET /students/password/edit(.:format) devise/passwords#edit
PATCH /students/password(.:format) devise/passwords#update
PUT /students/password(.:format) devise/passwords#update
cancel_student_registration GET /students/cancel(.:format) devise/registrations#cancel
student_registration POST /students(.:format) devise/registrations#create
new_student_registration GET /students/sign_up(.:format) devise/registrations#new
edit_student_registration GET /students/edit(.:format) devise/registrations#edit
PATCH /students(.:format) devise/registrations#update
PUT /students(.:format) devise/registrations#update
DELETE /students(.:format) devise/registrations#destroy
root GET / landing#index
So again, do you think it's better to have both the student's dashboard and the teacher's dashboard be separate, or just have one dashboard and use if statements to differentiate based on the user's type (using 0 & 1 to indicate whether they are a student or teacher)?
Thanks in advance!
If the data that you want to display to each type of user are similar, you could use the same controller and load different partials based on the type of the user.

Installing Active Admin and getting an ArgumentError

I'm trying to use ActiveAdmin for my first time w/ Rails 4. Upon installing all dependent gems, I try to run the installer, i.e.:
rails generate active_admin:install
Doing so gives me the following error:
in `add_route': Invalid route name, already in use: 'admin_root' (ArgumentError)
However, I don't have any 'admin_root' route in routes.rb so I'm a little confused. Here's the output from running 'rake routes':
Prefix Verb URI Pattern Controller#Action
exams GET /exams(.:format) exams#index
POST /exams(.:format) exams#create
new_exam GET /exams/new(.:format) exams#new
edit_exam GET /exams/:id/edit(.:format) exams#edit
exam GET /exams/:id(.:format) exams#show
PATCH /exams/:id(.:format) exams#update
PUT /exams/:id(.:format) exams#update
DELETE /exams/:id(.:format) exams#destroy
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session GET /users/sign_out(.:format) devise/sessions#destroy
user_password POST /users/password(.:format) devise/passwords#create
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
user_registration POST /users(.:format) devise/registrations#create
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
root GET / composer#index
home GET /home(.:format) home#index
GET /exam_db/:exam_name/:chapter_name/:topic_name/:item_name(.:format) exam_db#gateway
exam_db_gateway GET /exam_db/gateway(.:format) exam_db#gateway
Here's the full error:
gems/actionpack-4.0.0/lib/action_dispatch/routing/route_set.rb:409:in `add_route': Invalid route name, already in use: 'admin_root' (ArgumentError)
You may have defined two routes with the same name using the `:as` option, or you may be overriding a route already defined by a resource with the same naming. For the latter, you can restrict the routes created with `resources` as explained here:
Also worth noting, if I decide to skip the Devise user class altogether, it works:
rails generate active_admin:install --skip-users
The only problem is, I'm not sure how to configure 'config/initializers/active_admin.rb' if I skip the Devise user class?
Any thoughts as to why this might be happening?
I had the same error when upgrading to rails 4 with ActiveAdmin and it turned out this line was repeated twice in my routes.rb: ActiveAdmin.routes(self) I removed the second instance and the error went away.
In addition to Andre's answer - as a result of the error the assets weren't installed properly. You'll have to run rails g active_admin:assets to get the js/css assets installed in the pipeline.

Resources