Dynamic fields and inheritance

I have a model that allows subclasses to dynamically define fields.

The following code is a short test case that illustrates the problem I’m
having:

class Product < ActiveRecord::Base
acts_as_ferret :fields => [:name]

serialize :data

def self.data_properties (*properties)
properties.each do |property|
define_method(property) {self.get_property(property)}
define_method((property.to_s + ‘=’).to_sym)
{|value| self.set_property(property, value)}
end
end

def get_property (property)
self[:data][property] if self[:data]
end

def set_property (property, value)
self[:data] = Hash.new unless self[:data]
self[:data][property] = value
end
end

Here’s the migration for said model:

class CreateProducts < ActiveRecord::Migration
def self.up
create_table :products do |t|
t.column :name, :string
t.column :type, :string
t.column :data, :string
end
end

def self.down
drop_table :products
end
end

An example of a couple subclasses are:

class Book < Product
acts_as_ferret :fields => [:name, :author, :pages]

data_properties :author, :pages
end

and:

class Music < Product
acts_as_ferret :fields => [:name, :artist, :label]

data_properties :artist, :label
end

Creating a couple of records works fine:

(Book.new(:name => ‘Moby Dick’, :author => ‘Herman Melville’, :pages => 704)).save
=> true

(Music.new(:name => ‘Abbey Road’, :artist => ‘The Beatles’, :label => ‘Apple’)).save
=> true

But things start to get strange when I search for content:

Book.find_by_contents(’*’)
=> #<FerretMixin::Acts::ARFerret::SearchResults:0xb7433ef8
@total_hits=2, @results=[]>

Music.find_by_contents(’*’)
=> #<FerretMixin::Acts::ARFerret::SearchResults:0xb7431360
@total_hits=2, @results=[#<Music:0xb7431608 @attributes={“name”=>“Abbey
Road”, “type”=>“Music”, “id”=>“2”, “data”=>"— \n:artist: The
Beatles\n:label: Apple\n"}>]>

I can provide debug output for the above commands if you’d like.

My ultimate goal here is to be able to find Products by fields only
defined for Products (i.e. name) as well as to be able to find
subclasses of Products by their respective fields (i.e. find Music by
artist).

Any help, insight, or even telling me that I’m smoking crack would be
greatly appreciated.

Regards,

Evan

On Wed, Oct 11, 2006 at 01:11:32AM +0200, Evan wrote:

I have a model that allows subclasses to dynamically define fields.

The following code is a short test case that illustrates the problem I’m
having:

class Product < ActiveRecord::Base
acts_as_ferret :fields => [:name]

Don’t call acts_as_ferret in your base class, instead add the :name
field to the acts_as_ferret calls in Music and Book. That should fix
your problems.

acts_as_ferret isn’t supposed to be called twice in a model (which
is the case if you call it in your superclass, and in classes inheriting
from that).

cheers,
Jens


webit! Gesellschaft für neue Medien mbH www.webit.de
Dipl.-Wirtschaftsingenieur Jens Krämer [email protected]
Schnorrstraße 76 Tel +49 351 46766 0
D-01069 Dresden Fax +49 351 46766 66

Jens K. wrote:

On Wed, Oct 11, 2006 at 01:11:32AM +0200, Evan wrote:
Don’t call acts_as_ferret in your base class, instead add the :name
field to the acts_as_ferret calls in Music and Book. That should fix
your problems.

I assume that I will be unable to call Product.find_by_contents in this
case. So, in order to do search of all products I would have to do a
multi-index search?

On Mon, Oct 16, 2006 at 05:41:23PM +0200, Evan wrote:

Jens K. wrote:

On Wed, Oct 11, 2006 at 01:11:32AM +0200, Evan wrote:
Don’t call acts_as_ferret in your base class, instead add the :name
field to the acts_as_ferret calls in Music and Book. That should fix
your problems.

I assume that I will be unable to call Product.find_by_contents in this
case. So, in order to do search of all products I would have to do a
multi-index search?

right.

You could also do it the other way around: just call acts_as_ferret in
your
Product class, and override to_doc in your child classes to add your
dynamic
properties to the ferret document. Don’t forget to use
:store_classname => true when you call acts_as_ferret.

If you want to declare special Ferret options on a per field level,
you’d have to declare them in the acts_as_ferret call in class Product
for all kinds of products. That’s not really nice but should work.

Jens


webit! Gesellschaft für neue Medien mbH www.webit.de
Dipl.-Wirtschaftsingenieur Jens Krämer [email protected]
Schnorrstraße 76 Tel +49 351 46766 0
D-01069 Dresden Fax +49 351 46766 66

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs