Rails 4 multiple similar models... STI? - ruby-on-rails

I have 3-4 different types of clients for a photo site. Musician, wedding, portrait, and general with the possibility of adding more types. The idea is each type will have a shared set of attributes such as name email etc. but each will have their own too.
Musicians will have band name, members, genre, while wedding will have venue, coordinator details and so on.
I think this is the right way to go about it, correct me if there's an easier way to track multiple shared and unique attributes.
I was reading up on single table inheritance and one place said to use it only if the models have the same attributes but different behavior. How can I structure my models to meet this? From a more generic OOP standpoint this makes a lot of sense to me, but I'm having doubt's from that clause of STI.

Your use case sounds like a good one for STI. The key thing is that the children share some attributes with their siblings, not all attributes. I found this overview helpful:
http://samurails.com/tutorial/single-table-inheritance-with-rails-4-part-1/

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.

ActiveRecord database design

I would like to create a new app rails but being a beginner it's been several days that I try several possible ways without really finding the right one, I just managed to do something but I'm not sure that it's perfect in terms of relationships. the concept would be that people could either create or participate in meals. I would like the ingredients to be reusable, but their attributes such as the origin or cooking method can be modified in each case. do you think this style of rallying is fair?
or
The second option is a classic one. Stick to using many-to-many relation in that cases.
Though it is better to have one-to-many relation between specification and menu - like several specifications for each menu. And specification should also contain ingredient_id.

Rails: model vs. array

When should an array of values become a full fledged model? My problem is an application that is littered with models for such mundane objects as Country, Degree, Profession, etc. which are all simply parts of a user registration form. Should these constant arrays just be hard-coded or is there another better way to store them than using ActiveRecord models?
If it makes sense to have them as database tables, then it makes sense to have them as models. And I would argue that it does make sense to have at least some of these as database tables, because that way you can give your client the ability to edit them on-the-fly. I don't want a programmer to be responsible for maintaining a list of countries or professions.
(In a recent application I worked on that had an international focus, the ability for the client to edit the list of countries was a key requirement; in many settings, what countries are listed and what they are named have controversial political implications, so the client needed domain experts to discuss and decide on country names.)
Hardcoded Array is fine, creating a model for this is part of the antipatterns listed in 'Rails Antipatterns' from Chad Pytel

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.

Is this a legitimate use of Rails' Single Table Inheritance?

I've just been reading Chad Fowler's blog post about 20 Rails Development No-Nos. On Single Table Inheritance he comments:
The storage of a column called “type” which holds a class name is a pretty good indicator that something fishy is going on. It’s fishy but not always bad. I think, though, that any time you use it you should ask yourself more than once if it’s the right solution. Databases don’t do what they do best as well when you have lots of STI and polymorphic associations.
I'm writing a blog application and I'm considering using STI for the comments that can be made on a post and for the contact messages that visitors can post if they want to get in touch with me. My Message model will inherit from my Comment model. They both share common attributes, except that Message will have an extra subject field. Another commonality is that both will be submitted to Akismet for spam checking.
Rather than just ask myself more than once if it's the right solution as Chad suggests, I thought I'd get some opinions from the Stack Overflow experts as well! Does what I'm proposing sound like a good fit for STI?
I've used STI a number of times. Consider a CMS which might have Page, NewsItem, BlogItem etc.
They could each descend from a common class which in turn inherits from ActiveRecord. The table for each would be the same (title, body, tags, published_at) but each model might have different associations, or different statuses, or a different workflow so each has custom code in their own class. Yet they all share a common table and parent class. It also allow me to use the parent class to do a cross class search and have the resulting Array of records automatically type cast.
There are other ways to tackle this and maybe not the best example but there are certainly times when STI is handy for situations where object behavior may differ but persisted state is the same. Of course you have to be sure this is also true in the future.
In your case comments and contact messages are different. It sounds like there is there no benefit by having them in the same table. Maybe put shared code in a parent class or better still in a module in /lib.

Resources