Ruby on Rails - Adding a second (extremely) simple Auth layer in app - ruby-on-rails

Once a user logs into their account, they are presented with a list of 'Employees'.
As of right now, when you click an employee, it takes the user to the 'show' page of that specific employee, however I want to add a 'pin-protected' aspect to that list before it renders the show page.
I want to add a simple layer of authentication that would go like this:
When a user clicks their name on a list, a text-field appears that asks for the selected employee's pin.
The user types in the pin. On submit, it compares the inputted pin against the 'pin' column for that employees' record. If it's correct it grants access to the selected employee's show page.
Is this something that is easily done in RoR? This is the first real app I have worked on, so I am having trouble wrapping my mind around a couple concepts like these.
Thanks so much!

Take a look at devise, it's most definitely your best bet for Ruby on Rails 3 authentication layer.
You're best bet if you just want to add a little functionality to your existing model class would be to add a method along the lines of:
def validate_pin(pin_to_check)
self.pin == pin_to_check
end
And then you just need to modify your employee controller so that show method checks to see if the pin has been provided (ideally via a session variable), otherwise redirect and request the pin with an additional method and route Employee#request_pin in the controller which asks the user to enter the pin, on success redirecting to the Employee#show route.
Session handling in the controller
To write the session variable, you'd need an Employee#check_pin method (as a POST route) and you'd just use the code:
session[:pin_valid] = true
Then you'd check session[:pin_valid] in your Employee#show method

Related

Render a form in a modal(bootstrap) and make it available on another controller's view

It's been a while since I've used Rails and I think I've gotten a little rusty. Is there a way to do this?
I'm trying to make a messaging feature that allows one user type to message another. I want the button to display on the User index page and the user show page. When the button is clicked a modal will popup with a form contained therein.
Currently I've made a Message model with three columns: user_type1_id, user_type2_id and message_body.
Should I make a distinct controller for this new model? Or should I put the logic in the controller of user_type1 (the usertype that will be messaged)?
Any other suggestions would be welcome.
Controllers are there primarily to get data from the database and get it ready for the views. So if you have user#index and user#show pages, then you should use the UsersController for all the logic associated with those views, even though it uses other modals. It really is the "Rails Way". If, however, you were to create a message#index page, then you should create the associated MessagesController.
Also, there is nothing wrong with creating a partial and sticking in the messages view directory (the filename would be, say, messages/_form.html.erb). Then, whenever you needed that form (throughout the entire site), all you would need to do was type:
<%= render 'messages/form' %>

Ruby on Rails Routing with Comments

I am trying to create a comment model for my posts and the question is how am I able to create comments but not have the routes nested inside of the posts...
That is, there is no route to posts/comment/:comment_id and instead just have the user enter a comment and let the user stay on the page without having to transfer the user. I want the user to have no interaction with a different route and just have them say where they are.
Not sure I understand correctly, but if you don't want the user to be taken to a new page after creating a comment just remove the "render" method in the action for the comment controller.

How to trigger modal when event occurs in Rails

I'm sure that there is an answer to this out there, but I'm not entirely certain how to properly phrase this question, so my apologies if this is repetitious.
I am working on implementing a badge/achievement system for a site. The backend stuff is there, but I'm working on the front-end now, and I'm basically trying to figure out how to redirect to a sort of "Congratulations!" page when someone gets a new badge.
The congratulations page is going to be a modal, but for simplicities sake, if anyone has an idea of how to trigger an action like this only once when a new Badge is created, that would be a huge help. Right now, when a user performs a given action, say... adding money to their account, a user_badge is created (adds a Badge ID to an array).
Thanks in advance!
You can use before_filter for actions, where you want to check that new badge appears (probably you don't want to check it in auth actions, so you can't use global before_filter). Then you can use redirect_to in this before filter, if user has a new badge.
But I don't recommend to do so, since you'll break the users flow. It's better to show alert/modal on the next requested page. To achieve this you can define a new instance variable in your before_filter (like #show_modal) and include the partial with modal to your footer.
example:
#before filter
def check_for_new_badges
if current_user.has_new_badges?
#show_modal = true
current_user.set_badges_as_seen!
end
end
#included in layout
- if #show_modal
= render 'shared/congrats_modal'

Generating secret URLs for a resource in rails

I've created a task management app that consists of lists and tasks. Users can only view their own lists and tasks. I would like to add the ability for a user to share a list if they like. Here are the steps I would like to accomplish:
User clicks a link from /list/show to share the list
User receives a secret URL to share: myapp.com/lists/1/23534512345234523 or whatever.
Secret URL redirects to a view other than /lists/show. Something like /lists/1/23534512345234523 which would be routed to /lists/secret_show or whatev.
Only users who have that url can see the information on that page.
Hope that is making sense. I imagine I would have to update the list record with a unique token to list.token. Then I would some how have to recieve the incoming URL and through a new action
lists#secret_share
def secret_share
...
end
Where I filtered for the list record by list.token and routed to secret_share. Then perhaps in the view I could simply restrict the view by the presence of the token in the URL.
Thoughts?
Whatever "secret URL" you hand out should not redirect to the real URL or you're going to create all kinds of opportunities for information leakage. It should be a strictly alternate URL.
Using routing for this seems like a good idea instead of using a separate controller. In your route you might want to pass an additional parameter to indicate this is a "secret" URL, like :secret => true where the value in question is something that cannot be submitted by the user to fake things out. User parameters are always strings, for instance, so using true should be a safe alternative.
This special parameter might disable access checking on your controller so that the page can be viewed by people that don't normally have access. You could also show a different layout using the layout method in your controller.

Rails 'routing' based on model properties

I am trying to do different things on the home page of my application based on properties of the currently authenticated user. For example:
location, user, state, -> destination
/, no user -> a home page
/, user authenticated, state: unverified -> user profile page
/, user authenticated, state: verified -> a content listing
What this looks like is that I am trying to 'route' based on the current user's state (as represented by a state machine). These 3 actions already exist in 3 different controllers (I call them 'pages', 'users', and 'posts'), but while one can call another controller's view, one can't call another controller's action, making it a little tough to not repeat myself. There's a number of ways to deal with this, but I'm not sure what The Rails Way is for this, so I thought I'd ask. I see as my options:
Use redirect_to in a hypothetical 'redirect controller', but I want the page to appear under /, so this isn't what I want.
Get fancy with a routing constraint (not sure this is possible; need sessions/cookies available in routing and I'm not sure that's the case)
Pull the logic for the particular actions out of their respective controllers, toss them into ApplicationController, and use them directly based on the user's state in a hypothetical controller (or just toss it into pages).
Repeat myself significantly, either in the controller, the views, or both
Yet-unknown options, I'm open to suggestions.
I'm leaning towards the third option, with the obvious downside that some piece of those controllers will now more or less inexplicably live in the ApplicationController (unless, god help me, I do some sort of Lovecraftian include-on-extend). Having this code live in two places feels dirty to me.
Am I missing something obvious?
Would a single action that uses a helper to pick the right partial based on the current state of the user work?
Also, take a look at using ActiveSupport::Concern instead of getting all Lovecraftian include-on-extend. http://api.rubyonrails.org/classes/ActiveSupport/Concern.html

Resources