Devise User Inheritance and user_signed_in? and current_user - ruby-on-rails

I'm using devise to help with my authentication and for various reasons I have a couple subclasses of the User model that helps separate the concerns for registration and some other business logic.
The subclasses of User are Affiliate and Admin (and I might have more in the future), all of which store all of the data in the User table (not separate tables).
All users can log in via the default users resource (/users/sign_in). However, this is where I'm having an issue.
If the user signs in via the /users/sign_in resource I can access the user_signed_in? and current_user helper and then access any other Active Record associations. This is what I want! Woo hoo! This works great.
However, the same is not true of a user who signs up as an Affiliate. Since devise automatically logs the user in (which I DO want) I expect that user_signed_in? to equal true and current_user to be the user that just signed in. This is not the case when a user signs up via the /affiliate/sign_up resource.
On the Affiliate model (remember, it subclasses user like such class Affiliate < User) I have generated (through devise) a separate set of controller/views for sign_up so I can customize this process a bit (as the sign_up process is a bit more customized for this particular type of user). When the user signs up via this resource /affiliate/sign_up the affiliate is then signed up, but NOW, the current_user is nil and user_signed_in? is false. But, the helpers current_affiliate is a hydrated object and affiliate_signed_in? is true.
What I want to do is be able to access ONE type of helper - the user_signed_in? helper and the current_user helper not the child affiliate_signed_in? and current_affiliate. I'd like to access: current_user and user_signed_in only. Seeing that Affiliate subclasses User, why doesn't user_signed_in? and current_user returned the current user (aka: the Affiliate)? Why do the current_affiliate and affiliate_signed_in? helpers work, but not the user-esque ones not?
Is there a way to make the framework always use current_user and user_signed_in? helpers since everything is subclassing the User model?

The way you set it up, it seems that you are able to log in as both a user and an affiliate at the same time. That means, that at a given moment there could be a current_user and a current_affiliate. If you want it to be current_user all the time, you can override the Devise helpers. But you have to make sure that a there can only be a user OR an affiliate logged in, through one session. Else Devise has no way of knowing which object to return for current_user.

Related

How do you restrict access to a certain webpage?

I am trying to allow access to the log-in/sign-up page for a admin user only from my computer or any other way that lets me only see the web page for an admin sing-up-log-in.
Or what do typical web applications do to restrict access to the public towards a certain web page? If there is a bets-practice way, I would like to implement that.
I currently have Devise installed.
You can use the authenticate_user! Devise helper, adding it as callback within the needed controller and specifying the methods you want to control.
For instance if you have a Post model, then adding the authenticate_user! in the PostController it'll ask the user to be logged to have access to the methods in that specific controller:
class PostsController < ApplicationController
before_action :authenticate_user!
If you want to restrict just some specific methods then you can play with only and/or except.
See: Devise will create some helpers to use inside your controllers
and views. To set up a controller with user authentication, just add
this before_action (assuming your devise model is 'User')
Devise - Controller filters and helpers
According to your comment then you can create a method in the ApplicationController in order to restrict all of your controllers and methods.
This way you can define an array of addresses, and if the remote_ip coming from the request is in the array then you give access, if isn't then perform any other action:
ApplicationController < ActionController::Base
before_action :protect
private
def protect
addresses = ['127.0.0.1', ...]
if addresses.include?(request.remote_ip)
# give access
else
# restrict access
end
end
end
But if you need something more sophisticated then you'd have to see on your Nginx or Apache, whatever you're using to deploy your project.
I normally restrict webpage access through controller methods. My recent use case was going to a webpage only when payment was successful but redirecting when it was not, if any body issued a get request for that page directly, it would result in 404.
In your case, there can be multiple option for setup.
You can use cookies to see users credentials using Action Dispatcher
Use Devise for users and then you can fix a certain role to a user through adding a new migration and assign roles yourself after registering or let them choose.
I will expect you followed Devise route. In the controller action check for current user's role.
If User Not signed in (using current_user == nil)
redirect to home page and then return
else
if
its admin you go ahead and use the success page as partial and let them see the page using `<%= render 'pages/mypage'%>` and use return to end
else
just redirect back to home page with a notice "Don't try this".
redirect_to root_path, notice: 'Don't try this' and then use
return to end
end
(Just for fun, to see how many times a user did this wrong action, you can also have a table which stores current_user and number_of_wrong_attempt, and store their email whenever they try to go that page without permission before redirect in controller. After that you can email them with a background rake task which checks for a certain false attempt threshold that: "Hey! Your registration is being removed because you are doing unprohibited actions")

Rails Pundit how the policies are worknig?

I have a web application in ruby on rails with devise as the authentication and pundit as the authorization.
I have a model user with an integer role attribute with values 0, 1, 2, for visitor, vip, and admin respectively. I also have a scaffold, say Page that I want just vip and admin to have access to and not visitor users.
In page_policy.rb I have
def index?
current_user.vip? or current_user.admin?
end
and in pages_controller.rb I have a line authorize current_user.
Although I have given access to vip but it is available just for admin user. Where have I been wrong with the code?
Thank you
I assume you have properly set up your predicate methods vip? and admin? on the User model, and these work as expected? Can you check the result of calling each of these methods on your current user?
Pundit actually passes the result of current_user to your policy initializer, and you can access that via the user method inside your policy methods. Also I would be careful of using the or operator in this context (see http://www.virtuouscode.com/2010/08/02/using-and-and-or-in-ruby/).
So I would try:
def index?
user.vip? || user.admin?
end
Also, pundit expects you to pass the resource you are checking to the authorize method, not the user object. If you don't have an instance to pass, you can pass the class:
authorize Page

Accessing newly singed up user in Rails app using devise

I am currently making Rails app using devise.
After a new user signs up, I need to access newly singed up user's information to run my customized function.
However it seems like devise's current_user is nil since the user is not logged in yet until the user confirms the email.
I essentially just need to check whether user's confirmed_at is nil.
Is there a way to do this?
I would do this in the User model with a callback:
# in app/model/user.rb (assuming you have a User model)
after_create :run_customized_function
private
def run_customized_function
# whatever need to be done with this user, for example:
# Rails.logger.info("User##{id} just signed up with email '#{email}'")
end

Rails How to Login a Guest User with Devise

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.

where's the appropriate place to handle writing the current_user.id to an object

I am not using Devise but have implemented a simple authentication scheme (basically outlined here http://railscasts.com/episodes/250-authentication-from-scratch) with the relevant part being here:
application_controller.rb
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
I have a list of assets that a user must be authorized to add. I am using paperclip. A user can has_many and a asset belongs_to a user (although this is essentially irrelevant to where it is assigned since my asset model is polymorphic for different assetable_types).
Where should I assign the current_user id to an asset? I would think in the model; maybe I should do a default_values using the session[:user_id] but that seems to be kinda ugly.
Also, these are nested_attributes and the models that these are nested to, currently don't know anything about the user. So really the source of information for the current_user isn't part of the current association.
thx
edit 1
should I create an instance of a User based upon the session[:user_id] value or just push it in?
If I understand your question correctly, why not assign the user to the asset in whichever controller first finds out that the asset belongs to the user? It's the controller's responsibility to translate web requests (including the session / current user) into something applicable to the model.

Resources