Hi I am trying to prevent duplicate user name creation, and my application keeps trying to redirect me to a hypothetical account page and keeps throwing username undefined error in my erb file, and I am actually trying to redirect back to signup page if the user name already exist.
Here is my model for User class:
class User <ActiveRecord::Base
include Slugifiable::InstanceMethods
extend Slugifiable::ClassMethods
validates_uniqueness_of :username, case_sensitive: false <---This should validate if username exist
has_many :players
has_secure_password
end
Here is my user controller post method where it should either create or redirect back to signup page and give a flash message that the user name exist already
post '/signup' do
if params[:username] == "" || params[:email] == "" || params[:password] == "" || params[:name] == ""
flash[:notice] = "<h3 class ='alert'>Please fill-in info!</h3>"
redirect to '/signup'
else
if #user
flash[:notice] = "<h3>Username already exist, try anoter one.</h3>"
redirect to '/signup'
else
#user = User.create(:username => params[:username], :email => params[:email], :password =>
params[:password], :name => params[:name])
session[:user_id] = #user.id
redirect to '/account'
end
end
end
When I try to create a duplicate username for testing purposes....it keeps redirecting me to an account page but throws an error that username is undefined from erb file. It works fine when creating a completely new username though. What am I doing wrong?
"throws an error ... from erb" sounds like there's an issue in an ERB file somewhere?
User.create probably silently fails when the uniqueness check triggers, i.e. it sounds like it sets #user.username to nil, or #user itself is nil.
You also never defined what it should do when the validation check fails.
You can:
use User.create! to raise an exception.
check #user.valid? and #user.errors for any errors, and report them to the user
Related
I'm having some trouble authenticating users for my app. During the authentication process I get the following error:
Refused to display 'https://www.facebook.com/dialog/oauth?response_type=code&client_id=xxxxxxxx…%2Fliketodownload.xx-xxxx.com%2Fauth%2Ffacebook%2Fcallback&scope=email' in a frame because it set 'X-Frame-Options' to 'DENY'.
I think it's to do with the authentication trying to redirected to an invalid target and that's why it's getting blocked. But with Ruby and Sinatra I am unsure of how to overcome this.
Many thanks.
UPDATE
I'm not redirecting to views, of which the auth and add to page dialogs are trigged into new targets via html. Now I'm trying to figure out the logic of which to auth and redirect users appropriately.
Code below:
post '/' do
if current_user
signed_request = FBGraph::Canvas.parse_signed_request(APP_SECRET, params[:signed_request])
if signed_request["page"] != nil
is_admin = signed_request["page"]["admin"]
is_liked = signed_request["page"]["liked"]
if is_admin #if admin, see if existing user is in db, if not create, then send to admin page
puts "user is a page admin" #logging for dev
redirect '/index'
elsif is_liked #if liked send to download end point
puts "user has liked page" #logging for dev purposes
redirect '/main/#/liked'
elsif !is_liked #otherwise make them like the page
puts "user has not liked" #logging for dev purposes
redirect '/main/#/notliked'
end
else
redirect '/addtopage/#/addtopageview'
end
elsif $auth1 && !current_user
puts "post / add to page view reached"
User.first_or_create({:uid => $auth1["uid"]}, {
:uid => $auth1["uid"],
:nickname => $auth1["info"]["nickname"],
:name => $auth1["info"]["name"],
:email_address => $auth1["info"]["email"],
:created_at => Time.now})
redirect '/addtopage/#/addtopageview'
else
# we just redirect to /auth/facebook here which will parse the #signed_request FB sends us, asking for auth if the user has not already granted access, or simply moving straight to the callback where they have already granted access.
puts "post / auth me reached"
redirect '/addtopage/#/authme'
end
end
get '/auth/:provider/callback' do
content_type 'application/json'
response.set_cookie 'test', {:value => "facebook_callback", :path => "/"}
JSON.generate(request.env)
auth = request.env["omniauth.auth"]
$auth1 = auth
#need escape here to allow user to initially authorise app without the full #signed_request?
session['fb_auth'] = auth
session['fb_token'] = cookies[:fb_token] = auth['credentials']['token']
session['fb_error'] = nil
if params[:signed_request] != nil #if the signed request isn't empty
signed_request = FBGraph::Canvas.parse_signed_request(APP_SECRET, params[:signed_request])
if signed_request["page"] != nil #if the signed request contains page data
$page_id = signed_request["page"]["id"]
is_admin = signed_request["page"]["admin"]
is_liked = signed_request["page"]["liked"]
if is_admin #if admin, see if existing user is in db, if not create, then send to admin page
puts "user is a page admin" #logging for dev
User.first_or_create({:uid => auth["uid"]}, {
:uid => auth["uid"],
:nickname => auth["info"]["nickname"],
:name => auth["info"]["name"],
:email_address => auth["info"]["email"],
:created_at => Time.now})
#insert page_id into database?
redirect '/index'
elsif is_liked #if liked send to download end point
puts "user has liked page" #logging for dev purposes
redirect '/main/#/liked'
elsif !is_liked #otherwise make them like the page
puts "user has not liked" #logging for dev purposes
redirect '/main/#/notliked'
end
else #user authed app but needs to add to page
puts "add to page view"
redirect '/addtopage/#/addtopageview'
end
else
#needs to redirect to a page telling them that they must be on facebook or that they must authorise the application
redirect '/index'
end
end
helpers do
def current_user
#current_user ||= User.get(session[:user_id]) if session[:user_id]
end
end
Facebook domains can not be iframed except for the socials plugins, Why?
for security reasons, for example let's say you're logged into Your Facebook account
and I have http://example.com/xss.html which has an iframe of http://facebook.com in this way I can steal or hi-jack sensitive information from your account like fb_dtsg token, same thing for oAuth Dialogs I can set my iframe source to to it and steal Your access_token :)
I hope it's clear enough why Facebook uses
header('X-Frame-Options: DENY');
I setup my app similar to the tutorial here - http://railscasts.com/episodes/235-devise-and-omniauth-revised. If you cant access it, below is my code
Omniauth controller callback
def all
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash.notice = "Signed in!"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
redirect_to new_user_registration_url
end
end
alias_method :twitter, :all
end
user model
def self.from_omniauth(auth)
where(auth.slice(:provider, :uid)).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.username = auth.info.nickname
user.name = auth.info.name
end
end
def self.new_with_session(params, session)
if session["devise.user_attributes"]
new(session["devise.user_attributes"], without_protection: true) do |user|
user.attributes = params
user.valid?
end
else
super
end
end
Now I am wondering how do I obtain the authenticated user's oauth token and oauth token secret?
Thanks
If you want to take a look at the information returned by a certain provider, put this as the first line of your callback controller:
raise env["omniauth.auth"].to_yaml
You'll be able to see that the information you want can be accessed in auth.credentials.token and auth.credentials.secret.
EDIT: Now that Rails 4 uses the better_errors gem, this method of inspecting the omniauth hash no longer works so well. A better way now is:
render :text => "<pre>" + env["omniauth.auth"].to_yaml and return
I am programming a simple login/out web app. Here's the relevent code:
get '/logout' do
session.clear
end
get '/self' do
if session[:user_id]
user = User.find session[:user_id]
user.to_json
else
status 401
{"error" => "Not logged in."}.to_json
end
end
If I call logout, and then self, it doesn't return "Not logged in". Rather the :user_id still persists and I am returned the user's details. What am I doing wrong?
Thanks!
This should work
get '/logout' do
session[:user_id] = nil
redirect '/self'
emd
I am not finding much info on how to do this even though there are lots of suggestions on how to pass params to a redirect using hashs like this redirect_to
:action => 'something', :controller => 'something'
in my app I have the following in the routes file
match 'profile' => 'User#show'
my show action loos like this
def show
#user = User.find(params[:user])
#title = #user.first_name
end
the redirect happens in the same user controller like this
def register
#title = "Registration"
#user = User.new(params[:user])
if #user.save
redirect_to '/profile'
end
end
The question is in the register action when I redirect_to how do I pass along the params so I can grab that user from the database or better yet ... I already have a user variable so how do I pass along the user object to the show action?
-matthew
If you're doing a redirect, Rails will actually send a 302 Moved response with a URL to the browser and the browser will send another request to that URL. So you cannot "pass the user object" as in Ruby, you can only pass some url encoded parameters.
In this case you would probably want to change your routing definition to:
match 'profile/:id' => 'User#show'
and then redirect like this:
redirect_to "/profile/#{#user.id}"
First off, I'd name your route, to make using it easier:
match '/profile/:id' => 'users#show', :as => :profile
You would then redirect to it, like so:
redirect_to profile_path(#user) # might have to use profile_path(:id => #user.id)
Then to pull the user from the database:
def show
#user = User.find(params[:id]) # :id comes from the route '/profile/:id'
...
end
As an aside, if you use something like Devise for authentication, it provides you with a current_user method, and therefore you wont need to pass around the user's id:
match '/profile' => 'users#show', :as => :profile
redirect_to profile_path
def show
#user = current_user
end
Hey there, im a little bit confused about handling invalid user authentication request, at login controller. So, i already have modified login view, but cant figure out where to put the exception handling block. It should work like this: you login - if its incorrect you will see warning message at /login .
Any ideas ?
What strategy have you chosen ? In my custom Strategy, I call the class method 'authenticate' on my User class:
class User
def self.authenticate(login, password)
u = User.first(:conditions => ['email = ?', login]) # find a user with this login
if u && u.authenticated?
return u
else
nil
end
end
end
Also, you might want to look at the source code of merb-auth-more/mixins/salted_user which is a module that is automatically mixed into your User class.
you would put your exception handling action in the exceptions controller
# handle NotAuthorized exceptions (403)
def not_authorized
render :format => :html
end
and to customise the view you would create a template in app/views/exceptions/not_authorized.html.haml