Many values for enum - ruby-on-rails

I have to sort the stores registered in segments. I want to have pre-registered segments for the user to choose, but they are many. It's a good idea to put everyone in an enum? There are over 15.
A Store is a model that have a type, the type is the segment. There is several types. The pre-registered are the several types in enum. I was thinking that the code will be dirty with all types in enum.

It's up to you, really. You'll have people tell you that it's better to manage something like a field that can only have one of several values as an enum, and others would say that the field should be a string and you should validate it on your Segments model.
I'm partial to the latter.

Related

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.

efficiently storing "answers"

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.

Tables representing an enumerated list of codes in Rails?

I've looked through similar questions but I'm still a little perplexed about something that seems to be a simple case in Rails.
Let's say I have a model class called Employee. One attribute of an employee is their security_clearance, which is a string that can be None, Some, or Full. No other values are valid. In other applications I'd probably represent this an Employees table that has a foreign key to the SecurityClearances table, which has exactly three rows. The SecurityClearances table has columns entitled code (e.g. SEC_CLEARANCE_NONE, SEC_CLEARANCE_SOME, ...) and value ("None", "Some", "Full").
How do I want to do this in Rails? Do I want has_one :security_clearance on Employee and belongs_to :employee on SecurityClearance? That doesn't seem to be quite right.
It seems nonoptimal to type out the string literals of None, Some, and Full everywhere, especially since the values to be displayed could change (for example, perhaps the string for the Some code will be change to be low clearance instead).
Update:
Now that I think about this some more, don't I really just want a belongs_to :security_clearance on Employee? That would do the trick, right? Employees need to know what their security clearance levels are, but security clearance levels have no tie to a particular employee.
Take a look at this plugin: http://github.com/mlightner/enumerations_mixin/tree/master
It allows you to define this like has_enumerated :security_clearance, besides also caching the SecurityClearance model, etc.
Without the plugin, though, you're right about the relationships.
Also check out the Enum Fields plugin from the GiraffeSoft folks:
http://giraffesoft.ca/blog/2009/02/17/floss-week-day-2-the-enum-field-rails-plugin.html

Resources