I set up twitter login system and got the error message above around the codes
redirect_to member_path(session[:user_id]), :notice => "#{auth["info"]["name"]}さんの#{auth["provider"]}アカウントと接続しました。"
in the def callback of the sessions_controller.rb. I wonder why this happened because it never happened when I set up facebook login with omniauth gem.Could you tell me why this occurred and how to solve this?
I checked some elements. A new user was created through twitter login. And I could get "session". But couldn't acquire session[:user_id].
☆member.rb
def self.create_with_omniauth(auth)
create! do |member|
member.provider = auth["provider"]
member.uid = auth["uid"]
member.mail = auth["mail"]
member.image = auth["info"]["image"]
if member.provider == "facebook"
member.name = auth["info"]["name"]
else
member.name = auth["info"]["nickname"]
end
end
end
☆sessions_controller
def callback
#omniauth.auth環境変数を取得
auth = request.env["omniauth.auth"]
#Userモデルを検索
member = Member.find_by_provider_and_uid(auth["provider"], auth["uid"])
if member
# 既存のユーザ情報があった場合ルートに遷移させます
session[:user_id] = member.id
redirect_to member_path(session[:user_id]), :notice => "ログインしました。"
else
# Userモデルに:providerと:uidが無い場合(外部認証していない)、保存してからルートへ遷移させる
Member.create_with_omniauth(auth)
redirect_to member_path(session[:user_id]), :notice => "#{auth["info"]["name"]}さんの#{auth["provider"]}アカウントと接続しました。"
end
end
Your problem is that you try to build a member route which requires id for member. Other words Rails should build routes like /members/:id where id MUST be a number. When you pass session[:id] (which is nil!) to the route helper member_path you get an error.
What to do?
1) (if you use a gem for authentication, for example devise) you can pass to the route helper current_user: memeber_path(current_user)
2) if you have own method which authenticate user you can set session[:user_id] youself.
I suppose that the problem is in else-block. So you can define session[user_id] after a new Member is created. I hope that method Member.create_with_omniauth(auth) return a new member - it means that you need take its id
if member
# 既存のユーザ情報があった場合ルートに遷移させます
session[:user_id] = member.id
redirect_to member_path(session[:user_id]), :notice => "ログインしました。"
else
# Userモデルに:providerと:uidが無い場合(外部認証していない)、保存してからルートへ遷移させる
session[:user_id] = Member.create_with_omniauth(auth).id # <--- UPDATED PART IS HERE
redirect_to member_path(session[:user_id]), :notice => "#{auth["info"]["name"]}さんの#{auth["provider"]}アカウントと接続しました。"
end
PS
And anyway you can avoid to render/redirect to this route if session[:user_id] is nil
redirect_to member_path(session[:user_id]) if session[:user_id]
Related
I have recently started learning rails and had to develop an application with three roles: user(admin), student, instructor. I wrote the following code myself. but the problem is that it makes the role of all active users similar to the most recent login. For example, if admin was logged in and later a student logs in and then if admin refreshes her page, she will also become a student. What i should change in my code to fix this problem? And if it is not possible to implement it like this way, suggest me how i should fix this problem. thanks.
here is my users_controller code:
def login
if session[:user_id]!=nil
redirect_to(:action => 'index')
end
end
def attempt_login
if params[:username].present? && params[:password].present?
found_user = User.where(:username => params[:username]).first
if found_user
authorized_user = found_user.authenticate(params[:password])
if authorized_user
flash[:notice] = "Welcome! You are LoggedIn"
session[:user_id] = authorized_user.id
redirect_to(:action => 'index')
return
end
end
found_student = Student.where(:username => params[:username]).first
if found_student
student_id = Student.authenticate( params[:username],params[:password])
if student_id
flash[:notice] = "Welcome! You are LoggedIn"
session[:user_id] = student_id
redirect_to(:action => 'student_index')
return
end
end
found_instructor = Instructor.where(:username => params[:username]).first
if found_instructor
instructor_id = Instructor.authenticate( params[:username],params[:password])
if instructor_id
flash[:notice] = "Welcome! You are LoggedIn"
session[:user_id] = instructor_id
redirect_to(:action => 'instructor_index')
return
end
end
flash[:notice] = "Invalid username/Password combination."
redirect_to(:action => 'login')
end
end
def logout
flash[:notice]="Logged out"
session[:user_id] = nil
redirect_to(:action => "login")
end
and here is my application_controller.rb code
def require_login
unless session[:user_id] or config.my_config
flash[:notice] = "You are not Logged In"
redirect_to :root
return false
else
return true
end
end
It seems to me that you're sharing the same session key session[:user_id] to store the ID of User, Student and Instructor. How do you differentiate between the three kinds of logged in users?
It's possible that if a logged in Student visits the instructor_index path, then the student's ID would be used to load a Instructor with the same ID, and a view for an instructor would be rendered. I don't see any code to indicate otherwise.
I would have expected such a system to store both a session[:user_id], and a session[:user_type] to ensure that it's possible to exactly identify the logged in person.
I followed the tutorial from railscast about authentication. Because I have two models that should be authenticated I changed the session create code a little bit:
def create
if User.find_by_username(params[:username]) != nil
user = User.find_by_username(params[:username])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_path, notice: "Eingeloged als User"
end
elsif Admin.find_by_username(params[:username]) != nil
admin = Admin.find_by_username(params[:username])
if admin && admin.authenticate(params[:password])
session[:user_id] = admin.id
redirect_to adminpage_index_path, notice: "Eingeloged als Admin"
end
else
flash[:error] = "Benutzername oder Password ist falsch"
render 'new'
end
end
If I login as user it works, and when I type in a false password it also works. But somehow when I want to login as admin I get the error:
Template is missing
Missing template sessions/create
I don't know why I get this error! I mean where does my code say that it should redirect to session create ? Thanks
My routes:
get 'login', to: 'sessions#new', as: 'login'
get 'logout', to: 'sessions#destroy', as: 'logout'
resources :users
resources :sessions
Look at the logic in your controller action:
if admin && admin.authenticate(params[:password])
session[:user_id] = admin.id
redirect_to adminpage_index_path, notice: "Eingeloged als Admin"
end
If you have provided a valid username and an invalid password, what is going to happen?
You're not going to get into that if statement - you're going to continue through the controller action, fall out the bottom, and the default behaviour in Rails is to render a view at the end of an action if no other behaviour is requested. Hence it's trying to render the create view for your create action - which doesn't exist.
You need to handle the invalid-password case for both users and admins.
Also, why are you calling find_by_username twice for both users and admins?
I think you are missing the else part in Admin authentication..
It should be,
def create
if User.find_by_username(params[:username]) != nil
user = User.find_by_username(params[:username])
if user && user.authenticate(params[:password])
session[:user_id] = user.id
redirect_to root_path, notice: "Eingeloged als User"
else
redirect_to root_path, notice: "Your Notice"
end
elsif Admin.find_by_username(params[:username]) != nil
admin = Admin.find_by_username(params[:username])
if admin && admin.authenticate(params[:password])
session[:user_id] = admin.id
redirect_to adminpage_index_path, notice: "Eingeloged als Admin"
else
redirect_to root_path, notice: "Your Notice"
end
else
flash[:error] = "Benutzername oder Password ist falsch"
render 'new'
end
end
So it looks like the faulty line is the redirect_to adminpage_index_path, notice: "Eingeloged als Admin" . It may help if you post your routes (run rake routes from your terminal). If it's saying the template is missing though, likely you don't have an index.html.erb in your app/views/adminpages/ folder? Is there a file there? (Also make sure you have the appropriate app/contollers/adminpages_controller and appropriate index action.
I'm using Omniauth to try to signup/login users on my web app.
This is happening inside my AuthenticationsController#Create method:
Authentications Controller:
class AuthenticationsController < InheritedResources::Base
def create
omniauth = request.env['omniauth.auth']
authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])
if authentication
flash[:success] = "Signed in successfully"
sign_in_and_redirect(authentication.user)
elsif current_user
token = omniauth['credentials'].token
secret = omniauth['credentials'].secret
current_user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'], :token => token, :secret => token_secret)
flash[:success] = "Authentication successful"
redirect_to authentications_url
else
user = User.new
user.apply_omniauth(omniauth)
if user.save!
flash[:success] = "Account created"
sign_in(authentication.user)
else
session[:omniauth] = omniauth.except('extra')
redirect_to '/signup'
end
end
end
I originally had sign_in(:user, authentication.user) but it gave me argument errors, so I changed it to just had sign_in(authentication.user) in the above code. However, now I'm getting a NoMethodError - undefined method 'user' for nil:NilClass.
Line 23 sign_in(authentication.user) is failing because you are in the else branch of if authentication condition (so authentication is nil).
What you probably meant to do is call sign_in(user) for user you just created a few lines above.
First you test if authentication is defined, and then in the else block, which will only trigger if it is not defined, you go and reference authentication.user for some reason. This could not possibly work.
That condition seems to apply if you haven't authenticated, and aren't logged in. Why would you be engaging the sign_in function under those circumstances?
If your using a set list of providers in your db make sure
> :provider => omniauth['provider']
Matches up with the provider in the db, for instance. If you have facebook_Oauth2 in your db and the provider response is facebook authenthication will fail.
When i run in my page this code :
<% user = User.find(session[:userid]) %>
i get the error :
line #1 raised:
Couldn't find User without an ID
although i have in my authentification in my sessions_controller this :
def create
if user = User.authenticate(params[:username],params[:password])
session[:user_id]= user.id
session[:language_id]= user.language_id
User.find(user.id).update_attributes(:last_login => Time.now)
redirect_to root_path , :notice => (I18n.t :"session.login_success")
else
flash.now[:alert] = (I18n.t :"session.error")
render :action => 'new'
end
end
and the session should contain the userid
In your log-in you set session[:user_id], and you try to find session[:userid] (note the spurious underscore). That's why.
Your controller is looking for params session[:user_id], but in your views it is session[:userid] so it will complain that session[:user_id] is nil.
I can't seem to figure out what I am doing wrong here. I have implemented the Super Simple Authentication from Ryan Bates tutorial and while the login portion is functioning correctly, I can't get an error message and redirect to happen correctly for a bad login.
Ryan Bates admits in his comments he left this out but can't seem to implement his recommendation. Basically what is happening is that when someone logs in correctly it works. When a bad password is entered it does the same redirect and flashes 'successfully logged in' thought they are not. The admin links do not show (which is correct and are the links protected by the <% if admin? %>) but I need it to say 'failed login' and redirect to login path. Here is my code:
SessionsController
class SessionsController < ApplicationController
def create
if
session[:password] = params[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "whoops"
redirect_to login_path
end
end
def destroy
reset_session
flash[:notice] = 'Successfully logged out'
redirect_to posts_path
end
end
ApplicationController
class ApplicationController < ActionController::Base
helper_method :admin?
protected
def authorize
unless admin?
flash[:error] = "unauthorized request"
redirect_to posts_path
false
end
end
def admin?
session[:password] == "123456"
end
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
#
end
You need to use Ruby's comparison operator == rather than the assignment operator =. Your create action should be:
def create
if session[:password] == params[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "whoops"
redirect_to login_path
end
end
Edit: The problem is that nowhere in your SessionsController are you actually checking the entered password against the correct password. Change your create method to this:
def create
if params[:password] == '123456'
session[:password] = params[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "whoops"
redirect_to login_path
end
end
It's not ideal having the password hard-coded like this and storing it in the session for use by the admin? helper method, but this is supposed to be super simple authentication.
if #YOU MISSING SOMETHING HERE WHICH Returns TRUE IF USER IS VALID
session[:password] = session[:password]
flash[:notice] = 'Successfully logged in'
redirect_to posts_path
else
flash[:notice] = "invalid login" #CHange if messaage for invalid login
redirect_to login_path
end
it must be
if session[:password] == params[:password]
You never have a fail condition due to:
if session[:password] = session[:password]
This will always be true. You probably want something like:
if session[:password] == 'canihazpasswrd' then
do_something_here
Edit: Refer #john's answer. :)
Try this:
def create
if session[:password] == '123456'
flash[:notice] = 'Succesfully logged in'
redirect_to home_path
else
flash[:notice] = "Incorrect Password!"
redirect_to login_path
end
end
The thing is that the tutorial you used does no user's authentication. It only checks if the login belongs to an admin, so some content will be showed.
This way you'll never have wrong login/password, just admin/non-admin.