Consider a typical social networking website, which has more or less the following models:
User
Blog, Posts
Forums, Topics, Responses
Wiki, Pages
....
....
I want to introduce a model called Site/Space where each User can have one or many sites/spaces. And I want to provide a way for the Site owner to select many features (or call it apps/tools).
Whats the best way to design this model - so called feature/app/tool?
Note: In many cases each feature may not be the same as corresponding model. Lets consider blog feature, by enabling the Blog feature, I should be able to associate (some how) that the corresponding site has access to both Blog & Post, (another example) by enabling Forums feature, I should be able to associate the site has access to not only Forum, but also Topic & Response models. I need these checks so that I could define a before_filter to check if a particular site has access to the content or not.
I looked at some open source rails applications that have this kind of on demand features, but by looking at the form attributes, it looks like they have has_blog, has_post,... fields tucked in the Sites table, in my situation it may not work as the number of these models may grow. Do you still think that adding these boolean fields in the Sites table is the best approach?
polymorphic associations, has_many :through, and/or has_and_belongs_to_many sound like the building blocks to your solution. I'd look into them.
Define a many-to-many relationship between an Apps and a Sites table in your database.
Apps
AppID
Name
...
Sites
SiteID
UserID
...
SiteApps
SiteID
AppID
SELECT AppID FROM SiteApps WHERE SiteID=...
See also SQL: Many-To-Many table AND query
Related
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.
I have seen regular debates about the way to manage the different class of users.
Usually, it seems that developers prefer a role based approach (e.g. user, admin,...) with gems like Cancancan
But I'm wondering if it's applicable for an appointment booking app (appointment for doctors, teachers,... or even bookings). Indeed in this case, the 2 types of users have access to totally different pages. In its documentation about associations, Ruby on Rails guide takes the example of a medical appointment booking app with 1 table for doctors and 1 table for patients.
For this kind of app, I'm a little bit lost regarding the most efficient solution!
Thanks!
You can use a tool like Cancanan to break out the different roles and abilities, then restrict access to certain parts of the system based on those rules.
Additionally you can display only the relevant navigation or pages when the user's accessing the system so they might not even be aware of what they're not seeing.
Question
I have a User model with authorisation and authentication logic built.
Now I realise I have three different types of users. I want to store different information about each of them.
What is the best way to handle this in Rails?
Thoughts based on current reading
I've looked at STI but from what I've read feel it is inappropriate because I'll end up with a lot of NULL fields in my database.
Ideally I'd like to not duplicate the authentication / authorisation logic for each of the three user types.
Each user will also have different functionality within the application.
You can try using polymorphic associations and creating table users with data that all types of users have and putting other data in seperate tables. Railscast epizode covering this topic.
There are lots of ways to do this. Here's one approach:
Instead of thinking of different types of users, you could think of roles that a user has.
For example, if a user could be a butcher, baker, or candlestick maker, you could have four tables: users, butchers, bakers, candlestick_makers. The latter three role tables each have a user_id column; they "belong to" the user.
If you need to enforce that a particular user has only one role, you will have to do that in the application (since this database schema would allow multiple roles for a single user).
This method is good if there is a lot of stuff that would belong in those role tables. If not, leaving some NULL columns on the users table probably won't kill you.
Rather than the typical one store app, where I (as a user) go and add products that one seller (the owner of the Spree app) is selling, what I want to do is to create an ecommerce site that has multiple vendors.
So you could see an overview of all vendors, and then you can buy multiple products from multiple vendors.
Does Spree allow me to customize it to that extent?
If so, are there any docs for that?
Thanks.
One approach (the one I used), is to add a 'vendor' Property to each item. Note - this approach assumes that each item is only sold by a single vendor. If you actually have a marketplace with various vendors competing to sell the same item, you'll need to do a similar thing by adding a 'vendor' OptionType, that is defined for each product Variant.
Each vendor (new model) is assigned a code that can be used when setting up your items (as either a property value, or multiple variant option values). When an order is placed, you can use a new OrderFulfillment model to track the various shipments that the various vendors will use to fulfill that order (one OrderFulfillment record per vendor in the order).
That's basically all the model changes you'll need. In the controller area, you'll need to modify the 'shopping cart' event machine sequence to handle the different vendor's shipping methods. And in the case of multiple vendors, you'll also need to present the user with a choice of vendor (think amazon marketplace).
How you handle your payments to various vendors was not part of my project, but shouldn't be too complex to add if needed.
Regarding links: You should be familiar with the basic Spree concepts which are discussed in the guide in general, and more specifically here. You will also need to make some internal modifications (new associations, modified controller behavior) which you can read about here.
I think you have a few options available for that.
Essentially, you want an e commerce app where users can sign up and list their own products, and then have a user profile page where someone can look and see just that user's products, right? Some people call this multi-tenancy, and if you do a google search you will soon find this spree extension: multi-tenant
I am looking to do the same thing as you, and I'm a bit wary of multi tenant because I would have to roll back to Spree 2-2 stable (I'm currently on 2-3).
The previous answer here suggests that you should create a new model called Vendor. I would say why not just update your already existing user model to become a vendor?
What I'm suggesting is simply creating an association between the User model and the Spree::Products model. This way you can scope products to individual users and create profile pages without the complexity of adding new, foreign models and/or different admins for each user. All of the spree methods are already attached to your User class, so I would think a simple belongs_to/has_many association would work. Haven't tested this at all, but that's what my thinking is.
I'm building a Rails app that has Etsy.com style functionality. In other words, it's like a mall. There are many buyers and many sellers.
I'm torn about how to model the sellers. Key facts:
There won't be many sellers. Perhaps less than 20 sellers in total.
There will be many buyers. Hopefully many thousands :)
I already have a standard user model in place with account creation and roles.
I've created a 'role' of 'seller', which the admin will manually apply to the proper users. Since we'll have very few sellers, this is not an issue.
I'm considering two approaches:
(1) Create a 'store' model, which will contain all the relevant store information. Products would :belong_to :store, rather than belonging to the seller. The relationship between the user and store models would be: user :has_one store. My main problem with this is that I've always found has_one associations to be a little funky, and I usually try to avoid them. The app is fairly complex, and I'm worried about running into a cascade of problems connected to the has_one association as I get further along into development.
(2) Simply include the relevant 'store' information as part of the user model. But in this case, the store-related db columns would only apply to a very small percentage of users since very few users will also be sellers. I'm not sure if this is a valid concern or not.
It's very possible that I'm thinking about this incorrectly. I appreciate any thoughts.
Thanks.
I would definitely use a relationship between a store and a user. This provides a lot more flexibility and is a much cleaner data design.
I have never had any issues using any of the basic associations in Rails/Active Record.
What do you mean by "funky"?