how can we use cancan gem without being log-in? - ruby-on-rails

I am trying to make a cancan permissions for visitor who doesn't have to login to get some services. To clarify this for example:-
I've a search controller which has new and search actions . In the related new viewer there's some links, some of them I don't want to be seen for non-login users and others must be seen for them!..
I've tried to write these lines in the controller search :-
before_filter :authenticate_user! # this forces the user to log-in ( I don't want this )
load_and_authorize_resource # this doesn't work without authenticate_user
before_filter :load_permissions
in the new view I wrote this
<%= link_to "Listing Managment", extras_path if can? :index, Role %>
but it raises an error for me because of ( can? )
hint: the error arises when I remove the controller's 3 before filter
above. But still not convenient when I put them.

In your cancan initializer you can use something like
user = current_user || User.new
That way cancan will pick up the current user (who may have roles) and if there is no current_user (you are not logged in) will return a dummy user record (anonymous user) with no active roles.

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 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.

How should I display download links to only certain users in ActiveAdmin rails?

I want to hide download links according to user role of logged in user in Active Admin
I want to be doing it like this but I'm not able access current_user
index :download_links => current_user.admin? do
# columns
end
Your question seems to be incomplete.
Guess- You have a User model, id, role, etc as attributes
First, Find the user first based on id, #current_user = User.find(params[:id)
Then,
if #current_user.admin?
# do not show the links
end
Hope you need this to use in views, so use along <% rails tag %>
Try to use current_admin_user, b/c the activeadmin user is called `AdminUser
Devise helper
Or u can define your own method in active_admin.rb like:
config.current_user_method = :current_user

Rails CanCan only show data that user created

I am using Devise for registering accounts and signing in/out. The next functionality I want to add is to only show the data entered for a given user. For instance, if I create a new "something" (a client in my case, at /clients/new), I only want the person who created that something to be able to view it. Right now, if I log in and create a new client, then log out and back in as a different user, I'm able to see the client I created as the other user. This should be restricted so that the author is the only one who can read, update and destroy their own clients.
I've watched Ryan Bate's screencast on CanCan 3 times now, but it seems to only touch on setting it up for different roles, and not for limiting content based on the author.
How can I go about this with CanCan?
My current ability.rb has nothing in it but an empty initialize(user) method.
I have tried this inside that method:
can :update, Client do |client|
client.try(:user) == user
end
with
<% if can? :update, #client %> ... <% end %>
around the loop that displays the clients in the index view, but to no avail.
I think that filtering the results using CanCan is not an optimal solution.
If User 'has_many' Clients, then in your controller method just query for Users' clients:
#clients = current_user.clients
Give this a try
def initialize(user)
can :update, Client, :user_id => user.id
end
From cancan wiki

Devise role based routing

I have an app with multiple users. Each user as a theoretical role (user, client, etc). I've designed a view/controller for each user type.
I want to be able to login each type of user do a different root url and lock them to it.
Originally I was going to add a column to Users in Devise called role and so I can differentiate the users. The problem I'm having is how to say in routes.rb if current_user.role == "client" root :to => 'controller#index'
Once they are logged in to the page I also want to keep them from being able to visit any of my other paths ie: domain.com/calls domain.com/units
I've been looking into cancan to run alongside Devise but I'm not sure if this is the answer.
Instead of handling it in routes, why not handle it in ApplicationController?
#application_controller.rb
before_filter :direct_to
def direct_to
if current_user.role == "client"
redirect_to client_controller_path
# etc
end

Resources