Forum: Ruby on Rails How can I use the same model/pojo as both type ActiveRecord and non-ActiveRecord. Doesn't seem dry t

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Rick (Guest)
on 2009-01-02 21:46
(Received via mailing list)
I understand I can just define a class without extending
ActiveReord::Base, but what if I want to use the model object
sometimes without having the data persist. For example...

Let's say I have an "AutoManufacturer" object it might have
name=Mercedes,etc. But AutoManufacturer could contain a collection of
"Automobile" objects, (class=CLS, model="CLS350, numberOfDoors=4").
Maybe your db isn't the one storing ALL the Automobile objects, you
might only want to store 'favorite automobiles' but you still want to
collect all the Automobile information (class, model, etc) when you
record a favorite.

So now what if I go to my DB and get my "AutoManufacturer" objects and
for each AutoManufacturer I query some webservice to return a list of
Automobiles and I want to then display on a page the AutoManufacturers
and a collection of the Automobile objects I returned from my
webservice call. If I have "Automobile" defined as an ActiveRecord
type when I do something like....

automobiles = getCarsFromWebservice()
automobiles.each do |a|
    car = Automobile.new();
    car.class= a.class
    car.type= a.type
    autoManufacturer.autos << car
end

every new car created above and added to the autoManufacturer actually
creates a new car in the db, In this case all I want is fully
populated list of autos in each autoManufacturer object for use to
display on the front end, but I don't really want the automobile added
to the db at this time. (Maybe after they select some, I'll then query
a webservice and populate a real Automobile that I do want to persist
in my db.)

Currently I'm having to do something really lame. I'm creating
basically identical objects - one a model object and one a simple
pojo. It doesn't seem very dry to do it this way though. What's a
better approach?

--
Rick
Florian Aßmann (Guest)
on 2009-01-03 06:40
(Received via mailing list)
Hi Rick, hope I got it right:

class AutomobileManufacturer < ActiveRecord::Base
   has_many :automobiles

   def favorite_automobiles
     AutomobileCollection.from_association_collection automobiles
   end
   def all_automobiles
     favorite_automobiles | remote_automobiles
   end
   def remote_automobiles
     AutomobileCollection.from_webservice
   end

end

class AutomobileCollection

   def self.from_association_collection(collection)
     collection = collection.map { |a| AutomobileItem.from_database a }
     new collection
   end
   def self.from_webservice
     # load collection... or take it as argument
     collection = collection.map { |a| AutomobileItem.from_webservice
a }
     new collection
   end

   # generate a hash to simplify intersect
   def initialize(collection)
     @collection_hash = collection.inject({}) { |hash, item|
       hash.merge item.identifier => item
     }
     @collection = collection
   end

   # this could possibly be done with ruby stdlib 'Delegate'
   def each(&block)
     @collection.each(&block)
   end

   # intersect with another automobile collections
   def |(other)
     new_keys = other.automobiles_hash.keys - @collection_hash.keys
     new_collection = @collection +
other.automobiles_hash.values_at(*new_keys)

     self.class.new new_collection
   end

   class AutomobileItem

     # two seperate methods because I think the interface for
     # webservice automobile and database automobile wont match.

     def self.from_webservice(automobile)
       instance = new automobile.manufacturer # ...
       instance
     end
     def self.from_database(automobile)
       instance = new automobile.manufacturer # ...
       def instance.favor
         # nop ...
       end
       instance
     end

     def initialize(manufacturer, *further_attributes)
       @attributes_hash = {
         # ...
       }
     end
     # generate an unique but compareable identifier
     def identifier
       "#{ manufacturer } ..."
     end
     # save the record, or maybe not when boxed automobile was loaded
from db...
     def favor
       Automobile.create @attributes_hash
       # nop
       def self.favor; end
     end
   end

end

To make a subclass of ActiveRecord::Base to something not subclassing
it requires some voodoo magic. If you really interested in this kind
of stuff you should gte yourself involved with the rubiunius project. ;)
Otherwise box them in something that would provide the same interface
for SOAPed objects as for ORMed objects.

This code is fully untested, but I hope you get the idea.

Regards
Florian

Am 02.01.2009 um 20:46 schrieb Rick:
Rick (Guest)
on 2009-01-03 19:03
(Received via mailing list)
Thanks for this Florian. I really appreciate the help. I have to admit
though being a rails and ruby newbie, I'm a bit confused by it (ok
maybe a lot confused.) (I'm a seasoned Java/JEE guy though so I'm not
having too much trouble catching on too ruby and rails.)

I've never seen a non ActionRecord object work as being persisted and
retrieved. In the case below AutomobileItem is that object that could
act as being retrieved from a db or a webservice (and as a collection
like you have shown.) I think some of the info that is left out in the
comment block in  def self.from_database(automobile) I might need to
see. Say I wanted to get a single AutomobileItem out of the db by the
automoblileID how is it done? I take it's something like setting an
AutomobileItem with the id and then passing it to the
from_database(automobile) method? I'm just clueless on how that would
work? (I probably need to find a document or something online
explaining it? I have the Agile Web D. with Rails pdf but I
don't think that covers this?)

Also what if just wanted all automobiles.. since I don't have a
AutomobileItem.find(:all), what would I call?

Sorry for these probably ignorant questions, it's just a bit difficult
for me since almost all the examples I'm finding deal with pure
ActiveRecord objects.

(Not that it matters but in real life this isn't working with
Automobiles, but rss feeds. I'm currently using Hobo migrations and my
models look like:

class RssFeed < ActiveRecord::Base

  fields do
    title :string
    body :text
    authors :string
    entry_url :string
    timestamps
  end

  belongs_to :rss_feed_source

end

class RssFeedSource < ActiveRecord::Base

    fields do
      name :string
      url  :string
      timestamps
    end

    has_many :rss_feeds

    #used for non persistent feeds
    attr_accessor :feeds

    #tried declaring array in def intitialize but must have done it
wrong
    def add_feed(feed)
      @feeds = [] if @feeds == nil
      @feeds << feed
    end

end

//see now annoying because I had to create this non persistent object
that mimics the RssFeed class!
class RssFeedNonpersistent
  attr_accessor :title, :body, :authors, :entry_url
end


On Fri, Jan 2, 2009 at 11:39 PM, Florian Aßmann
<removed_email_address@domain.invalid> wrote:
>     favorite_automobiles | remote_automobiles
>     collection = collection.map { |a| AutomobileItem.from_database a }
>   def initialize(collection)
>
>
>         # nop ...
>     def identifier
>
> Regards
>> name=Mercedes,etc. But AutoManufacturer could contain a collection of
>> webservice call. If I have "Automobile" defined as an ActiveRecord
>> every new car created above and added to the autoManufacturer actually
>> better approach?
>>
>> --
>> Rick
>>
>> >
>
>
> >
>



--
Rick
This topic is locked and can not be replied to.