alternative to using many to many relations with simple data in a relational database - ruby-on-rails

I'm working on a ruby on rails project that requires recording some simple user data which fits in a many-to-many relationship (think of it as an set of user interests). I'm experienced with doing many to many relations using has_many :through and HABTM, but when the thing is simple enough that it could be represented as a single word it seems like overkill to create a new model and to have to do the required joins to access it. I don't see much need in recording other properties than the name of the interest itself, so that argument for using a model isn't persuasive. I know noSQL can be good for this, but I'm wondering what the right way to do this with a relational db would be (I'm using postgres), both from a performance and good design perspective. The approach I'm thinking of using would be to record it as a delimited string in the user model using the text datatype and then parse this into an array. or this could be a string representing an array of hash keys which then queries a hash table or key/value store db for the data. I'm sure there many different approaches to this, but I'd appreciate knowing what the best practice would be, since I expect I'll be having to implement this in the future a lot. Also if you could recommend any any tools/gems/frameworks that assist in this that would be very helpful.
Thank you.

Basically serialize the data in some way and store it in a column knowing in advance that you will not query against it. One fairly compact solution I've seen people use is to store it as json which relieves you of having to do anything complicated. You simply need a varchar type that is large enough to store the json strings.

Related

ActiveRecord schema for multiple types of objects with common columns?

I'm working on a Rails 5 app for Guild Wars 2, and I'm trying to figure out a way to serialize and store all of the items in the game without duplicating code or table columns. The game has a public API to get the items from, documented
here: https://wiki.guildwars2.com/wiki/API:2/items
As you can see, all of the items share several pieces of data like ID, value, rarity, etc. but then also branch off into specific details based on their type.
I've been searching around for a solution, and I've found a few answers, but none that work for this specific situation.
Single Table Inheritance: There's way too much variance between items. STI would likely end up with a table over 100 columns wide, with most of them null.
Polymorphic Associations: Really doesn't seem to be the proper way to use these. I'm not trying to create a type of model that gets included multiple other places, I just want to extend the data of my "Item" model.
Multiple Table Inheritance: This looks to me like the perfect solution. It would do exactly what I'm wanting. Unfortunately, ActiveRecord does not support this, and all of the "workarounds" I've found seem hacky and weird.
Basically, what I'm wanting is a single "Item" model with the common columns, then a "details" attribute that will fetch the type-specific data from the relevant table.
What's the best way to create this schema?
One possible solution:
Use #serialize on the details (text) column
class Item
serialize :details, Hash
end
One huge downside is that this is very inefficient if you need to query on the details data. This essentially bypasses the native abstractions of the database.
I was in a similar situation recently. I solved by using Sequel instead of ActiveRecords.
You can find it here:
https://github.com/TalentBox/sequel-rails
And an implmentation example:
http://www.matchingnotes.com/class-table-inheritance-in-rails.html
Good luck

Store as JSON or separate attributes?

I'm using Rails 3.2 and MariaDB. I have this group of data:
description, services, facilities
Not indexed and purely for output in the show page. Should I store these as one JSON object in one more_info attribute or store as separate attributes?
I personally would make columns for them, it would generally make the fields easier to work with, especially if there will be need a to update the values. I usually reserve JSON serialized fields when I do not know how many attributes there will be.
If you are showing the data to your users I would recommend saving them in different columns. I find that as soon as users see something they want to filter by it or work with it in ways you have not foreseen.
If you are not then the choice is less clear cut but the very fact you have 3 distinct groups suggest that they are different things which could be treated differently as your application matures.
I would always go with the Normalised form unless you have documented reasons not to.

Categorization of models in Rails 4

The goal is to have a list of non-unique categories for the models to be sorted under. However, a model could be placed in multiple categories.
Aside from using an array attribute and searching through each array of each model (thus eliminating scalability), how would one categorize models? I am unable to find a proper association form as well, for that would clutter the database with many instances of the "same" category.
If you're using a newish version of postgresql and rails 4, you can build light-weight tagging very easily using postgres' array column types. Array columns can be indexed and there's a set of decent operations on tables containing arrays. Arrays are performant and it's pretty fun to build this functionality from scratch, especially if your requirements are pretty simply.
There's a couple "ifs" in there which might mean this isn't the approach for you. If you're curious, this blog describes the process pretty clearly: http://rny.io/rails/postgresql/2013/07/28/tagging-in-rails-4-using-postgresql-arrays.html.
Good luck!
Would something like acts_as_taggable_on work? Or do you need something more elaborate? Could you give an example of what you'd like the code to look like?

Rails - EAV model with multiple value types?

I currently have a model Feature that is used by various other models; in this example, it will be used by customer.
To keep things flexible, Feature is used to store things such as First Name, Last Name, Name, Date of Birth, Company Registration Number, etc.
You will have noticed a problem with this - while most of these are strings, features such as Date of Birth would ideally be stored in a column of type Date (and would be a datepicker rather than a text input in the view).
How would this best be handled? At the present time I simply have a string column "value"; I have considered using multiple value columns (e.g. string_value, date_value) but this doesn't seem particularly efficient as there will always be a null column in every record.
Would appreciate any advice on how to handle this - thanks!
There are a couple of ways I could see you going with this, depending on your needs. I'm not completely satisfied with any of these, but perhaps they can point you in the right direction:
Serialize Everything
Rails can store any object as a byte stream, and in Ruby everything is an object. So in theory you could store string representations of any object, including Strings, DateTimes, or even your own models in a database column. The Marshal module handles this for you most of the time, and allows you to write your own serialization methods if your objects have special needs.
Pros: Really store anything in a single database column.
Cons: Ability to work with data in the database is minimal - It's basically impossible to use this column as anything other than storage - you (probably) wouldn't be able to sort or filter your data based on it, since the format won't be anything the database will recognize.
Columns for every datatype
This is basically the solution you suggested in the question - figure out exactly which datatypes you might need to store - you mention strings and datestamps. If there aren't too many of those, it's feasible to simply have a column of each type and only store data in one of them. You can override the attribute accessor functions to use the proper column, and from the outside, Feature will act as though .value is whatever you need it to be.
Pros: Only need one table.
Cons: At least one null value in every record.
Multiple Models/Tables
You could make a model for each of the sorts of Feature you might need - TextFeature, DateFeature, etc. This guide on Multiple Table Inheritance conveys the idea and methodology.
Pros: No null values - every record contains only the columns it needs.
Cons: Complexity. In addition to needing multiple models, you may find yourself doing complex joins and unions if you need to work directly with features of different kinds in the database.

Rails 3.0 - best practices: multiple subtypes of a model object

So this is probably a fairly easy question to answer but here goes anyway.
I want to have this view, say media_objects/ that shows a list of media objects. Easy enough, right? However, I want the list of media objects to be a collection of things that are subtypes of MediaObject, CDMediaObject, DVDMediaObject, for example. Each of these subtypes needs to be represented with a db table for specific set of metadata that is not entirely common across the subtypes.
My first pass at this was to create a model for each of the subtypes, alter the MediaObject to be smart enough to join into those tables on it's conceptual 'all' behavior. This seems straightforward enough but I end up doing a lot of little things that feel not so rails-O-rific so I wanted to ask for advice here.
I don't have any concrete code for this example yet, obviously, but if you have questions I'll gladly edit this question to provide that information...
thanks!
Creating a model for each sub-type is the way to go, but what you're talking about is multiple-table inheritance. Rails assumes single-table inheritance and provides really easy support for setting it up. Add a type column to your media_objects table, and add all the columns for each of the specific types of MediaObject to the table. Then make each of your models a sub-class of MediaObject:
class MediaObject < ActiveRecord::Base
end
class CDMediaObject < MediaObject
end
Rails will handle pulling the records out and instantiating the correct subclass, so that when you MediaObject.find(:all) the results will contain a mixture of instances of the various subclasses of MediaObject.
Note this doesn't meet your requirement:
Each of these subtypes needs to be represented with a db table for specific set of metadata that is not entirely common across the subtypes.
Rails is all about convention-over-configuration, and it will make your life very easy if you write your application to it's strengths rather than expecting Rails to adapt to your requirements. Yes, STI will waste space leaving some columns unpopulated for every record. Should you care? Probably not; database storage is cheap, and extra columns won't affect lookup performance if your important columns have indexes on them.
That said, you can setup something very close to multiple-table inheritance, but you probably shouldn't.
I know this question is pretty old but just putting down my thoughts, if somebody lands up here.
In case the DB is postgres, I would suggest use STI along hstore column for storing attributes not common across different objects. This will avoid wasting space in DB yet the attributes can be accessed for different operations.
I would say, it depends on your data: For example, if the differences between the specific media objects do not have to be searchable, you could use a single db table with a TEXT column, say "additional_attributes". With rails, you could then serialize arbitrary data into that column.
If you can't go with that, you could have a general table "media_objects" which "has one :dataset". Within the dataset, you could then store the specifics between CDMediaObject, DVDMediaObject, etc.
A completely different approach would be to go with MongoDB (instead of MySQL) which is a document store. Each document can have a completely different form. The entire document tree is also searchable.

Resources