Rails: Models that inherit columns from parent, and each have additional columns - ruby-on-rails

I'm creating a logbook app that will work for multiple sports (e.g. scuba-diving and sky-diving) and I'm trying to find a way to have children models inheriting not only parent methods, but parent (database) columns.
An image may explain better:
Logbook database sample
So, any models under the category ScubaDiving, FreeDiving and SkyDiving are models that I will be calling from the views.
The models under Parent or Diving however, will never be called, and are only meant to populate their children with database columns (and methods perhaps).
What is the best way to go about creating the models + associations + inheritance ?
From the research I've done, I've read about:
Single Table Inheritance:
Will only pass parent methods, not database columns
Polymorphic Associations:
I compared my situation to the example I found (comments on photos, articles, posts), but my Divespot and Airport (equivalent: Photo, Article) can't have many Spots (eq: Comments).
Multiple Table Inheritance:
Couldn't make it work, but it seemed the closest to what I was looking for?
Simple models:
I could always create a model for each child (with no parent) and repeat the code. I still wanted to see if there was a way to refacto.
I am using Rails 5 and a PostGresql database.

Single Table Inheritance:
Will only pass parent methods, not database columns
Of course all classes inherit the database columns. Since all classes "live" in the same table, they have the same columns. STI is probably not the best solution in your case for another reason - the columns seem to be different for each model, so you would have a bunch of columns being "NULL" for the models that don't have these columns.
I'd suggest considering to create a model / table for each of your classes and then linking the children objects to an object representing the parent. You can then delegate methods like name, location to the Spot, for example. You will probably then need to work with polymorphic associations. You can be a bit fancy and try "proper" MTI, see this guide

Related

rails STI: specific attributes for subclasses

I'm starting building my first rails app and i already have user model with STI (admin, employee, public and representative all inherits from user model).
but now i want to add specific columns (adress, state, phone) for representative subclass but i cannot apply migration directly for subclass model.
the first solution is to add these columns tu user model but i don't know how th restrict acess to only representant subclass
the second solution is to create a separate contact table and and then use polymorphic association (i want to associate with other model) and add the attributes
my question is what is the best solution for this case? and if there is better solution?
Thanks
Hope you Doing well
I think second option is better then first.
Reason:
1) If this all filed are optional then it will create record with null value but in second case if all filed are optional then record will not be created,there is no need to any entry for that.
2) In future there is requirement of add or use this filed into other model then you can do by easily with polymorphic association .
It sounds like you are abusing the idea of an STI in this case. The general rule, is that you might have different associations for different child models and different behaviour BUT you ALWAYS have all the table columns used by all child models.
The whole Idea for why you would want to use STI is that all models contain the same structure of data, but maybe have different behaviours. In your case, I would suggest using associations (as you suggested yourself) and then add the has_one/has_many in the child model, which would limit the associations scope within the inheritance chain.
It is not possible to restrict columns to only some child models without patching ApplicationRecord. But in any case, even if you manage to make a patch to introduce this kind of behaviour, your database table will still have all the columns for all the tables, thus resulting in bigger database tables due to half empty columns, increased size and reduced performance.
I hope that answers your question.

Model which belongs_to can be several models?

This is the situation that I have now:
Adword has_many pages
page belongs_to Adword
Right now I want to place another Ad provider, and that will also generate pages. So, ideally I want somehow to say something like (this is where I am lost):
AdProvider has_many pages
page belongs_to AdProvider
Where AdProvider could be Adwords, X, Y - What is the correct way to approach this kind of situations in Rails? RIght now I just have a adword_id attribute in Page, but there will be pages which are not associated to Adword but to another Ad provider.
Use Polymorphic association.
From the doc:
With polymorphic associations, a model can belong to more than one
other model, on a single association. For example, you might have a
picture model that belongs to either an employee model or a product
model.
I use Single Table Inheritance (STI) when I want to accomplish this.
"STI should be considered when dealing with model classes that share much of the same functionality and data fields, but you as the developer may want more granular control over extending or adding to each class individually. Rather than duplicate the code over and over for multiple tables (and not being DRY) or forego the flexibility of adding idiosyncratic functionality or methods, STI permits you to use keep your data in a single table while writing specialized functionality."
You can read more about it here.
As suggested by #emaillenin you could use polimorphic associations to deal with this.
You can see more about that here
But you should have in mind that classes sharing this type of association should follow a pattern, or else you could end up with tons of if statements in order to avoid their differences.
However by your description of the relation between AdProvider and Adword, I'm guessing that you are using a STI (Single Table Inheritance) system, so those similarities are already implied.
This article will help you to choose between Polymorphism and STI approach: STI
Below you can find a quote from the article:
"
3. Do the objects have similar data but different behavior?
How many database columns are shared by every model? If there are going to be many model-specific columns, you should consider Polymorphic Associations. On the other hand, if a Car, Truck, and Motorcycle all have the same attributes, eg:
color
engine_size
price
but different method implementations, eg:
drivetrain_weight # sums different components
value_after_depreciation(years) # uses different depreciation rates
drivers_license_certifications # references different certifications
then Single Table Inheritance is probably a good design choice. If there are only minor differences in a few methods, you may want to “cheat” and go with a Single Class."

Ruby on Rails: How to implement this particular model (with inheritance, N-to-M relationship, etc)

I've already defined the data model for my application, which will contain this particular part:
Now, my particular issues are related to modelling "Value" and it's child models "Value_Decimal" and "Value_Text". Basically I wan't to have this hierarchy as it's expected to have several other value types, and each value model with have several other different columns (I'm not considering Single Table Inheritance due to this fact).
How can I implement this with Rails' Active Record, can someone point some directions?
Many thanks in advance!
The item_property_value table should have a value_type column allowing for polymorphic associations. Then you can create different tables named for each of your various 'value' models inheriting from an abstract value model (that has no table). This way you can avoid STI, but still inherit from one base model.
Because the item_property_value model is combining 3 different relationships it will need to be treated as a first-class Rails model which means it will also need an id as a primary key. You can then use a has-many-through mapping to access the actual objects it is joining.
Read up here on polymorphic associations. Abstract classes are simply flagged as such:
class Value < ActiveRecord::Base
self.abstract_class = true
end

Rails: associations in app with one model

I've read so many Rails books/tutorials, but when it comes time to actually make the app, I keep tripping over myself, so I'm trying this little exercise to help me get it better.
I have an app with 3 classes (Link, Url, Visit) that have associations defined between them, such as has_one, belongs_to etc. This allows me to call methods like Link.url
If I were to convert this into an app with a single model, is it possible to create the convenience methods (such as Link.url) even though there are no relationships between models, because there is only one model.
This might not be the 'Rails way' but if you answer this question it'll help me get it more.
I guess another way to ask this is, do the Rails associations only exist because the tab
Thanks
Models exist to represent tables in a database. If you have 3 different conceptual objects, then you need 3 different models. Keeping those objects separate and in different tables/models is essential to good programming in any language. The relations are there to help you understand the correlation of each object to the others.
If you think all of data from each of the models can be represented in one table sensibly, then combine them in to one model with a name that encompasses all of the data. If you choose this option, you'll use columns for that one table which represent each of the pieces of data you need. Those column names come free in the model when you create the migration. A table with a column named "url" on a model named "Hit" could be used like this:
Hit.first.url

Database and relationship design when subclassing a model

I have a model "Task" which will HABTM many "TaskTargets".
When it comes to TaskTargets however, I'm writing the base TaskTarget class which is abstract (as much as can be in Rails). TaskTarget will be subclassed by various different conceptualizations of anything that can be the target of a task. So say, software subsystem, customer site, bathroom, etc...
The design of the classes here is fairly straightforward, but where I'm hitting a snag is in how I will relate it all together and how I will have rails manipulate those relationships.
My first thought is that I will have a TaskTarget table which will contain the basic common fields (name, description...). It will then also have a polymorphic relationship out to a table specific to the type of data the implementing class wraps.
This implies that the data for one instance of a class implementing TaskTarget will be found in two tables.
The second approach is to create a polymorphic HABTM relationship between Task and subclasses of TaskTarget which I thought I could reuse the table name TaskTarget for the join table.
Option #2 I suspect is the most robust, but maybe I'm missing something. Thanks for any help and of course I'm really just asking to make sure I get it done right, once!
I think the two approaches (easily) available to you in Rails are:
1) Single Table Inheritance: You create a single TaskTarget table that has every field that every subclass might want. You then also add a "type" field that stores the class name, and Rails will pretty much do the rest for you. See the ActiveRecord api docs for more info, especially the "Single Table Inheritance" section.
2) Concrete Table Inheritance: There is no table for the base TaskTarget class. Instead, simply create a table for each concrete class in your hierarchy with only the fields needed by that class.
The first option makes it easier to do things like "Show me all the TaskTargets, regardless of subclass," and results in fewer tables. It does make it a little harder to tell exactly what one subclass can do, as opposed to another, and if you have a lot of TaskTargets, I suppose eventually having them all in one table could be a performance concern.
The second option makes for a cleaner schema that is somewhat easier to read, and each class will work pretty much just like any normal ActiveRecord model. However, joining across all TaskTarget tables can be cumbersome, especially as you add more subclasses in the future. Implementing any necessary polymorphic associations may also involve some extra complexity.
Which option is better in your situation will depend on what operations you need to implement, and the characteristics of your data set.

Resources