DRY way to handle users with multiple accounts in Rails app - ruby

This is a Rails app for a school. I'm using Devise for user accounts. So far each user has a .role of admin, teacher or student which restricts what the user can access and contribute in the app. I'm using user.email to log in. All is working great so far.
Now I've realized that I have a problem with sibling accounts. The unique user.email used for logging in is actually the parent's email address (since the students are minors) and now I have to account for a parent with two or more children who are students. I obviously can't have a student account for each child and use the same email address because it has to be unique (and I do want to keep the requirement in the validation).
Given that I already have a large chuck of the app done, what would be a nice DRY way to account for this situation?
I've searched this site and others but not really found anything that accounts for this situation.
One way I thought would be to change the role in the User model to parent and then have a separate Student model . A user with the role of parent could then has_many :students but this doesn't sit well with me.
Any general ideas/concepts would be appreciated, as would any pointers to articles or gems that would help me with this.

I don't know if it's the best way, but one approach would be to append a sibling-unique identifier to the name portion of the parent's email address for all student email addresses. You could do it in such a way that it could be stripped off when you wanted the "real" email address. There's actually some precedent for this kind of approach, per http://www.plankdesign.com/blog/2013/06/testing-infinite-unique-email-addresses-with-gmail/.

Related

Google Classroom API: Courses list returning unavailable classes

I am trying to fetch a list of classes which the current user has access to, and I am getting classes returned which the user cannot access.
Using the ruby client I can call
service.list_courses(course_states: "ACTIVE")
# I have 7 courses returned
OR
service.list_courses(course_states: "ACTIVE", teacher_id: "me")
# I have 3 courses returned (just mine)
The issue is that in the first call there are 4 courses returned which the current user cannot see/access. This seems like it shouldn't be happening as the docs say Returns a list of courses that the requesting user is permitted to view, restricted to those that match the request.
Is this a bug which I should report in the issue tracker or am I misunderstanding what results can be returned in the courses list?
My use case is that I want to create a course work item in a course, but I only want to do this for courses that the teacher can access. I thought that the list courses should return exactly that list, but, it doesn't seem to (unless I specify teacher_id: "me", but then I'm worried I'll miss courses which the teacher is collaborating on (if that's even possible))
Is this a bug or am I misunderstanding something?
Edited to add
Thanks to #ziganotschka for the API details. After further testing, calling service.list_courses(course_states: "ACTIVE", teacher_id: "me") will return courses that the requesting user has created or courses that the requesting user is collaborating on. This wasn't obvious to me as the course object has an owner_id field which is a single user, so, I thought the teacher_id might be referencing that.
The issue I had been running into was that I was logged in as the super admin which according to the answer below allows me to see all the courses. However, I wasn't actually able to access the weblink of any of those courses which is what was confusing me.
The behavior of the API is following:
service.list_courses(course_states: "ACTIVE") returns for anyone all the courses in which he/she is participating - be it as teacher or student.
If an admin calls service.list_courses(course_states: "ACTIVE") he can see all the classes of the domain - this is intended behavior.
service.list_courses(course_states: "ACTIVE", teacher_id: "me") will return only the classes owned by me.

CustomerInfo nickname and reference_id usage in different platforms

I find that the nickname and reference_id fields work differently across platforms and I'd like to get clarification on how they should be used.
With the API, I can retrieve and set both these fields.
In the web-based dashboard, both fields are displayed and can be edited if present, but there's no way to enter a nickname when creating a new customer.
In the Register iOS app, none of these fields are shown or editable. They're also absent when creating a new customer.
What I want to do is map Square Customers to our existing members, but we're facing three problems:
reference_id seems to map perfectly with our existing member numbers but, as mentioned, it's nowhere to be seen in the Register app.
Searching customers in the Register app only searches in names and emails. It would really help us if it searched in reference_id as well.
CustomerGroupInfo is read-only via the API (and not even an endpoint). We would map these to our membership levels.
As of now, I'm looking at ugly workarounds, but I wanted to know if something in the roadmap could help us out. Thanks in advance to the people at Square!

How to work with not (yet) registered devise Users

I have a User model, for login and registration, its email field is used (everything vanilla from the devise gem).
I want (other) users to be able to e.g. add Users to a team, with the email-address as the identifier.
That is fine when the User is already existing (pseudo #team.users.add(User.find_by(email: other_users_email))) but I am unsure how to handle situations where the user does not yet exist (did not [yet] register).
When a (new) User sets up a new account, for the example above after successfull registration current_user.teams should show up correctly.
I do not want to force these potentially new users to use the system (e.g. using devise_invitable) and bother them with an email.
I followed the path of creating the User when a user with the given email does not yet exist, but then when the user actually tries to setup an account, it fails (email not unique).
Alternatively, I could remodel the TeamMember-part and let it optionally either store an email-adress or the reference to an existing User. Then what I would need is to check for "open" TeamMembers directly after User-Account-creation (so, TeamMembers with the given email). I could also do this on each requst, but that looks too expensive to me. There might be race conditions, but I could live with that (and check for the every-now-in-a-millenia-gap with a cron-job).
Any pointers? I am sure this is not that unusual.
I'd do this:
When a user A adds user B to a team by email, create the object for that user B, but set a flag, something like auto_created_and_inactive: true
When user B signs up on the site, you just have to handle this in your users#create: first, try to find an auto-created record and update it (set a password or whatever; also reset the flag). Or otherwise proceed with the usual route of creating a new record.
I have to admit that I did not yet tried #sergio-tulentsevs approach (implement RegistrationController#create). But to complete what I sketched in my question:
User model can define an after_confirmation method, which is called after ... confirmation! So, if I store every information about a potential user with a reference to his/her email-adress, once he/she registered I can query this information and e.g. complete Team-Memberships.
# app/models/user.rb
def after_confirmation
# (pseudo-code, did not try)
self.teams < TeamMembership.open.where(email: self.email)
end

all queries default to users company

I am using cancan and trying to get it to limit equipment shown for a specific company.
I have a company with many users that should only see equipment that belong to that company.
I thought cancan could do this based on this:
Rails 3 company account with many users, restrict access to data
So I tried this code:
can :manage, Equipment do |equipment|
user.company == equipment.company
end
In the equipment controller I have #equipment = Equipment.all which I figured would just pull the equipment for that users company, but of course it pulls them all. Is there an easy way to do this or do I need to do #equipment = Equipment.find_by_company_id(current_user.company) anytime I want to pull just that companies equipment. To make this worse I want to eventually break it down by groups and departments, but would rather not have to force myself into more big find queries. I am open to anything, plugins, suggestions, whatever will be the fastest way to fix this.
I could have added more code to this question, but I don't know that adding it all would really help the question.
Thank you very much
Toby
Try Equipment.accessible_by()
https://github.com/ryanb/cancan/blob/master/lib/cancan/model_additions.rb

Best practices for allowing users to choose a display name on a social networking website?

I run a social networking / blogging website ( http://www.obsidianportal.com ), and currently the users are identified by their unique (and unchangeable) username everywhere. Many have requested the ability to have a display name as well that they can choose. I'd like to support this, but I'm worried about spoofing and identity theft. So, I'm wondering if anyone has dealt with this and has any advice?
Here's what I'd like to avoid:
I'm known as Micah on the site. I don't want anyone to be able to choose my name as their display name and then impersonate me to others on the site. Similarly, I don't want people to be able to impersonate each other.
Here are some possible avenues I've identified:
Let them choose whatever name they want (within reason: profanity, racism, hate speech, etc.)
Don't allow users to choose a display name that overlaps with an existing unique username
Don't allow users to choose a display name that overlaps with an existing unique username OR an existing display name.
Am I being too paranoid? Should I just chill out and let users pick whatever names they want?
I'd go with the principle of least astonishment, in this case "Don't allow users to choose a display name that overlaps with an existing unique username OR an existing display name." Otherwise you could have 10 different people with nickname Piskvor talking to each other ;)
If the account is linked to a profile with some statistic I think you doesn't require to have to be unique username. If at StackOverFlow someone try to use my name and he is under 1 000 reps, I think it's obvious that I am the real. Of course, someone can use my name here and try to be me, in that case I would require assistance from administrator so maybe you should have a système to report abuse.
In the other way, I have a system that validate the username to be unique. That way, it's simpler. I do this because registered people doesn't have any profile page so it would be hard to know who is the real one.
Hope that help you.

Resources