Wednesday, April 30, 2008

Deserializing object failed in ActiveRecord

The serialize in ActiveRecord failed to deserialize object correctly

class ListTracker < ActiveRecord::Base
serialize :query_list
serialize :query
belongs_to :user
end

class QueryList
attr_accessor :class_name
def initialize(class_name = "")
@items = []
@restrict_items = []
@class_name = class_name.strip
@order_field = "id"
@order_direction = ""
@sort_items = []
@table_included = Set.new
end
def class_name
@class_name ||= ""
end
end


1.query_list = QueryList.new
2.list_tracker = ListTracker.new
3.list_tracker.query_list = query_list
4.list_tracker.save

In line 1 new QueryList object is created
In line 2 new ListTracker object is created
In line 3 QueryList object is assigned to query_list method(column in table which is serialized) of ListTracker an ActiveRecord decendent.
In line 4 ListTracker object is saved to table.

In Rails 1.2.3,

>> t = ListTracker.find(:first)

=> #"contacts", "updated_at"=>"2007-04-04 16:13:17", "query_list"=>"— !ruby/object:QueryList \nclass_name: Contact\nitems: \n - !ruby/object:Query \n after_blanket_count: 0\n before_blanket_count: 0\n join: OR\n key: id\n negation: false\n op: st\n table: contacts\n value: 62d703da-707c-11db-80be-000c6e8c7636\n - !ruby/object:Query \n after_blanket_count: 0\n before_blanket_count: 0\n join: OR\n key: id\n negation: false\n op: st\n table: contacts\n value: 1faad762-707c-11db-80be-000c6e8c7636\norder_direction: ''\norder_field: id\nrestrict_items: []\nsort_items: \n - !ruby/object:QuerySort \n descending: false\n field: created_at\n field_type: contacts\n summary: false\ntable_included: !ruby/object:Set \n hash: {}", "id"=>"64", "order_by"=>"", "user_id"=>"f7163ddc-fc4a-11da-81a0-000c6e8c7636"}>

>> t.query_list

=> #[#"st", "after_blanket_count"=>0, "value"=>"62d703da-707c-11db-80be-000c6e8c7636", "table"=>"contacts", "before_blanket_count"=>0, "negation"=>false, "key"=>"id", "join"=>"OR"}, @class="Query">, #"st", "after_blanket_count"=>0, "value"=>"1faad762-707c-11db-80be-000c6e8c7636", "table"=>"contacts", "before_blanket_count"=>0, "negation"=>false, "key"=>"id", "join"=>"OR"}, @class="Query">], "class_name"=>"Contact", "table_included"=>#, "restrict_items"=>[], "order_direction"=>"", "sort_items"=>[#"created_at", "summary"=>false, "descending"=>false, "field_type"=>"contacts"}, @class="QuerySort">], "order_field"=>"id"}, @class="QueryList">


Deserializing it gives a strange class of YAML::Object.

For some quick dirty fix Load the QueryList.. class before deserialize happens
I think rails dependency system didn't load the class before deserialize cause the problem.
change the ListTracker to:

class ListTracker < ActiveRecord::Base
QueryList
Query
serialize :query_list
serialize :query
belongs_to :user
end

hope this helps.

Source : Rails trac

Extend Your ActiveRecord Association Methods

Much of the beauty of ActiveRecord associations is in the collection methods that are provided for you when you define has_many relationships.
For instance, when we say:

class Organization < ActiveRecord::Base
has_many :people
end

We now have an organization.people method that returns the collection of associated people within the organization. Easy enough. We also get nice little methods on the collection of people like organization.people<<, organization.people.build, organization.people.create and organization.people.find (among others). Well what if you wanted to define your own method on this auto-magically provided collection method? You do this through Association Extensions which let you define methods to add to the collection. You can define an association extension either with a block or a module – we’ll use a block provided to the has_many call here as it’s the most common way to do so:

class Organization < ActiveRecord::Base
has_many :people do
def find_active
find(:all, :conditions => ["active = ?", true])
end
end
end

I’ve defined a find_active method which will retrieve all people in the organization that have the active column set to true. This can be invoked very intuitively with: organization.people.find_active

This is a great way to provide convenience finder methods for common retrievals on the associated collection.

If you want to define an extension as a module just provide the :extend option in your has_many definition:

module FindActiveExtension
def find_active
find(:all, :conditions => ["active = ?", true])
end
end
class Organization < ActiveRecord::Base
has_many :people, :extend => FindActiveExtension
end

You can customize to your heart’s content – these are just some simplistic examples of how to plug into this nifty feature. I just recently stumbled upon it and thought it might be worth spreading the word since I found myself smitten by it.

Resources • Josh Susser’s New association goodness in Rails 1.1, part 2 • Association Extension API docs

Turn Deprecation Warnings Off in Rails

Rails deprecation warnings that you’ll see when you do naughty things like access @cookies from your controller or use deprecated methods like ActiveRecord’s find_all. Sometimes it’s useful to turn off those warnings – especially when they’re coming from a part of your application you don’t control (i.e. a third-party library).

To turn off all deprecation warnings, just do the following:

ActiveSupport::Deprecation.silenced = true

Or, if you want to perform something other than spit out deprecation warnings you can re-route them however you want within a block:

ActiveSupport::Deprecation.behavior = Proc.new { |msg, stack| MyLogger.warn(msg) }


Or, if you want to be more granular, you can silence specific parts of your code that you know reference deprecated code:

def bad_action
ActiveSupport::Deprecation.silence { p "Referencing #{@cookies} is bad" }
end

Bang Methods In Ruby

In Ruby, you can write methods whose names end in ! (exclamation point or “bang”). There’s a lot of confusion surrounding the matter of when, and why, you would want to do so.

What ! does (and does not) mean

The ! in method names that end with ! means, “This method is dangerous”—or, more precisely, this method is the “dangerous” version of an otherwise equivalent method, with the same name minus the !. “Danger” is relative; the ! doesn’t mean anything at all unless the method name it’s in corresponds to a similar but bang-less method name.

So, for example, gsub! is the dangerous version of gsub. exit! is the dangerous version of exit. flatten! is the dangerous version of flatten. And so forth.

The ! does not mean “This method changes its receiver.” A lot of “dangerous” methods do change their receivers. But some don’t. I repeat: ! does not mean that the method changes its receiver.

Don’t overuse the !
Not every !-method changes its receiver, and not every receiver-changing method ends with !. There’s Array#pop/push/shift/unshift/concat/clear, and lots of others.

Don’t add ! to your destructive (receiver-changing) methods’ names, unless you consider the changing to be “dangerous” and you have a “non-dangerous” equivalent method without the !. If some arbitrary subset of destructive methods end with !, then the whole point of ! gets distorted and diluted, and ! ceases to convey any information whatsoever.

If you want to write a destructive method and you don’t think the name conveys destruction, you might be tempted to add a ! to make it clear. That’s not a good idea. If the name of a destructive method, without a !, does not connote destruction, then the name is wrong and cannot be repaired by slapping a ! on it.

In such a case, you should create the traditional pair of methods: a non-bang method and a bang method. It’s conventional to define the non-bang method in terms of the bang one. Here’s an example involving a simplistic version of an Array#flatten_once method (it doesn’t handle nested objects other than arrays very well, but it makes the bang-point):

class Array
def flatten_once!
res = [] each do |e|
[*e].each {|f| res << f }
end
replace(res)
end
def flatten_once
dup.flatten_once!
end
end

The non-bang method is defined in terms of the bang method. You wouldn’t want to write an isolated method called flatten_once! without the matching non-bang version, since there’s no way to measure the “danger” except in relation to the non-dangerous method.

Danger takes many forms
Sometimes you get more than one kind of “danger” even within one bang method. Take String#gsub!. This method changes its receiver:
str = "David" str.gsub!(/$/, " Black") str # David Black It also differs from gsub (non-bang) in that if the string does not change, gsub returns a copy of the unchanged string but gsub! returns nil:
str.gsub(/xyz/, "blah") # David Black str.gsub!(/xyz/, "blah") # nil str # David Black The ! in gsub! gives you a heads-up: it warns you of danger, and that means that before you use the method, you should find out exactly how it behaves. (A simple “ri String#gsub!” should do it.)