rails access signed in user and the user id for the profile for a multi-page profile - ruby-on-rails-3

Hi clever programmers,
I've been searching and reading a couple days, but I need some Rails help-
Here is my goal: I want to make a multi-page profile for each user, and I'd like to handle this profile with a profile controller.
The problem? How do I make the 'show' REST action apply to an entire controller instead of just one page? Specifically, how can I have both a #current_user and a #user variable available in the Profile controller that correspond to the signed-in user and the current user's page.
I'm not sure if I should be making routes with multiple :id s in the route or if there is some way to persist the signed-in-user in something like #current_user when they sign in that is just available everywhere and then I would use the :id of the user who's profile it is in the route. I'm pretty sure facebook does something like facebook.com/{your_id}/{their_id}/ for example.
I tried accessing #current_user from my session_helper.rb class but it came up nil and I'm not sure how to pass the :id to use User.find(params[:id]) because the profile controller is not affiliated with the resource for the User model.
Any protips or links to helpful readings would be much appreciated. I'm a beginner so feel free to suggest a better course of action if I'm going against the rails way. Thanks in advance!

You may not know but you can store session data, and user_id it's really common thing that people saves on it.
So for saving at the sign in
session[user_id] = ....
Then you could have something like this on a helper
def current_user
User.find(session[user_id]) if session[user_id]
end
You should check the gem called devise. It provides all the functionality for aunthentication and it also provides a current_user method everywhere. You should check it at least to see how they have implemented that method.

Related

Nested Business Model in Devise Sign Up

I'm relatively new to rails and am using devise for my user sign up and sign in processes. At sign up if a user doesn't have an invite token I would like them to also sign up and create their business that will be associated with their user account.
Below is a screenshot of the error I am getting in my RegistrationsController when trying to create the new business.
Here is my code in the registrations_controller.rb:
if params[:invite_code]
...
else
resource = build_resource({})
resource.businesses.build() # Inserts a blank object for business
respond_with resource
end
Any ideas on why it isn't able to pass the business information provided and create a new business? Thanks in advance for any help.
I think it's just a pluralization issue. The has_one association on the User should be singular (:business) as should the method call in the controller (resource.business.build()) and accepts_nested_attributes_for.
That being said, that part of the controller should never even be getting hit. All of your logic should be contained within this first conditional. Everything happening here should probably be pulled out into another method and called after the successful save. Here's a new gist with a refactoring of registrations_controller.rb: https://gist.github.com/ccschmitz/7ea0a41180e25de9168d

Mixing secured users and visitors on the same site

I suspect this is more a question of best practices than code. If I have a site (RoR3 and Devise) where a registered user can upload and create documents into a database with the normal collection of views. Of course the user must first sign up and log into the site. Having created a document they might want to send out a link to another person who is not registered with the site (and won't be).
So what I envision is a set of views that are "read only" if you will where the invited person can view the document but can't navigate outside that view, except for the home page. Devise doesn't seem to have the concept of a non logged in visitor that I can see and I haven't found anyone who has done this.
Thank you
Yeah, this can get tricky, especially if non-registered users can do some stuff but not all. We tried a couple of approaches to solve this problem in a company I recently worked for, including the invitations aspect you mentioned.
Because our entire app revolved around users, when a user visited the site, we created an instance of User. If the user was signed in the user model would be backed by a database record, and if not, they were just a virtual user and we used session data to store semi-persistent state information.
In application_controller we set current_user to either the real user or just an object, so it was always available, and quacked like a user, especially including a registered? method
At first we wrapped tons of stuff in our views with if current_user.registered? all over the place. But that quickly got to be a mess. The better pattern (in cases where the differences were significant) would be to create partials that like _sidebar and _sidebar_registered, so we could create a method that, given the root name of a partial rendered the appropriate one depending on user state.
In the case of invitations where users have limited access to content if they were invited, we wrote an invitation module that was backed by a model. The invitER could send an email from the system, or generate a URL with an embedded token. We stored the token in a table so we knew who invited whom, which was necessary in our case -- looking up the token was all that was needed to authenticate. Once the user was sorta-authenticated, we stored the state in the session, and a method on User (invited?) would let us know if the user had access.
In general there were certain whole controller actions that only registered users could get at (e.g. edit/delete) we would just use before_filters in the controller to control access. It's mostly in the view's that things got messy.
We did look at CanCan as we started getting different levels of user authorization. But I can tell you, this can balloon into rather gnarly code quickly unless you carefully segregate who can see and do what.
Devise provides you with the user_signed_in? method and the current_user method to help you with this kind of thing. For example, in your view you could have something along the lines of:
<% if user_signed_in? %>
<%= current_user.username %>
<% end %>
etc.
If your permissions get more complicated, I would recommend using an authorization gem to help you manage your restricted sections. A couple of examples are Declarative Authorzation (my personal favorite) and CanCan.

Rails 3: How Does One Restrict Access to IDs

This might be very simple; I don't know Rails very well.
I have a match myController/myAction/myID in my routes.rb that will direct hyperlinks to the proper page (using link_to). But here's the problem: I don't want people to be able to freely modify the id parameter, passing in via the URL whatever they like.
Is there a way to perhaps restrict access to routes to the link_to method only? Or maybe there's another way to go about this, using a passed in hidden variable param or something?
Users access you site via urls like: /controller/action/:id right? A user can change an id and must not view another non authorized resource. How to achieve this?, on your controller, return only those resources that user is allowed to access.
For example, suppose that you are using devise:
class AController < ApplicationController
def index
#resouces = current_user.find_all_by_id params[:id]
end
end
This way if the user tries to access something he does not have access to, he will get an error.
Hope this helps, if not please let me know and I'll try to elaborate.
About current_user, yes it is supposed to be the current logged in user, it doesn't have to be devise, you can implement your own session handling logic and then create a helper method to retrieve the currently logged in user.
About using devise, if you don't want to implement your own session handling logic, plus if you want features like:
remember me
already created views that you can fully customize
authentication
authorization
password encryption
many more (please look at the docs for further information)
Then devise is a good way to go.
Also, it is always a great idea, if possible and as a learning exercise, implement your own authentication and authorization layers, you won't regret.
Best regards
Emmanuel Delgado

Should I use an authorization gem for this or a simple before_filter method instead?

I have two types of users: user and editor. I have a User model with the boolean column is_editor to determine if a user is an editor.
Let's assume. User Foobar decides to sign up as an editor. He succeeds. From today onwards, he is an editor. One day Foobar accidentally navigates to the editor registration page (registrations controller, new action).
Since Foobar is already an Editor, I should redirect him to his profile page. Should I use an authorization gem (such as Cancan) for this? Or should I have a simple method (i.e. before_filter :check_if_user_is_not_an_editor) in the registrations controller that checks if user is already an editor and redirect?
If I end up using the Cancan approach. The thing is, I already have the following that checks for other authorization.
rescue_from CanCan::AccessDenied do |exception|
flash[:alert] = exception.message
redirect_to root_url
end
Which will render a flash alert message: You are not authorized and redirect to root url. Which is not what I want, because I need to redirect to Foobar's profile instead.
What are your thoughts? Is this the task of authorization or just a simple redirect in the said controller? Which is the more appropriate approach?
Honestly, it seems pretty minor so whatever you choose, I wouldn't feel bad about your approach. Personally, I would go with your second option (simple redirect). First of all, it seems simpler, which is always a plus. If you're using an authentication solution like Devise, you probably have a current_user or user_signed_in? helper that you can use in a before filter quite easily. Secondly, it doesn't really strike me as the type of problem that authorization is concerned with.
In one sense, it is a permissions concern (I guess semantically anyways) since your application defines behavior that is 'not allowed'. Realistically, it's not allowed but not because the user doesn't have necessary permission. The reason the behavior isn't allowed is because no user should be able to register as the same type of user they're already registered as - that is, there are no user types that should be able to do such a thing so the currently-logged in user's permissions are moot. It seems like your problem should be resolved by defining application behavior - not user permissions.
Just the way I see things, feel free to implement whatever solution you feel fits best.

Using Devise with a singular Resource

I'm a newb with Rails and am trying to get out my first Rails 3 app with Devise. I have a situation where pretty much everything on my site is specific to a user. I'm creating a kind of private gallery that isn't public facing, so that every image belongs_to a user and a user has_many images. Here's my issue... I want to rework my routes so that showing a users images doesn't require a user id in the URL. I will be showing a user's images in the user/show route.
current route (from rake:routes):
/users/show(.:format) {:action=>"show", :controller=>"users"}
Is it possible to have devise use only "resource" instead of "resources"? so it would be /users/show/? Am I making sense? I am not sure the terminology to ask, but I want all of a user's functionality to imply that I know who the user is, then I can check that in the controllers.
Thanks!
In your controller, for the show action:
def show
#user = current_user
end
That's all you need to do. If you were EXPECTING an id, then you do something like #user = User.find(params[:id], but since you know what user you want (in this case, the current_user, which is exposed by Devise), you don't need to do anything special.