Saving an hash as a string, reform it later - ruby-on-rails

I want to be able to save a params[:object] hash in a text field of a drafts table, to keep this hash saved and pull it out later. I want to know if it's possible to do so that I get a hash out later, with functionality.
Right now, when I am saving a post in here, so I have the following line:
#draft = user.drafts.build(:content => params[:post])
This saves the params[:post] hash as:
"--- !map:ActiveSupport::HashWithIndifferentAccess \ntitle: asdfasdfasdf\ncontent: \"\"\ndiscussion_id: \"87\"\ndraft: \"false\"\n"
If I find the draft (ie d = Draft.find(1)) and then I try to pull this hash out, I just get the string value here.
Is there some way I can reform this into a hash? Or is there a better way to go about saving the params hash in the first place?
Thanks

Check out the class method serialize in ActiveRecord::Base:
class Draft < ActiveRecord::Base
serialize :content, Hash
end
It should save a fair amount of time over doing this yourself!

Related

Casting form inputs in a Rails form

I seem to have a few cases where I want to accept an array of values via a form:
<input name="model[field][]>
<input name="model[field][]>
<input name="model[field][]>
But then on the server side, my "Model.field" attribute is implemented as a string.
So there will be some kind of transformation taking the array and converting it into a string.
My question is this: Is there a way to generically handle this.
On the server side, is there a way where I can say "Whenever the form tries to assign an array to a string, use function X to do the assignment"
I realise my schema is questionable... and it's questionable to do blanket casting.... but if I HAD to do this, what would be the best method?
thanks!
It's Rails. You can do everything you want. If I understand you correctly: You receive an array from form and you need to save this array in database. Here are steps to do this
1) permit this attribute (you are using Rails4). Do smth like this:
def model_params
params.require(:model).permit(:title, {:field => []})
end
2) Serialize field in database. Just put this in your model:
class Model
serialize :field
end
Rails will handle all for you. Read more about serialize method

How to get serialized column list on RoR

I'm user of Ruby on Rails.
I made active model like this.
class User < ActiveRecord::Base
attr_protected :id
serialize :user_info, Hash
serialize :user_auth, Array
serialize :user_addr
end
I want to get the column names which contains a serialized object and type.
I'm looking forward to the method like this.
ex )
User.serialized_columns #=> {:user_info => Hash, :user_auth => Array, :user_addr => nil}
Would you help me?
Yes, you can get it using the method serialized_attributes which returns a Hash where key is the column name and value is the class of the column
So, you can get the serialized columns as
User.serialized_attributes
But you have modify the value of each key according to your requirement.

serialize & before_save in Rails 4

I have a DocumentType model w/ a extensions attribute. In my form I'm allowing people to insert those extensions into the form.
I want to be able to parse that input before saving, stripping out any invalid options, convert it into an array and have Rails serialize it.
I have the following code but I just end up w/ the input that the user gave in the form instead of an array:
class DocumentType < ActiveRecord::Base
serialize :extensions
before_save :process_extensions
def process_extensions
self.extensions = [*self.extensions.gsub(/[^a-z ]+/i, '').split(' ')].uniq
end
end
The key to understanding what's happening is knowing when serialization occurs. By inspecting serialization.rb in activerecord you'll see that the serialization magic happens by overriding type_cast_attribute_for_write, which is called on write_attribute. That is, on attribute assignment. So when you do:
document_type.extensions = something
something gets serialized and written to the extensions attribute. That is way before the save takes place. In fact, you don't even have to call save on document_type to have the attribute serialized.
The best workaround I know is to override extensions= on DocumentType. Something like:
def extensions=(value)
value = [*value.gsub(/[^a-z ]+/i, '').split(' ')].uniq
write_attribute :extensions, value
end
I believe this append because the value of extensions is serialized while the model is validated by Rails, and your process_extensions method is called later (before the model is saved) and does not act as expected
Try to use before_validate instead
before_validate :process_extensions

Rails data design for multiple date picker

I have an Appointment model, whose available_dates can include multiple dates (say, available in Jan 1, 5, 6 and 7).
My question is very basic: how should I store available dates for each event?
What I can think of is a table Avaiable_Dates with two columns: event_id and date. Each event would have multiple rows, one date per row. It seems to be cumbersome to query entire table to make sure we got all dates of an event. A Hash {event => {date1, date2, date3}} would be faster, but I don't know how to implement it using ActiveRecord.
Thank you.
It might not be a bad idea to just use the separate model for available times, but if you decide to go the hash route you can do so using the serialize keyword. You have to tell ActiveRecord to serialize the variable, and then it will do the serialization and deserialization automatically whenever you access the hash.
Saving arrays, hashes, and other non-mappable objects in text columns
Active Record can serialize any object in text columns using YAML. To do so, you must specify this with a call to the class method serialize. This makes it possible to store arrays, hashes, and other non-mappable objects without doing any additional work.
class User < ActiveRecord::Base
serialize :preferences
end
user = User.create(:preferences => { "background" => "black", "display" => large })
User.find(user.id).preferences # => { "background" => "black", "display" => large }
You can also specify a class option as the second parameter that’ll raise an exception if a serialized object is retrieved as a descendant of a class not in the hierarchy.
class User < ActiveRecord::Base
serialize :preferences, Hash
end
user = User.create(:preferences => %w( one two three ))
User.find(user.id).preferences # raises SerializationTypeMismatch
When you specify a class option, the default value for that attribute will be a new instance of that class.
class User < ActiveRecord::Base
serialize :preferences, OpenStruct
end
user = User.new
user.preferences.theme_color = "red"
From rubyonrails.org
From a design perspective, if you think you will ever add any more data to the available time object then you should make it its own model. Otherwise a serialized hash seems fine.
I don't see a problem with the separate table that you mentioned, I would go with that. It will also be easier to extend later which you will appreciate when the time comes.

Suggestion needed for keeping hash value in the table in rails

As an extension of the question
How to retrieve the hash values in the views in rails
I have some doubts of keeping hash values in the table..
I have a user detail table where i am maintaining the additional details of the user in a column named additional_info in a hash format .. Will it be good in keeping like so...
As if the user scenario changes if the user wants to find all the users under a particular project where i kept the project to which the user belongs in the hash format..
Give some suggestions..
Simple solution is to serialiaze it:
class FooBar < ActiveRecord::Base
# ...
serialize :additional_info
#...
end
This internally uses the YAML serializer. You can assign any object that can be serialized using YAML.
foo = FooBar.first
foo.additional_info = {:foo => 'Lorem', :bar => 'ipsum'}
foo.save
foo.additional_info[:foo] # Gives 'Lorem'

Resources