Users and nested (yet potentially independent) "groups" in Rails 3? - ruby-on-rails

I'm having a bit of trouble wrapping my head around something. Basically I'm starting a new project that involves groups of groups of groups of groups of…well, you get the idea.
Anyway, the only model that is somewhat "universal" throughout the application is the concept of Users (as they are what determines what privileges any one person has). The problem comes in when you have groups that can "own" other groups. For instance, you can have a "city" chapter that is owned by a "state" chapter that is owned by a "national" chapter, etc. And, each chapter can have their own users when then have rights to all groups below them.
The thing is, though, that no one group is guaranteed to be owned (or used) by another group, so they would need to be independently managed. I can't quite conceptualize what the methodology would be to handle something of this nature. I mean I could probably use some sort of acts_as_nested setup, but I fear even that may get out of hand. Also, as far as the groups themselves are concerned, should I use some kind of inheritance model (given that they would likely share many properties)?
Perhaps I should simply create an individual MVC setup for each group -- although there's still the issue of associating users, etc. Can anyone offer suggestions?
Best

You could create a groups table which self-references. That would keep all your group data in a single table and the magic is done via associations.
Ryan Bates has a railscast that could likely be tweaked to fit your situation. e.g. rather than friendships, having ownerships or something like it.
Edit:
Having only a single parent helps. It appears the plugin acts_as_tree will likely work for the task at hand. Ryan Bates happens to have a railscasts epidsode for that plugin as well.
Objectives
1: Allow groups to have children, parents Solution: acts_as_tree
2: Allow groups to potentially become or remain independent. Solution: acts_as_tree. Simply remove the parent_id and the group would become it's own root node
3: Enforce hierarchy (e.g cities cannot have another city as a parent). Solution: This would likely have to be done via a custom validation
4: Users rights inheritance. I anticipated this particular objective to be the most challenging. Of course, I don't know all the in's and outs of what "rights" means to your application, but I'll some assumptions... you fill in blanks where I'm wrong. Once you have the associations between users and groups (and possible "rights" table). Solution: To determine if rights should apply to current_user for current_group, a) check ownership and if not b) transverse up current_group.ancestors until you get an answer or hit the root.
It sounds like a fun project. I wish you luck with it!

Related

What is the name of this concept I am implementing, and how to in Rails?

I am trying to implement a feature to my project (kind of like a social media site) that could be either basic or complex and I am not sure if I am going to take forever reinventing the wheel or just go on a crazy tangent that won't work. I just need to "check in" so to say.
I am going to use Facebook terminology as an example to simplify the concept but implement similar features with different names. In Facebook you have Pages and Groups, which are similar yet have slight differences (from now, I will call the collection of these DataSets). Both of these can have multiple admins or followers, which are all User roles, and each User can have roles for multiple Groups and multiple Pages (one role per Group or Page). Then for example, you can click a drop down to change your account to post as a Page you are an admin for.
Essentially, the concept I am describing is where a single User can have a role for multiple different types of DataSets. For example, a single User could follow 30 different Pages and 10 different Groups, and be an admin for one Group and two Pages. Does the concept I am describing belong to a particular concept or software design pattern? I am finding it really hard to describe this feature without using Facebook examples.
I have a strategy to implement this type of functionality in Rails, but I feel like using this strategy would be making the problem harder than it is and there is a fancy rails way of doing it, or a Gem, but I just don't know how to research it due to lack of terminology to describe my problem.
Current strategy is:
I have a Users table from Devise. Pages and Groups are each individual models and have their own tables. I have matching database tables to make the many-to-many relationships between Pages and Users, along with Groups and Users (e.g. 3 column design, column for the user_id, column for the page_id and the type of relationship such as admin or follower). Let's call these Group_User and Page_User. I am being flexible at the moment as I may add more DataSets similar to Page and Group.
Then for the Devise User table, I have an extra two columns to track the DataSet that the User is an admin for and currently posting as. One column is for the DataSet type and the other for the id for this instance (e.g. [Group,1] is stored in these two columns to represent Group with group_id:1 and [Page,3] is used to represent Page with page_id:3). These two columns can be checked when displaying options relevant for admins in that Group/Page and a simple drop down at the top of the site changes the values in these columns to any of the Pages/Groups the logged in User is an admin for. This way, one User login can take on many admin roles and change between these easily as needed.
Is there a better way to do this in Rails, such as a gem or specific design pattern? Or am I on track to implement these features myself? I think I understand the problem but my solution just seems simple/raw and possibly might have unintended consequences later down the track (e.g. it seems database intensive).
One way I was thinking of doing this was making a concern that includes methods to build the relationships and pass in the name of the DataSet as an argument, just so I am not rewriting the same methods for Pages, then Groups, then whatever comes next.
I looked at other solutions such as polymorphic typing (which I think is good for if each user only had one role or only managed relationships for one group or one page) and Single Table Inheritance (but I think my Pages and Groups might be too different for this to work). I thought about using inheritance as well (e.g. a parent for both Group and Page) but I am not sure this helps much.
I am just a guy that studied too much computer science and not enough software engineering. Any tips on how to simplify this problem or just a simple "yeah that will work" would be really helpful!
I think you are going great in the database design. Once participated in a social media application like yours which had similar type of design. Your design seems much better than the one I worked with. In my opinion this type of applications are supposed to be database extensive.
There are several design patterns used in RoR. One I heavily use is Service Object Pattern to maintain thin controller and models. Also it helps me to write reusable class.
Another one I like is the Presenter Pattern to simplify views.
You can have a details look at this blog post for more design pattern ideas.

Should I use polymorphism to model these relationships?

I'm working on an app with Project, User, and Group models. A Project has many groups, a User belongs to many groups through a Membership model. I have two choices:
When a Project is created, a default group is created. Any person participating in this project is automatically added to it.
Make Memberships polymorphic so that users can be a member of a project, and a group in the project.
Both approaches have wider implications: Other models will come into play, such as: File, Post, and Task.
If I go for option 2, those models will also have to be polymorphic. But it would simplify things a bit.
If I go for option two, I forgo polymorphism, but things get a bit complicated. For example, finding the users projects means I have to query for the user's groups, then projects associated with those groups, and then make sure the projects are unique.
Has anyone faced a similar situation, any advice or additional pros and cons for either approach?
I really would rather ditch groups altogether, but it's a requirement for permissions, to separate content based on group.
I think best option would be creating a default group, because:
Then you can go with a clear structure:
projects - has many groups
groups -> has many users etc,
you will have the flexibility of managing groups easily
your core structure is simple, hence years down the line, easy to expand
you are easing the work flow of user by automating a one step. I personally believe if you could let a user to up and running quickly, they will find your system user friendly

Creating groups and signing up users assigned to the group - Ruby on Rails

I'm building out a SaaS application that allows an individual to signup and create an exclusive Group. The admin will then be able to add people to the group by e-mailing them (this will be used primarily internally by companies).
Unfortunately, I'm quite new to Rails and thereby not too sure where to begin.
All groups should be mutually exclusive and users should only be able to belong to one group.
Any suggestions of where to begin in terms of the Group / user relationship?
Thanks a lot.
In terms of the relationship between Users and Groups, it will be a one (Group) to many (Users) relationship. Bringing rails into context, you can take a look at ActiveRecord associations to give yourself the right knowledge about the types of functionality that's exposed. Everyone user :belongs_to only one Group, and Groups :has_many Users. If you need a primer on database relationships, you can check out any primer like this or any link you can find with some diligent googling.
You can try out some things and come back once you have something going, then others will be able to help you out more. If you are REALLY new to Rails, you can check out and try the running example here. Good luck.

Rails Roles / Permissions in a HABTM Relationship -- managing the relationship

I have created the following tables in my application - roles, permissions and permissions_roles. Roles HABTM permissions, and permissions HABTM roles. I have seen many tutorials on setting up all of the tables/models etc for the 3 tables and defining the relationship, but I haven't been able to find anything on actually maintaining the relationship -- What is the best practice -- set up a third controller/set of views?
I want to be able to create Roles/Permissions independently of the relationship, ie make the assignment later - If I create a new role, I may need to go back and assign existing permissions to it (or vice-versa).
I know there are plenty of plugins that do this sort of thing, but I really want to see if I can learn more by starting from the ground up...
Thanks
Its a little bit dated, but should still work, I shudder at the verbosity of the code but it was one of the first things I did in Rails...
http://blog.wolfman.com/articles/2006/5/20/role-based-authentication-admin-page

RoR table inheritance?

Scenario: I have a users table in my application. I also have two subclasses of users, lets say contributors and viewers. Each user group must have an entirely different set of attributes but they both share certain user properties (login, password, name).
What is the best way to implement this using Ruby on Rails?
I think single table inheritance would leave me with too many null fields.
I think linking three tables (users, viewers, contributors) would work fine, but then when wanting to edit any information i have to do: #user.viewer, while i would love to be able to just do #viewer.
Any ideas of the best solution?
I would probably go with the three tables approach. Data integrity is king over code cleanliness.
If you want to make it look neater, put virtual attributes on the Viewer and Contributor models that make it look like the User attributes are local. You can make it a module and include it in both Viewer and Contributor models.
You can also set up an :include => :user on the default finders so that you don't get an extra query when using those fields.
I'm extremely caffeinated right now, so comment back if that doesn't make sense :)
don't compromise the database schema, make it fit best. I like the three table method. If you do the database bad, the application will have very hard to fix issues later, run slow, etc.

Resources