Single Table Inheritance: Optional Plugin module and migrations - ruby-on-rails

I want to know how you can solve this with ruby on rails:
there is a core module which provides a class BasePlugin.
Optional plugins inherits (single table inheritance) from this base class.
Example: The FooPlugin from fooplugin module is a external, optional module (provided by a third party).
Since STI is used the migrations for FooPlugin need to live in the fooplugin module.
Result: BasePlugin does not know its whole table, since optional external modules add extra columns.
I am new to ruby on rails, but have developed database based applications in different languages for years.
Question:
Is the above usage of STI possible with ruby on rails?

The STI table contains the intersection of all attributes for both the parent model and all children models. Note that in STI, BasePlugin is a model, not a module. External plugins are generally provided as gems.
But the key thing is that BasePlugin doesn't need to have all of it's attributes defined when it is first created. If you later add a FooPlugin child and use a migration to add columns to the base_plugins table to add attributes to FooPlugin, BasePlugin will be able to see those columns. ActiveRecord uses introspection to populate the database columns into the ActiveRecord object at startup, so BasePlugin.attribute_names will show you all columns, even if they are only used by the child type.

Yes you can implement what you describe, as ActiveRecord loads the schema after it connects to the database.
I have written about "best practices" using STI with Rails + ActiveRecord on another stackoverflow question here which might be helpful.
For your use case you will want to make sure plugins don't clash their columns, so you will probably need some kind of column naming scheme/prefix for each plugin.
I no longer use ActiveRecord with Rails, and prefer the more powerful and more performant data access layer Sequel. If you're not locked into ActiveRecord you may want to consider Sequel as an alternative as it supports both STI and also CTI (Class Table Inheritence) as well as the latest Postgres features like JSONB which may be better suited to your use case to keep plugins from clashing with each others columns, or simply just storing your plugin related data in a fully indexed JSON column.

Related

Rails Multi Table Inheritance, Polymorphic association or Single Table Inheritance?

I'm trying to implement the OpenEHR reference model in Rails (ActiveRecord), but I'm finding some problems, since it works with a lot of different of different classess,
Here is the diagram of a Composition:
As you can see, a lot of classes "inherit" a couple of attributes from Locatable or Pathable* (the whole reference is huge, and almost every class inherit from it).
Also, it establish data_types as other classes, for example in the same composition class, language is class CODE_PHRASE, that have two attributes (link).
Therefore I encounter two problems 1) how can I inherit attributes from abstract classes, and 2) how is that I can "include" the needed "classes".
For the first problem I thought in using Polymorphic Associations.
For the second one, I thought using STI, but I'm quickly finding a lot of almost similar models (they are exactly the same actually): CompositionLanguage, CompositionTerritory, EntrySetting, EntryEncoding that I only use in the type attribute to "link back", for example: The composition class, can have up to three attributes with CODE_PHRASE, since all three references a different attribute (language, territory and category), I thought that I needed to know for the associations (there's no point in knowing that Composition has 3 code_phrases, but I didn't know which one is the corresponding attribute). On the other hand, the Entry class, have the setting and encoding attribute (link).
I realize that there could be different approaches, but I would really like to know if that maybe Rails (or ActiveRecord), wasn't made for this. Or, maybe I'm missing conceptual info.
The openEHR RM specification has deeply nested inheritance and composite patterns with tree hierarchy.
I could not implement this nested inheritance by ActiveRecord. The following implementation is an example to simulate openEHR RM.
I would be very happy if this example could help you.
https://github.com/skoba/openehr_rm_rails
Have you looked at this project ..
https://github.com/skoba/openehr-rails
I think Shinji uses Active Record.
Personally, given the complex structure of the openEHR RM, if I was starting out I might look to use something like MongoDB with an ORM.
I have pointed the openehr technical community to your question via the openehr technical list to see if others can help.
Ian

Does a hasMany relationship in GORM require an indexColumn?

I'm dealing with legacy tables right now. Our Grails app will simply display data. All data entry and updates take place using a different tool. It would be very difficult to add columns to the legacy database. Are indexColumns absolutely, positively required? Or is there some way I can simply not use indexColumns at all in this case?
http://grails.org/doc/latest/ref/Database%20Mapping/indexColumn.html
Not if it is a Set, which is the default type for hasMany relationships.
By default when mapping an indexed collection such as a Map or List the index is stored in a column called association_name_idx
Grails documentation

What is the Ruby on Rails naming convention for models/controllers that are parts of another object?

I'm not sure about the naming convention for objects that are related/parts of an object in Ruby on Rails. Heres an example of this:
I have a User object
I have a separate Image model that only stores images of the User object
I also have a separate History model that only stores the actions of the User
Would it follow Rails convention to name them to UserImage and UserHistory models? Or is this not following convention? If so, why not?
Thank you!
It generally depends on what other names are used in your application, and to some degree on personal preference.
My preference is not to add namespace prefixes unless it's really necessary because of namespace collisions, or is confusing because of similarly named structures with my application. Also it is more of a rails convention to use suffixes to prevent naming collisions with classes in different areas. For example controllers are all suffixed with Controller, mailers suffixed with Mailer, decorators with Decorator and so on.
In your case I would stick with User, Image and History. Prefixing Image and History doesn't really gain you anything, unless you have other types of Image/History models, in which case it might be better to look into polymorphic relationships instead of namespace prefixes.
It's mostly a matter of style and maintainability.
If you name your models this way then you will not be able to develop associations between models. Ex. UserImage model will be considered as a single entity not association of user and image model. If you want to develop this type of associations use HABTM relationship. Thats why rails follow "Convention over configuration".

Creating the same model from multiple data sources

This is mostly of a design pattern question. I have one type of model that I'm going to get the data to create them from multiple sources. So for example one record my be created from an API where another is created via screen scraping with Nokogiri.
My issue lies in how best to abstract out these different data sources. Right now I'm building lib classes that return the same hash which I then use to set the attributes of the model. But I'm wondering if this isn't more of a case to use STI. Or if there is some other way of doing this I'm just not thinking about.
I think your design decision would depend largely on what attributes need to be stored. From your description, it sounds like you have a model with multiple data sources, but which would be storing the same attributes regardless of the source. In that case STI seems like overkill. When you retrieve a row from the table, does it matter whether the source is the API or the screen scraper? If not, then you could just define separate methods for each data source and use the appropriate method in the controller.
#instance = MyModel.new(:datasource=>"API")`
I'd say don't worry about inheritance (or mixing in code from modules) unless you really need to. There are some gotchas -- STI is not fully supported by some gems/plugins, for example.

What is Ruby on Rails ORM in layman's terms? Please explain

I am having trouble understanding ORM in Ruby on Rails. From what I understand there is a 1:1 relationship between tables/columns and objects/attributes. So every record is an object.
Also what exactly is a Model? I know it maps to a table.
What I'm really after is a deeper understanding of the above. Thank you in advance for your help
I'm a Web developer going from PHP to Ruby on Rails.
"From what I understand there is a 1:1 relationship between tables/columns and objects/attributes. So every record is an object."
That is not exactly correct, unless you use the term "object" very loosely. Tables are modelled by classes, while table records are modeled by instances of those classes.
Let's say you have a clients table, with columns id (autonum) and name (varchar). Let's say that it has only one record, id=1 and a name="Ford". Then:
The DB table clients will map to the model class Client.
The record will map to a model instance, meaning that you have to create the object and assign it to a variable in order to work with the record. The most common way would be to do ford = Client.find(1)
The two columns of the table will map to methods on the ford variable. You can do ford.id and you will get 1. You can do ford.name and you will get the string "Ford". You can also change the name of the client by doing ford.name = "Chevrolet", and then commit the changes on the database by doing ford.save.
"Also what exactly is a Model? I know it maps to a table"
Models are just classes with lots of very useful methods for manipulating your database. Here are some examples:
Validations: Besides the typical db-driven validations ("this field can't be null") you can implement much complex validations in ruby ("this field must be a valid email" is the most typical one). Validations are run just before you invoke "save" on a model instance.
Relationships: The foreign keys can also be mapped onto models. For example, if you had a brands table (with its corresponding Brand model) associated via a foreign key to your ford client, you could do ford.brands and you would get an array of objects representing all the records on the brands table that have a client_id = 1.
Queries: Models allow you to create queries in ruby, and translate them to SQL themselves. Most people like this feature.
These are just some examples. Active record provides much more functionalities such as translations, scoping in queries, or support for single table inheritance.
Last but not least, you can add your own methods to these classes.
Models are a great way of not writing "spaguetti code", since you are kind of forced to separate your code by functionality.
Models handle database interaction, and business logic
Views handle html rendering and user interaction
Controllers connect Models with Views
ORM in Rails is an implementation of the Active Record pattern from Martin Fowler's Patterns of Enterprise Application Architecture book. Accordingly, the Rails ORM framework is named ActiveRecord.
The basic idea is that a database table is wrapped into a class and an instance of an object corresponds to a single row in that table. So creating a new instance adds a row to the table, updating the object updates the row etc. The wrapper class implements properties for each column in the table. In Rails' ActiveRecord, these properties are made available automatically using Ruby metaprogramming based on the database schema. You can override these properties if required if you need to introduce additional logic. You can also add so-called virtual attributes, which have no corresponding column in the underlying database table.
Rails is a Model-View-Controller (MVC) framework, so a Rails model is the M in MVC. As well as being the ActiveRecord wrapper class described above it contains business logic, including validation logic implemented by ActiveRecord's Validation module.
Further Reading
Rails Database Migrations guide
Rails Active Record Validations and Callbacks guide
Active Record Associations guide
Active Record Query Interface guide
Active Record API documentation
Models: Domain objects such like User, Account or Status. Models are not necessarily supported by a database backend, as for example Status can be just a simple statically-typed enumeration.
ActiveRecord:
Provides dynamic methods for quering database tables. A database table is defined as a class which inherits ActiveRecord class (pseudo-PHP example):
class User extends ActiveRecord {}
//find a record by name, and returns an instance of `User`
$record = User::find_by_name("Imran");
echo $record->name; //prints "Imran"
//there are a lot more dynamic methods for quering
New records are created by creating new instances of ActiveRecord-inherited classes:
class Account extends ActiveRecord {}
$account = new Account();
$account->name = "Bank Account";
$account->save();
There are two pieces here: the ORM and Rails's MVC pattern. ORM is short for "object-relational mapping", and it does pretty much what it says: it maps tables in your database to objects you can work with.
MVC is short for "model-view-controller", the pattern that describes how Rails turns your domain behavior and object representations into useful pages. The MVC pattern breaks down into three chunks:
Models contain a definition of what an object in your domain represents, and how it is related to other models. It also describes how fields and relationships represented in the object map to backing stores (such as a database). Note that, per se, there's nothing about a model which prescribes that you have to use a particular ORM (or even an ORM at all).
Controllers specify how models should interact with each other to produce useful results in response to a user request.
Views take the results created by controllers and render them in the desired way. (By the time you get to your view, you should mostly know what's being rendered, and there should be very little behavior happening.)
The definition from Wikipedia:
Object-relational mapping (ORM, O/RM,
and O/R mapping) in computer software
is a programming technique for
converting data between incompatible
type systems in relational databases
and object-oriented programming
languages. This creates, in effect, a
"virtual object database" that can be
used from within the programming
language.
From a PHP view it will be in the following way(via example)
Connect to the database and get some row from posts table.
Turn that row to an object with attributes like those in the table columns.
If the posts has comments in comments table, you can also do post.comments and you get the comments also as an array of objects as well.
You can define relationships between tables like saying: Posts has_many Comments, a Comment belongs to a post and so.
So basically you are not working with database rows, instead you turn those rows and their relationships to objects with composition or inheritance relationships.
In layman's terms.
A Rails Model is proxy to a table in the database. These models happens to be Ruby classes.
The objects of these classes are proxies to rows in the table of which this model is a proxy.
Finally the attributes of these objects are proxies to the column data for that particular row.
Above is actually the Rails ActiveRecord ORM.
1:1 is not quite correct, since there is object-relation impedance mismatch.

Resources