Rails: Serializing Objects in a Database

Rails: Serializing objects in a database?

In computer science, in the context of data storage and transmission, serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file, a memory buffer, or transmitted across a network connection link to be "resurrected" later in the same or another computer environment.
(see http://en.wikipedia.org/wiki/Serialization)

  1. So serialized objects (in the context of ActiveRecord) are text/string representations of objects (encoded using YAML). When serialized, you can save (almost) any Ruby object in a single database field.

  2. You can use serialization if you have somewhat complex objects that you need to save in a database and you don't need to retrieve records based on the contents of a serialized attribute. I used them for example for storing preferences for users of a webapp: the preferences were basically hashes that I wanted to save in a single db field.

3./4./5. Use ActiveRecord::Base.serialize as Marc-André Lafortune suggested:

class User < ActiveRecord::Base
serialize :preferences
end

u = User.new
u.preferences = {:show_tooltips => true, :use_extended_menu => false, ...}
u.save

# ...

u = User.find(23)
u.preferences # => {:show_tooltips => true, :use_extended_menu => false, ...}

Serializing ActiveRecord objects without storing their attributes?

As far as I understand your problem you should google for: acts_as_nested_set better_nested_set even_better_nested_set and awesome_nested_set. I know they don't store the serialized hierarchies, but you should store their nodes atomically. Even huge traffic sites do that. Other than that - you should consider NoSQL (or schema-less DB).

Why is my object getting serialized into a string not text in my Rails ActiveRecord DB?

I see in your source code:

class Query
def initialize
@client = Soundcloud.new(:client_id => API_KEY)
end

def query_user(user_url)
@user_url = user_url
@user = @client.get('/resolve', :url => @user_url)
end
end

At this point @user is a still a SoundCloud::HashResponseWrapper object.
If you wanna store the data as string text you'll need to first do:

@user.to_json

To save it with symbolized keys in the db:

data = JSON.parse(@user.to_json).symbolize_keys
sc_user = SoundcloudUser.new(user_hash: data)

But you still can't call .key on a hash. If you want to call the value of the key you'll need to do:

sc_user.user_hash[:username] #for example

There are ways to extend your model but that's out of scope for this question.

UPDATE: Here's your updated controller:

class SoundcloudQueriesController < ApplicationController
def new

end

def index
@user = SoundcloudUser.find(3)
@user_hash = @user.user_hash # but do you even need this?
end

def create
sc_user_data = Query.new.get_user params[:username]
@soundcloud_user = SoundcloudUser.create({
user_name: sc_user_data[:username],
user_hash: JSON.parse(sc_user_data.to_json).symbolize_keys
})
end

def show

end
end

You'll also need to modify your Query class to be able to build a user from the souncloud username. It will look like this:

class Query
BASE_RESOLVE_URL="http://soundcloud.com/"

def initialize
@client = Soundcloud.new :client_id => ENV['SC_CLIENT_ID']
end

def query_user(user_url)
@user_url = user_url
@user = @client.get('/resolve', :url => @user_url)
end

def get_user(username)
@client.get('/resolve', url: BASE_RESOLVE_URL+username)
end

end

I'm not exactly sure what you want to use the query_user method for, or if you can just remove it and use get_user instead. In any case I forked your repo, got the controller create test passing. Will send PR.

Deserialized Rails ActiveRecord object won't save to SQL database

Solved: Calling var_name.dup.save works.

Intermediate debugging steps that might be helpful:

[6] pry(main)> fpt.valid?
=> true
[7] pry(main)> fpt.changed?
=> false
[8] pry(main)> fpt.save!
=> true
[9] pry(main)> FakeProductTest.count
=> 0
[11] pry(main)> fpt.errors.messages
=> {}

Thanks to @thorncp

How to add an element into an array of a Serialize Field using Ruby on Rails

Base on @veridian-dynamics (thanks for your help!) Here what I did.

Model:

class MyModel < ApplicationRecord
serialize :item_data, JSON
end

Controller:

class ItemController  < ApplicationController
before_action :authenticate_user!

def add_item
begin

mymodel = MyModel.find_or_create_by(id: param[:model_id])

if mymodel .item_data.blank?
item = {:items => []}
else
item = mymodel.item_data.deep_symbolize_keys
end

bookmark_exist = item[:items].any? {|i| i[:id] == params[:id]}
if !bookmark_exist
item[:items] = item[:items ].append({id: params[:id]}) # adding a new item
end

mymodel.item_data = item
mymodel.save

return render :json => item, :status=> 200

rescue Exception => e
return render :json =>{:errors=>e.message}, :status=> 400
puts "ERROR: #{e.message}"
end
end

def delete_item
begin

mymodel = MyModel.find_by(id: params[:model_id])
if mymodel.present? && mymodel.item_data.present?
item = mymodel.item_data.deep_symbolize_keys

item[:items] = (item[:items].select { |itm| itm[:id] != params[:id] }) # remove an item
mymodel.item_data = item
mymodel.save

return render :json => item, :status=> 200
end
rescue Exception => e
return render :json =>{:errors=>e.message}, :status=> 400
puts "ERROR: #{e.message}"
end
end

end

Rails can't write to serialized array field in database

If you're using native PostgreSQL arrays (which you are since you have array: true in your migration) then you shouldn't use serialize at all. serialize is used to store YAML in the database:

serialize(attr_name, class_name_or_coder = Object)

If you have an attribute that needs to be saved to the database as an object, and retrieved as the same object, then specify the name of that attribute using this method and it will be handled automatically. The serialization is done through YAML. If class_name is specified, the serialized object must be of that class on assignment and retrieval. Otherwise SerializationTypeMismatch will be raised.

So serialize simply stores a YAML-encoded object inside a text column in the database. But PostgreSQL, ActiveRecord in Rails4, and the underlying PostgreSQL driver all understands arrays without all the YAML unpleasantness.

Leave the array: true in your migration, remove the serialize :content, Array from your model, and it should work fine. As an added bonus, you'll be able to use all of PostgreSQL's array operators and functions to query your content, serialize doesn't allow you to do this.

De-serializing rails database array

It looks like you have some stray data in there which is mucking things up. The first thing that's inserted into the block is '1', and then when '1'.username is called your error is thrown. You can sidestep this issue by skipping anything that's not a User:

<ul class="list-group">
<% @user.company.members.each do |m| %>
<% break unless m.class == User %>
<li class="list-group-item"><%= m.username %></li>
<% end %>
</ul>

But that's a really ugly solution and you should probably figure out why you have stray data polluting your database in the first place. I think what you might actually be trying to do is use a has_many/belongs_to association to tie Users to a Company. Instead of using serialize, rails can handle all of the gruntwork for you.



Related Topics



Leave a reply



Submit