I am working on a model in rails, which has a column type that can have more than one values. In other words, as the users enter data in its database, new values might also be entered for that column. So it is like a one-to-many association. However, since the number of values will be very few (maybe less than 10), I did not want to create a separate model for it. By mistake, I had defined it as a string, but now I want to make it an array of strings, which can grow. How can I do that?
Thanks in advance!
What you're looking for is the serialize method.
Simply call serialize :attribute_name, Array in your model.
Related
I have rails model that can have three values a, b, and c.
It should be possible to assign none of them, one, of them, two of them or all of them.
My idea is that I can use this attribute as a string, and serialize it to use it as an array (for example [a, c], or [] or [a,b,c].
Using some strong validations it seems to me the logic way to go and I know rails can handle it.
Anyway I read everywhere that an array attribute is a wrong choice and that I should use an has_many relation.
Is there a good reason to have an has_many relation or it's an overkill for just a, b and c?
Another option would be to add three boolean attributes to my table (a:boolean, b:boolean, c:boolean) and work on that logic.
What is the best way to take for my scenario?
Rails 4 comes with native support for postgresql's array data type. So if you are using postgresql then you should use the array datatype instead of creating another model with has_many relationship.Although array datatype is not as fast as integer or string but considering the joins you have to perform it will give you some performance improvement.
How do I save multiple values in a single cell record in Ruby on Rails applications?
If I have a table named Exp with columns named: Education, Experience, and Skill, what is the best practice if I want users to store multiple values such as: education institutions or skills in a single row?
I'd like to have users use multiple text fields, but should go into same cell record.
For instance if user has multiple skills, those skills should be in one cell? Would this be best or would it be better if I created a new table for just skills?
Please advise,
Thanks
I would not recommend storing multiple values in the same database column. It would make querying very difficult. For example, if you wanted to look for all the users with a particular skill set, the query would clumsy both on readability and performance.
However, there are still certain cases where it makes sense.
When you want to allow for variable list of data points
You are not going to query the data based on one of the values in the list
ActiveRecord has built-in support for this. You can store Hash or Array in a database column.
Just mark the columns as Text
rails g model Exp experience:text education:text skill:text
Next, serialize the columns in your Model code
class Exp < ActiveRecord::Base
serialize :experience, :education, :skill
# other model code
end
Now, you can just save the Hash or Array in the database field!
Exp.new(:skill => ['Cooking', 'Singing', 'Dancing'])
You can do it using a serialized list in a single column (comma-separated), but a really bad idea, read these answers for reasoning:
Is storing a delimited list in a database column really that bad?
How to store a list in a column of a database table
I suggest changing your schema to have a one to many relationship between users and skills.
Rails 4 and PostgreSQL comes with hstore support out of the box, more info here In rails 3 you can use gem to enable it.
It depends on what kind of functionality you want. If you want to bind the Exp model attributes with a form (for new and update operations) and put some validations on them, it is always better to keep it in a separate table. On the other hand, if these are just attributes, which you just need in database keep them in a single column. There is way by which you can keep the serialized object like arrays and hashes in database columns. Make them a array/hash as per your need and save it like this.
http://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html#method-i-serialize
Serialized attributes, automatically deserializes when they are pulled out of tables and serialized automatically when saved.
There might be a group of records in a table where only two fields vary record by record, and rest fields remains same. This calls for a normalization by splitting by a table through a foreign key association. But, in Ruby-on-Rails, it would mean the creation of a model. So, is it still possible to lessen use of disk space?
May be, it is, because it would be reasonable that storing multiple values of one column in a record would require the column to be an array of any type. But declaring the field to be :array type results in an error. So, is there a way to work around it?
After generating a model, open the model's file. Insert one line for each field.
serialize :field_name
But ensure that the fields for which you are serializing, should be of type
:text
or
:string
If they aren't of such primitive data types, i.e. of another type like
:datetime
then it would return an error.
This step is not complete as a whole. You need to do one complementing step: de-serialize, because in the model-level storage, it is stored as a string starting with "---\n-", which is not suitable for array-type operations.
While reading data from the model, you need to perform the following step:
YAML.load(field_name)
where field_name refers to the field that was serialized.
The above step would return an array, on which you can perform normal array operations.
This might be a little odd, but how can I get the column name from object in my model?
For example, I have a table which happens to have all 50 states in it as separate columns (I know, I know that could be way more efficient), so they look like:
al_allowed, ak_allowed, etc...
These columns are booleans, but I wanted to know in my model how to get the column names?, for example if for a particular record (in this case Campaigns), I want to see which states are checked off, and if they are True, I want to push the states abbreviation(the column name) into an array.
You can get an array of column names from an ActiveRecord model by calling the column_names method. It's a class method, not an instance method, so you would use Campaign.column_names.
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.