I've been trying to play around with Omniauth-Twitter and am stuck with an infuriating problem. I'm unable to match my session id to the stored Twitter uid. I used Ryan Bates' screencast to assist me through the walkthrough.
Here's my session controller:
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
session[:user_id] = user.uid
redirect_to root_url, :notice => "Signed in!"
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Signed out!"
end
end
Here's my user model:
class User < ActiveRecord::Base
def self.create_with_omniauth(auth)
create! do |user|
user.provider = auth["provider"]
user.uid = auth["uid"]
user.name = auth["info"]["name"]
end
end
end
Here's my application controller that should be able to assign my Twitter persona to the current user variable:
class ApplicationController < ActionController::Base
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
On the front end, I'm trying to essentially display the user name, like so:
<% if current_user %>
Welcome <%= current_user.name %>!
<%= link_to "Sign Out", signout_path %>
<% else %>
<%= link_to "Sign in with Twitter", "/auth/twitter" %>
When I run the application and hit "Sign in with Twitter", I'm getting an error that says:
"ActiveRecord::RecordNotFound. Couldn't find User with id= "
The server's highlighting the current_user method as the error point. Any help would be appreciated? I'll gladly provide more info if needed.
You're confusing the user id, which is automatically assigned by the database, with uid, which is Twitter's id. Either:
Change session[:user_id] = user.uid to session[:user_id] = user.id. Or
Change
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
to
def current_user
#current_user ||= User.find_by(uid: session[:user_id]) if session[:user_id]
end
Personally, I would go for the first option.
Related
I have a sign up with facebook text link in my app.
I tried to add class to this text link to turn this into a button.
In rails it's written like this to display that text.
= link_to_session
So, as a rule I added the following
= link_to_session 'sign up', class: 'button button-primary'
but it gave me an error...
wrong number of arguments (2 for 0)
How could I fix this...?
Thank you for your time!
UPDATE
sorry.. I'm not quite sure where to look at...
I looked at session controller and in controller following is written...
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
user = User.find_by_auth(auth)
if user.blank?
if session[:user_id].present?
# via token
user = User.find(session[:user_id])
user.definitive_by(auth)
else
# new user
user = User.find_or_create_by_auth(auth)
end
else
user.token = auth.credentials.token
user.save!
end
session[:user_id] = user.id
redirect_to root_url
end
def create_via_token
session[:user_id] = params[:user_id]
redirect_to '/auth/facebook'
end
def destroy
session[:user_id] = nil
redirect_to root_url
end
end
Try the following
= link_to 'sign up', "write your path here", class: 'button button-primary'
Here session path should be present in your route.
I can't figure out why the #user variable is not being found. It's throwing the error inside of a view where I try to link to the user, and it mentions the index of Users.
What am I doing wrong?
More info: They login via a session page, and then I redirect them to the "User view" to then use the application as a logged in user. The session is created successfully.
Routes.rb
resources :users
resources :sessions
Users Controller
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.create!(user_params)
redirect_to users_path, notice: "Successfully created #{#user.name}"
end
def index
#user = User.find_by_email(params[:email])
end
private
def user_params
params.require(:user).permit!
end
end
Sessions Controller
class SessionsController < ApplicationController
def new
end
def create
#user = User.find_by_email(params[:email])
if #user && #user.authenticate(params[:password])
session[:user_id] = #user.id
redirect_to users_path, notice: "Logged in as #{#user.name}"
else
flash.now.alert = "Email or password is invalid"
render "new"
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, notice: "Logged out!"
end
end
User View
<%= link_to user.name, edit_user_path(user) %>
The user variable in your view is being seen as a local variable, which is undefined. Use #user instance variable instead of user as it's #user that's defined in your index action.
<%= link_to #user.name, edit_user_path(#user) %>
Update:
So basically the problem was in the OP's user's migration, the option id: false was set. Which led to creation of users table without the id column and #user.id was always nil. Removing this option from the migration fixed the issue!
Creating a Rails app that interacts heavily with Facebook. I want to users to be able to look at profiles of other users and see information on those users that has been pulled in from Facebook.
I'm using the omniauth-facebook and koala gems. I followed Ryan Bates' Railscasts on Facebook authentication and Facebook Graph API to get where I'm at.
I would prefer not to have to store a user's Facebook info in my database, but that seems to be the only way of doing it, because otherwise, when I try to view the profile page of another user who may have logged out, I get: "Koala::Facebook::AuthenticationError in Profiles#show"
type: OAuthException, code: 190, error_subcode: 467, message: Error validating access token: The session is invalid because the user logged out. [HTTP 400].
Is there a way to bring in this data from Facebook, even if that user has logged out?
Here's the necessary code:
user.rb:
class User < ActiveRecord::Base
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.image = auth.info.image
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
def facebook
#facebook ||= Koala::Facebook::API.new(oauth_token)
block_given? ? yield(#facebook) : #facebook
rescue Koala::Facebook::APIError
logger.info e.to_s
nil
end
end
sessions_controller.rb
class SessionsController < ApplicationController
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to feed_path
end
def destroy
session[:user_id] = nil
redirect_to root_url
end
end
application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
rescue ActiveRecord::RecordNotFound
end
helper_method :current_user
end
profiles_controller.rb
class ProfilesController < ApplicationController
def show
#user = User.find(params[:id])
end
end
profiles_helper.rb:
module ProfilesHelper
def facebook_profile_info
#user.facebook.get_object("#{#user.uid}",fields:'gender, locale, bio, birthday,
picture, relationship_status')
end
end
Also, if you have suggestions on better ways to accomplish these tasks than the trajectory I'm headed in, I welcome your suggestions.
I've built an app that allows users to sign up, sign in, and sign out (my own devise from the ground up, if you will).
The app allows users to sign up, but when trying to sign in I get the following error:
// (needless to say I'm at a stand still, who ever can figure this out is a genius in they're own right)
NoMethodError in SessionsController#create
undefined method `-' for nil:NilClass
Rails.root: /Users/user/Sites/rails_projects/sample_app1
app/controllers/sessions_controller.rb:11:in `create'
Request
Parameters:
{"utf8"=>"✓",
"authenticity_token"=>"/SEaqnrMf5X0pd4FVWbu8uWVAjTNw4LPKiXg+8Hl0PQ=",
"session"=>{"email"=>"Anthonypane#example.com",
"password"=>"[FILTERED]"},
"commit"=>"Sign in"}
Here are my Session_Controller Contents:
class SessionsController < ApplicationController
def new
#title = "Sign in"
end
def create
user = User.authenticate(params[:session][:email],
params[:session][:password])
if user.nil?
flash.now[:error] = "Invalid email/password combination."
#title - "Sign In"
render 'new'
else
sign_in user
redirect_to user
end
end
def destroy
sign_out
redirect_to root_path
end
end
Users_Controller contents
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#title = #user.name
end
def new
#user = User.new
#title = "Sign up"
end
def create
#user = User.new(params[:user])
if #user.save
sign_in #user
redirect_to #user, :flash => {:success => "Welcome to the Fun House!"}
else
#title = "Sign up"
render 'new'
end
end
end
Sessions_helper contents
module SessionsHelper
def sign_in(user)
cookies.permanent.signed[:remember_token] = [user.id, user.salt]
current_user = user
end
def current_user=(user)
#current_user = user
end
def current_user
#current_user ||= user_from_remember_token
end
def signed_in?
!current_user.nil?
end
def sign_out
cookies.delete(:remember_token)
self.current_user = nil
end
private
def user_from_remember_token
User.authenticate_with_salt(*remember_token)
end
def remember_token
cookies.signed[:remember_token] || [nil, nil]
end
end
And Lastly Users_helper contents:
module UsersHelper
def gravatar_for(user, options = { :size => 50})
gravatar_image_tag(user.email.downcase, :alt => user.name,
:class => 'gravatar',
:gravatar => options)
end
end
I think this line:
#title - "Sign In"
Should be this:
#title = "Sign In"
I followed along with Ryan Bates' authenticating with Facebook Railscast http://media.railscasts.com/assets/episodes/videos/360-facebook-authentication.ogv in which he uses gem 'omniauth-facebook' to authenticate with Facebook. At the end of the Railscast, he introduces Koala, which allows you to interact with the open graph api. Ryan gives instructions to pass the oath token as a parameter into this
#graph = Koala::Facebook::API.new(your_oauth_token)
I'm having trouble getting this to work because I'm not sure where to get the oath token from. Let me explain....
In the sessions_controller.rb, we have this
def create
user = User.from_omniauth(env["omniauth.auth"])
session[:user_id] = user.id
redirect_to root_url
end
which saves the omniauth information to the database in the User model
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
so I'm guessing I need the user.oath_token passed into
#graph = Koala::Facebook::API.new(your_oauth_token)
but I can't get it to work.
Can you please imagine that I have a Main controller and an index action.
Main_controller.rb
def index
#graph = Koala::Facebook::API.new(how do I get the oauth token in here?)
end
Question
How would I get the oath token (from either the session or the database) into the index method of the main controller?
For example, using the helper method in application_controller.rb
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
helper_method :current_user
I tried to do this in main_controller.rb
def index
#graph = Koala::Facebook::API.new(current_user.oauth_token)
#graph_data = #graph.get_object("/me/statuses", "fields"=>"message")
end
However, when I tried to loop through data using the following
Views/main/index.html.erb
<% if current_user %>
Looping through your statuses:<br />
<ul>
<% #graph_data.each do |status| %>
<%= status["message"] %> (<i><%=status["updated_time"]%></i>)<hr>
<% end %>
</ul>
<% end %>
It didn't give me any status updates
The error is that current_user is returning nil. This is probably because session[:user_id] is not set (ie user is not logged in). You should have a check in index to protect against this:
def index
if current_user
#graph = Koala::Facebook::API.new(current_user.oauth_token)
else
# User isn't logged in; do something else
end
end