Just installed Geocoder and trying to get it to show signs of life. I want a user to log in and have the profile landing page to show data on their ip. Since I'm in the dev environment, here is my attempt at a temporary solution:
class SessionsController
def create
user = User.authenticate(params[:username_or_email], params[:password])
if user
session[:user_id] = user.id
redirect_to profile_path, :notice => "Logged in!"
#request = Rack::Request.new({'REMOTE_ADDR' => '107.128.188.218'})
#location = #request.location
#blah blah blah
end
in the view:
<%= #location.data %>
the error I get is undefined method 'data' for nil:NilClass
in the intializers/geocoder.rb
Geocoder.configure(
:timeout => 30
)
You are assigning ivars #request and #location in the create action of your SessionsController, but the lifetime of these variables is just that request. After the controller action finishes, you are redirecting the client's browser to your ProfilesController, so you need to move those two assignments into ProfilesController#show, then it should work.
EDIT: Since you say you are using the SessionsController show action for the user's profile, moving those two statements to that action method should do the trick. :-)
Related
I am working on a reservation project and after login I want to pass the current user information from the Sessions Controller to a Reservations Controller via a home page. How can I do that? I have been following Michael Hartl's Rails Tutorial for the login. Here's what I have tried in the create section of the Sessions Controller
render home_path :local_variables[:id => user_id]
and in the home_path(users#home)
<%= link_to new_reservation_path(:user_id => :id) %>
but it shows me an undefined method error. My Reservation model has a user_id column.I am confused regarding this matter. What should I do?
render home_path :local_variables[:id => user_id]
Seems weird to me to pass locals that way (don't even know if it's possible, never seen locals used outside of rendering views/partials).
I think the best way is to redirect instead and set the user in the sessions once they have been logged in successfully, so in your login action:
user = User.find_by_email(params[:user][:email]) # or however you are finding the person trying to login
session[:user] = user
redirect_to home_path
then in users#home
#user = session[:user]
and finally, in the view:
<%= link_to new_reservation_path(:user_id => #user.id) %>
EDIT
Actually, probably not a good idea to store an object in the session, instead of
session[:user] = user
You could try:
session[:user_id] = user.id
and then to find the user:
#user = User.find(session[:user_id])
If you still get an undefined error then it's probably because the user is nil (unless the User model actually has no id attribute, which would be strange) so there might be an issue with the login part, it's hard to say without knowing what that looks like.
If you need the logged in user on every page, you could abstract the functionality out into the application controller:
before_filter :check_user
def check_user
#user = User.find(session[:user_id]) if session[:user_id]
end
Then, you can use the #user instance variable anywhere in your app.
I'm using the gem called omniauth-facebook, with which I succeeded at implementing facebook login auth.
It looks fine but it won't pass data of the whole object to the view. It just says nil.
It should show an array of things when using 'debug' or 'inspect'. It shows the content of session[:name] fine somehow.
Controller
class SessionsController < ApplicationController
def create
#auth = request.env["omniauth.auth"]
session[:oauth_token] = #auth.credentials.token
session[:username] = #auth.extra.raw_info.username
session[:name] = #auth.extra.raw_info.name
redirect_to bookd_url, :notice => "Signed in!"
end
end
View
<% if signed_in? %>
<%= #auth.inspect %>
<%= debug #auth %><br />
<%= session[:name] %>
<% end %>
Output HTML
nil
---
...
John
Your create controller action does a redirect. After the redirect, the process will start from scratch, and #auth will no longer be defined. If you render the view at this point, #auth will be nil. This is your problem.
You need to think about what you are trying to do here. You set an #auth variable from the authentication details in the initial request. You then use this to set some data in the session, which records who is logged in for example. Then, on the next page, where the user is logged in, you want to look at #auth. This doesn't really make sense: once you've authenticated a user, all you need to care about is remembering which user is currently logged in. You don't need to store details about HOW they logged in, and in fact you probably shouldn't.
You should instead be doing something like this:
#in ApplicationController, protected section
protected
def current_user
if #current_user
return #current_user
elsif session[:username]
#current_user = User.find_by_username(session[:username])
return #current_user
end
end
This will allow you to write current_user in your controller and view code, to access the user who authenticated, originally, which is the whole reason for logging someone in and keeping them logged in.
I login to my Rails application using a login page which is reached either directly through a login link that uses the route
match 'ladmin/login' => 'ladmin#login'
or if I try to edit content.
In either case I get taken to the login page, which allows me to login and then returns me to the page I was trying to use or the app index page, but now as a logged in user.
Most of the time this works totally ok, I get logged in and returns to my content edit page or to the links index page as expected (if I had just use the 'login' link iself).
However I have been able to track down a bug whereby
if I use either of my ajax links the request.url is remembered incorrectly going forward
(to either toggle group shading or to toggle Summary/Details, then the next time (even if several clicks) that I try to login (assuming I am logged out initially) results in the blank page - though I am actually now logged in. Interestingly I notice that when this happens, the url that I end up at in the browser address bar is always localhost:3000/toggle_row_shading which seems like a clue to the problem - it seems like the request.url is remembered incorrectly .
I require digest/sha1 for authentication in the User model with various methods for authentication and password.
The relevant code would seem to be in my LadminController:
def login
session[:user_id] = nil
if request.post?
user = User.authenticate(params[:username], params[:password])
if user
session[:user_id] = user.id
session[:username] = user.username
uri = session[:original_uri]
session[:original_uri] = nil
redirect_to(uri || {:action => "index", :controller => :links})
else
flash.now[:notice] = "Invalid username/password combination"
end
end
end
I can temporarily got around it with
def login
session[:user_id] = nil
if request.post?
user = User.authenticate(params[:username], params[:password])
if user
session[:user_id] = user.id
session[:username] = user.username
redirect_to({:action => "index", :controller => :links})
else
flash.now[:notice] = "Invalid username/password combination"
end
end
end
However this 'forgets' the page I have come from, e.g. an 'edit' link and just uses links#index to put me on after login which is not ideal. It does get around the blank page problem though, as the steps to reproduce it now longer make it happen.
How can I have the login return me to the intended edit page and not give me the blank page?
btw my code for the ajax links is:
%a{href: '#', :data => {toggle_group_row_shading: 'toggle'}}
click to toggle
Do I need an extra route perhaps as the app started at rails 2.3.8 ?
My routes include
match 'toggle_full_details' => 'links#toggle_full_details'
match 'toggle_row_shading' => 'links#toggle_row_shading'
get 'verify_link/:id', to: 'links#verify_link', as: :verify_link
get 'unverify_link/:id', to: 'links#unverify_link', as: :unverify_link
should I have them all as gets perhaps?
My application controller includes:
before_filter :authorize, :except => :login
and
def authorize
unless User.find_by_id(session[:user_id])
session[:original_uri] = request.url #request.request_uri
flash[:notice] = "Please Log In!"
redirect_to :controller => 'ladmin', :action => 'login'
end
end
I have had this happen to me before. The problem I found was that for AJAX requests, the session[:original_uri] is still getting stored and... is bad. Basically, it's storing a uri for an ajax request which doesn't display very well after logging in. The code I ended up with is something like:
if request.get? && !request.xhr?
session[:original_uri] = request.url
end
This way we're not storing into the session[:original_uri] things that shouldn't be redirected to after logging in. You may find other things in your app to add to this conditional. For example, I had some download links that would render a send_file, but those were no good for storing for next login either.
I have a controller set as the root of my app. It accepts in a parameter called uid and checks to see if the user exists. If not, I want it to redirect to the new user page and pre-populate the uid field with the uid in the parameter.
In my root_controller:
def index
if params[:uid]
#user = User.find_by_uid(params[:uid])
if (!#user.blank?)
# do some stuff
else
session[:user_id] = params[:uid]
redirect_to(new_user_path, :notice => 'Please register as a new user')
end
else
# error handling
end
end
In my users_controller, GET /users/new action:
def new
#user = User.new
#user.uid = session[:user_id]
# standard respond_to stuff here
end
This all works fine, but is this an acceptable way to do this? I originally tried passing the uid in the redirect statement, like:
redirect_to(new_user_path, :notice => 'Please register as a new user', :uid => params[:uid])
or even testing it with:
redirect_to(new_user_path, :notice => 'Please register as a new user', :uid => 'ABCD')
but neither seemed to pass the value to users_controller...I couldn't access it using params[:uid] from that controller.
Is session a proper place to store stuff like this, or is there a better way to pass it via the redirect? Thanks!
A session is fine to store that kind of information. Depending on what you are doing with the uid it might actually be dangerous to allow it to be read from the URL. Imagine if the end user was malicious and started putting other user's IDs into there.
For messages that should only last until the next request Rails actually has the flash object which will carry it over for you.
http://guides.rubyonrails.org/action_controller_overview.html#the-flash
That said, if you want to redirect to a url and pass some params, do so like this:
redirect_to(new_user_path(:notice => 'Please register as a new user', :uid => 'ABCD'))
The params you want to pass are arguments to the new_user_path method, not the redirect_to method.
Suppose this is my users controller:-
class UsersController < ApplicationController
def show
#user = session[:user]
end
def prepare
session[:user]= User.find(:first)
redirect_to :action => 'show'
end
def update
#user = session[:user]
#user.name = 'rai'
redirect_to :action => 'show'
end
end
View for show.html.erb
<%= #user.name %>
Show page
<%= link_to 'Update', :action=> 'update' %>
Now Explaining the issue:---
Suppose first time user opens the browser with
http://localhost:3000/users/prepare
o/p will be:---
Mohit Show page Update // supposing user table has values mohit as name
Now when he click on update he will get as output like this:--
rai Show page Update
But this should not happen cause
firstly when are at prepare action where value is fecthced from db and its mohit. and then he is redirected to show ie displying the values from session. ie mohit
Now when user click on the update he is redirected to update when value from session is stored to a user instance and the name attribute of that user instance has been modified to rai. and finally redirected to show page.
Now in this page when user's name is displayed its showing rai.. thats the QUESTION why??
cause session should store the same mohit value cause we havnt made any change in session..
When you are doing
#user = session[:user]
#user variabe is assigned reference to the object session[:user], not the copy of it.
So when you are modifying #user, session[:user] is also modified, as they are essentially the same object.
I'm not sure, but I think it is something with hashes and classes and about copying them. So when you do:
#user = session[:user]
You are not making a copy of object but it is something likre reference in C++, both #user and session[:user] are reffering to the same object, so when you modify one, you get both modified.
Example from console:
a = {}
a[:user] = User.first
a[:user].firstname # => "Mohit"
b = a[:user]
b.firstname = 'rai'
a[:user].firstname # => 'rai'
a[:user] = User.first
a[:user].firstname # => 'Mohit'