I have installed devise and I can create users. I am trying to display all of the users so that people can see who has signed up. I would eventually like to allow people to send messages etc..(think Tinder).
Any guidance on displaying profiles to the user?
This is big question to answer here and explain .I think you want to display listing of all the users and for every user there would be a profile page(show ). what you need to do is create controller having same name as devise name.I can give you small idea about that.
Class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id]) //you can change it according to rails4 standards
end
....
....
....
end
with this you can display all user and display there profiles.
Now for messaging you need to create a different model Message and which will have fields sender,receiver and msg .both sender and receiver will be user_id ,sender you can get from session and receiver you can get from profile itself.and remember user can have many messages
But for making this real time you have to use web sockets which will be different question to answer.
Related
I'm trying to implement an e-commerce app. In it, I allow the user to browse for products and put them into the cart even before signing in. I only prompt the user to sign in upon checkout.
However, I'm losing track of the user because the user's session id changes upon sign in. Due to this, Im unable to associate the items that the user placed into the cart (stored in redis) to the user who placed them in after the user signs in to the application.
Does anyone have any idea how could this be circumvented?
Thanks.
Cheers!
Found the solution. All that needs to be done is set session.options[:renew] = false and the session id will still be the same before & after signing in.
Please refer to the implementation below
class SessionsController < Devise::SessionsController
respond_to :json
def create
super
session.options[:renew] = false
end
def destroy
logger.info "Logging out: #{current_user.email}; Session Id: #{session.id}"
$redis.del "cart_#{session.id}"
super
end
end
So I have this app that I'm making where users have profiles after they signup and input their information.
At the moment I'm trying to add a feature that allows for new unregistered users to go to a profile to see what the app is like before they need to sign up (I'm planning on putting a "try it for free" button on the home_controller#index action. For authentication, I'm using the Devise gem.
Currently, I've watched the Railscast (393) on this, but I can't figure out (after several hours of trying) how to implement guest users and log them in using Devise.
I've also read about 4 different solutions on SO, and have decided to stick to this one (how to create a guest user in Rails 3 + Devise):
class ApplicationController < ActionController::Base
def current_user
super || guest_user
end
private
def guest_user
User.find(session[:guest_user_id].nil? ? session[:guest_user_id] = create_guest_user.id : session[:guest_user_id])
end
def create_guest_user
u = User.create(:name => "guest", :email => "guest_#{Time.now.to_i}#{rand(99)}#example.com")
u.save(:validate => false)
u
end
...
end
I have this in my application_controller.rb and don't understand how I would use these functions in the home_controller#index to create a guest user and log into the profile when the "Try it" button is clicked.
I've tried manually creating a user, saving it without authentication and then using Devise's sign_in method on link like so: Try it! and also tried
Try it!
I tried this, but the profile throws some validation messages saying I need to log in to view it. I've also tried removing before_filter authenticate! on the profiles_controller but I can't seem to get this to work at all.
Would anyone know how to create a user on the button click, and auto sign them into a guest profile? Thanks a lot for any help, I'm completely lost here.
I think you have a misunderstanding on what a guest user is. You say that you want guest users to auto sign in, and that is wrong. Guest users can't sign in, because... Well, because they are guests. You want to create them, but not sign them in.
This is why you want these helper methods in your ApplicationController, because when you try to get the current_user, if that doesn't exist (nil), you will have a fallback (that is why you use the || operator), that will assign a guest_user as a current_user.
So, forget about using sign_in links for guest users and you should be fine.
With Ruby on Rails, my models are being created with increasing unique ids. For example, the first user has a user id of 1, the second 2, the third 3.
This is not good from a security perspective because if someone can snoop on the user id of the last created user (perhaps by creating a new user), they can infer your growth rate. They can also easily guess user ids.
Is there a good way to use random ids instead?
What have people done about this? Google search doesn't reveal much of anything.
I do not consider exposing user IDs to public as a security flaw, there should be other mechanisms for security. Maybe it is a "marketing security flaw" when visitors find out you do not have that million users they promise ;-)
Anyway:
To avoid IDs in urls at all you can use the user's login in all places. Make sure the login does not contain some special characters (./\#? etc.), that cause problems in routes (use a whitelist regex). Also login names may not be changed later, that can cause trouble if you have hard links/search engine entries to your pages.
Example calls are /users/Jeff and /users/Jeff/edit instead of /users/522047 and /users/522047/edit.
In your user class you need to override the to_param to use the login for routes instead of the user's id. This way there is no need to replace anything in your routes file nor in helpers like link_to #user.
class User < ActiveRecord::Base
def to_param
self.login
end
end
Then in every controller replace User.find by User.find_by_login:
class UsersController < ApplicationController
def show
#user = User.find_by_login(params[:id])
end
end
Or use a before_filter to replace the params before. For other controllers with nested resources use params[:user_id]:
class UsersController < ApplicationController
before_filter :get_id_from_login
def show
#user = User.find(params[:id])
end
private
# As users are not called by +id+ but by +login+ here is a function
# that converts a params[:id] containing an alphanumeric login to a
# params[:id] with a numeric id
def get_id_from_login
user = User.find_by_login(params[:id])
params[:id] = user.id unless user.nil?
end
end
Even if you would generate random INTEGER id it also can be compromted very easy. You should generate a random token for each user like MD5 or SHA1 ("asd342gdfg4534dfgdf"), then it would help you. And you should link to user profile with this random hash.
Note, this is not actually the hash concept, it just a random string.
Another way is to link to user with their nick, for example.
However, my guess is knowing the users ID or users count or users growth rate is not a vulnerability itself!
Add a field called random_id or whatever you want to your User model. Then when creating a user, place this code in your UsersController:
def create
...
user.random_id = User.generate_random_id
user.save
end
And place this code in your User class:
# random_id will contain capital letters and numbers only
def self.generate_random_id(size = 8)
alphanumerics = ('0'..'9').to_a + ('A'..'Z').to_a
key = (0..size).map {alphanumerics[Kernel.rand(36)]}.join
# if random_id exists in database, regenerate key
key = generate_random_id(size) if User.find_by_random_id(key)
# output the key
return key
end
If you need lowercase letters too, add them to alphanumerics and make sure you get the correct random number from the kernel, i.e. Kernel.rand(62).
Also be sure to modify your routes and other controllers to utilize the random_id instead of the default id.
You need to add a proper authorization layer to prevent un-authorized access.
Let us say you you display the user information in show action of the Users controller and the code is as shown below:
class UsersController < ActionController::Base
before_filter :require_user
def show
#user = User.find(params[:id])
end
end
This implementation is vulnerable to id guessing. You can easily fix it by ensuring that show action always shows the information of the logged in user:
def show
#user = current_user
end
Now regardless of what id is given in the URL you will display the current users profile.
Let us say that we want to allow account admin and account owner to access the show action:
def show
#user = current_user.has_role?(:admin) ? User.find(params[:id]) : current_user
end
OTH authorization logic is better implemented using a gem like CanCan.
I have a Rails site that requires a lot of form fields that need to be filled out after the user first signs up (using a large jQuery wizard). At first, I wrapped all the "getting started" (executed when the user logs in for the first time) specific code in the users controller like this:
Class UsersController < ApplicationController
def new
#user = User.new
end
def getting_started
def getting_started
#user = User.find(current_user.id)
unless #user.employees.length == 15
15.times { #user.employees.build }
end
end
end
My question is, should I separate out the getting started method into it's own controller if the getting started method is beginning to grow rather large? What is the "rails way" of doing this?
Size isn't what dictates a new controller--controller purpose dictates a new controller. If it's not related to a User and is entity-like on its own, new controller. If it's just more User data, it should stay.
If it's simple size you're concerned with, it depends. If it's code acting directly on a User, it may belong in the User model. If not, it belong in private methods or its own library.
Without further details regarding what getting_started actually does, it's difficult to be more specific.
I'm trying to allow users to vote on threads without having to sign in/up in order to increase user engagement. How do I do this? At the moment my current though process is to tie votes with the visitor's IP address in order to prevent multiple votes, though another issue is that request.remote_ip is not getting me the correct IP (I'm on a school network). Any suggestions? Thanks very much!
Vote action in Threads Controller
def upvote
#thread = Thread.find(params[:id])
current_user.up_vote(#thread)
flash[:message] = 'Thanks for voting!'
respond_to do |format|
format.html { redirect_to :back }
format.js
end
Vote routes
resources :threads do
member do
post :upvote
post :unvote
end
I wrote acts as votable.
The whole idea behind this gem was to allow anything to vote on anything (so there is not hard dependency on a user, like in the situation you are describing).
If you do not want to use IP addresses to store votes then maybe you can use a unique ID that you tie to each session. This would be open to vote fraud, but it would allow anyone to vote without having an account.
You could do something like
session[:voting_id] ||= create_unique_voting_id
voter = VotingSession.find_or_create_by_unique_voting_id(session[:voting_id])
voter.likes #thread
You would need to setup a VotingSession model that acts_as_voter and maintains a unique voting id, but that should be really easy w/ rails.
Hope this helps
Finished Code
Ultimately I decided to tie it into the user's ip address.
First you have to create a Session model and db table, then you make the model acts_as_voter, and in your controller action you add the following lines.
session[:voting_id] = request.remote_ip
voter = Session.find_or_create_by_ip(session[:voting_id])
voter.likes #thread
#kyle K : if you are using Devise as I was, you can follow the following link for getting the guest user created for the anonymous user actions.
https://github.com/plataformatec/devise/wiki/How-To:-Create-a-guest-user
good thing with above is that you can also take care of handing over the guest user resources back to the actual signed in or registered user if the guest user converts within the same session using the 'logging_in' method as described in the article :)
what I did is:
voter = current_or_guest_user
voter.likes #thread