efficiently storing "answers" - ruby-on-rails

I'm building out an Answer ActiveRecord class that can have different types of answers. That is, the answer could be an integer, float, date, string... whatever...
The way I see it there are two ways to store the answers
1)
Have an attribute named "value" that is serialized.
This is nice since you can always access the answer from the same place. It probably sucks for searching answers since the data has to be de-serialized in order to be used (is this a correct assumption?)
2)
have several attributes integerValue, floatValue, etc...
This is easiest to search (if you know what type you're searching (which you probably do))
This sucks since the value isn't in the same place and need some hokey method like:
def value
stringValue||floatValue||integerValue
end
and some validations to ensure that only the correct one is set
What would you do??

I'd do one of two things:
Use single-table inheritance. Your table does contain those integerValue, floatValue, etc. fields; but it also contains a "type" field, and you'll subclass the Answer model to make IntegerAnswer, FloatAnswer, StringAnswer, etc. And then you can simply map the value accessor to one of those fields in each subclass. Look in the Agile book or Google on single-table inheritance in Rails for more on how to implement this.
Use a non-relational database. Something like MongoDB or CouchDB would render this problem moot; you could make value anything you wanted, or have multiple values per answer, or skip it entirely. I personally like Mongo with the MongoMapper gem, and if I had to address your use case that's the direction I'd go. It is getting away from ActiveRecord and "mainstream" Rails though, so you'd have to be comfortable with living at least a little on the edge.

What converting the value to a string in the database.
And using single table inheritance to define the type and retrieve the appropriate value.
You'd have one model Answer with two fields : one "value", which is a string.
And one "type", which is a string too and gets the type of the value.
Then for the float, you' have the following :
class FloatAnswer < Answer
def value
attributes['value'].to_f
end
end
When you do a Answer.find(:all), if the element has FloatAnswer as value, you will have a FloatAnswer object. Not an Answer one.
So you keep only one database field and always have the datas in the appropriate format.

Related

Data type and approach for Rails attributes with occasional second value

I have a use case where a user clicks on a word and sees information about its base word. Very occasionally there are words with two different but equally accepted spellings with identical meanings, and I'd like to display the alternate spelling when this happens (examples for Spanish: 'video' and 'vídeo', or 'quizá' and 'quizás').
Similarly, there are times where a base_word will need two inflection_forms.
The BaseWord model has attributes for base_word:string, inflection_form:string (i.e., 'ND3XX'), and the language_id. A base_word has_many :inflections to handle related words, but it seems silly to create a new inflection for a differently spelled word with an identical grammatical role.
I tried serializing both of the fields into an Array, and then later as a Set, but in both cases I had trouble querying the database for base_words where base_word was equal to one of the set/array members.
What is the most logical way to handle this case?
Since you are using Postgres you can use it's built in Array type which can be queried using SQL queries. cf http://edgeguides.rubyonrails.org/active_record_postgresql.html#array
Update 1 : Query example
Yes, its not as simple but, assuming you add an inflections column of type array to your migration, you should be able to hide the complexity with something like:
class BaseWord < ActiveRecord::Base
...
scope :has_inflection, -> (word) { where('? = ANY(inflections)', word) }
And then use it like any other scope. For ex.
BaseWord.has_inflection('vídeo').order('base_word').limit(5)

Is it possible to set a flexible data type using Rails and Postgres?

I'm setting up a question and answer model, and some questions will require Boolean answers, some will require Text, some Integers, some enum (I guess that's the same as integer, but I need to define the meaning in the model) and some Datetime). Is it possible for me to set a flexible model column in the Answer model (e.g. one answer column that accepts any data, and only sets it according to the answer_type of a question object)? Or would it be better to set up a YesNoAnswer model, a TextAnswer model, an IntegerAnswer model etc etc, and then a method on the Question model that chooses which type of answer model it needs based on the answer_type column?
For what it's worth I'm planning to load pre-set questions into the DB using a YAML file that "know" what next_question to send the controller to depending on the answer to the previous question. See my earlier question here.
I had heard about variant data types, but I'm not sure whether that's possible with Rails.
Refer to here to list out the data types which were using in rails, btw, this lists out all postgres's data types, likely, we don't have what you expected.
My experience in a previous project to work with multiple data types is:
Define a value column (type is text, so it is enough to contain anything)
Define a value_type column (this is an enum: {:integer, :boolean,..} for eg)
Define validation callbacks to validate the value & value_type
Hope this helps for you

Rails Migration Column Type Polymorphic

I've got a little situation that I'd like to take care of, but I don't even know if it's possible.
In my app, I have one model that can take a parameter value, this parameter can be either a string or an integer or a boolean.
Instead of doing two string column (in my migration) with one labeled as "type" (the type - really !) and the other labeled as "value" (for the... value ! Yes !) i was wondering if it was possible that there is only the column value remaining, with polymorphics types in there.
The Model represent a property on a taks. Theses properties can be : is this task's open (type "boolean" and value "true" for exemple) ? Does this task has a percentage (type "integer", value "20") ? Note that the table also have a column name.
Polymorphism in Rails is more about associations where the class of the related item is unknown - not database columns with a dynamic type.
While is possible to implement a dynamic column in a relational database using two string columns value and value_type and use a custom getter to typecast value its going to get really messy. Another possibility is to use a something like a HSTORE or JSON column type but again do you really need it? Is there a better way to structure your business logic than trying to jam everything into a single column?
I'm guessing that what you may be looking for is something like an enum to denote the state of your model.
class Ticket < ActiveRecord::Base
enum status: [ :open, :closed, :pending, :active ]
end
This would use an integer column named status.
If you wanted to store additional information it would be prudent to use an additional database column. Like if you want to monitor the progress you would create an integer database column named tickets.progress.
For your answer, yes it is possible, but don't do it that way.
It is possible to use string for all different cases:
"integer:100", "integer:23", etc.
"boolean:true", "boolean:false", etc.
you will need to identify each data type(use concat)and convert to a right type and only then you can use the value.
But it is completely wrong and its implementation is going to be very complicated. I strongly recommend not to use this example or something similar.
I think that this is a wrong database structure.
In general, if you have a case in which you have a column that you think can contain more than one data type - something is wrong in your database and you should make a 'redesign' of your database.
Usually the best practice is to separate to different columns. In your case, your column can get different types, each type represents different information. I think your table should have these columns:
status_id - will reference to another table, Status that will contain all possible statuses(if there are more than 2 options).
progress/percentage - integer.
My answer isn't relevant for relational databases.

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: What is the correct Rails way of doing custom types?

I'm doing a fairly complicated model on Ruby on Rails right now, and I was wondering what the correct "Rails" way of doing "custom types" for attributes was. For example, I have a table businesses which has a string attribute region. But region can only be one of a predefined list of possibilities (that could later be expanded). My question is: where do I define this Region type?
I know I could make a specific regions table (i.e. a Region model) which could house all the options, and then I could make an association between the models that have regions to that table. The problem is that I have many of these types on my model, so I would end up with more than half the tables in my database being "custom type tables" that only store the possible values for these types. Is that practical?
I also read that you could do this through validations (i.e. validate when saving a record, that the variables were within the possible values). This seems very impractical, since I want to make this model expandable, and form views would need to load the possible values of types into select boxes, etc. If I used this method, every time I needed to add a new possible value for a type, I'd have to change the validation and the views.
Is there a standard way of doing something like this? Something like defining types (maybe models without DB backing?) where I could list all the possible values easily?
Thank you for any help or suggestions on this. It's been bothering me for a long time while doing RoR apps, and I'm tired of hacking around it.
I guess there are many different ways to do it. Personally I would keep things very simple and DRY.
In an initializer, set arrays in the global scope:
REGIONS = ["region A", "region B", "region C"]
In the models, use validations as you wrote. Check that the value is in the REGIONS array.
In the views, use Rails helpers to populate selects, radios etc. from the REGIONS array. If you always have the same select, write your own helper region_select for instance.

Resources