Forum: Ruby on Rails Applicationwide BusinessObject/Hash

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.
Michael K. (Guest)
on 2006-03-20 10:57
(Received via mailing list)
Hello,

I'm a total newbie, so please forgive my ignorance.

I am trying to port an application from java to ruby. In order to do
that, I
need to put the object containing all the business logic into something
like
application scope.

The nicest solution would be just to have an application wide hash,
where I can
put all kinds in of objects.

Where and how would I instantiate such an object?

Would I do that in the environment.rb?

Greetings

Michael K.
Tim C. (Guest)
on 2006-03-20 11:28
(Received via mailing list)
With Rails the convention is to create classes of models which contain
the
business logic.  So if we have an object modelling a customer, then we
would
go ahead and create a customer.rb in models and place the business logic
for
a customer in this class.  It's not required but usually there is the
need
to save an object back into the database, the rails convention for this
is
to have a table called customers.

I'm not sure if I'm understanding your question correctly but it seems
like
you might be better off creating individual model classes and placing
business logic inside of them, by doing so you pretty much acheive
application scope as they can be instantiated from virtually anywhere in
the
application.

HTH,

Tim C.
removed_email_address@domain.invalid
Michael K. (Guest)
on 2006-03-20 11:47
(Received via mailing list)
Tim,

thanks for the quick reply. Sorry for not having been explicit.

Here's a rough outline of the design scenario:

A. I want all business logic to be encapsulated and separated from the
front
end. It has to be able to work without Rails. Thus, I might even be able
to use
it as console or windowed GUI application.

B. Business Data comes from all kind of sources i.e. remote XML-Servers,
local
databases etc. Thus one of the tasks the business layer is supposed to
do ist to
gather all the data from these sources and tansform them to a common
object model.

Since gathering the data and tranforming it to a common model consumes
quite
some time, I only want to do it once, an make it available to all users.

C. Third: Business logic, like some major calculations etc. being
executed in
the busines model.

D: Rails is simply used for MVC operations - not for business logic or
database
access.

So it's a standard three tier scenario.


Sincerely

Michael K.
Alex Y. (Guest)
on 2006-03-20 11:59
(Received via mailing list)
Michael K. wrote:
> Tim,
>
> thanks for the quick reply. Sorry for not having been explicit.
>
> Here's a rough outline of the design scenario:
>
> A. I want all business logic to be encapsulated and separated from the
> front end. It has to be able to work without Rails. Thus, I might even
> be able to use it as console or windowed GUI application.
I guess the standard response here would be to have a separate app
exposing an RPC (be that DRb, XML-RPC, SOAP, or whatever) interface to
Rails.

> B. Business Data comes from all kind of sources i.e. remote XML-Servers,
> local databases etc. Thus one of the tasks the business layer is
> supposed to do ist to gather all the data from these sources and
> tansform them to a common object model.
These could happily all sit in the Rails object-space, but I can
understand the motivation behind the separation.

> C. Third: Business logic, like some major calculations etc. being
> executed in the busines model.
Again, this is home territory for Rails.

> D: Rails is simply used for MVC operations - not for business logic or
> database access.
In Rails-speak, you're talking about Rails being used for VC operations,
with the M being split out to a separate app.

> So it's a standard three tier scenario.
Rails sits best as the entire middle tier of a three-tier scenario,
where the back tier is the database rather than an external model, but I
can't see anything specifically wrong with your suggestion.
Michael K. (Guest)
on 2006-03-20 12:18
(Received via mailing list)
Alex,

 > but I can't see anything specifically wrong with your suggestion.

Hopefully ;-)

What I wonder is _how_ and _where_ do I put my business object into
something
like an application scope?

I am very new to Ruby and Rails, so please excuse my naive question.

Is config/environment.rb the right place? If I instantiate an object in
config/environment.rb, will it then be available to all controllers?

How would I do that?

Greetings

Michael K.
Tim C. (Guest)
on 2006-03-20 12:25
(Received via mailing list)
Wow, okay that's a tall set of requirements, I don't want to discourage
you
but doing something like this is non-trivial in any environment, and it
sounds like you want to create a domain specific language from disparate
data sources which Ruby actually excels at doing, but the true measure
of
how easy or hard this will be to do in Ruby also depends on how
comfortable
you are with these concepts.

Firstly, the M in MVC is for Model and in Rails model objects are
represented as classes.  If you are comfortable with object oriented
programming then you can create plain old ruby classes that can
encapsulate
business logic data within them.  They can be used by Rails or they can
be
used by any other device that can access a plain old .rb file, including
consoles and windowed gui applications.  Additionally, if you want to
hook
them up to a database then you can subclass these objects to inherit
from
Rails ActiveRecord which provides an ORM solution to persist to a db,
and if
you choose to do this then you should be aware of ActiveRecord
conventions
for tables and objects.  Now these model objects can exist and be used
within the context of a Rails application or outside of it, they do not
come
coupled to the controller and view, and thus you already have achieved a
three-tier scenerio, by virtue of the way Rails is designed.

Now the hardest part of what you are describing will be gathering data
from
all the different sources you listed and turning them into a common
object
model, because you are asking to do this I'm assuming you know what you
are
getting into and so I'm going to point you to an article that may be a
help:

http://www.artima.com/rubycs/articles/ruby_as_dsl.html

This article describes creating a Domain Specific Language in Ruby,
which
I'm guessing is what you are attempting to do.

As for answering your original question my answer remains the same in
that
your best bet is to place your business logic into classes in the model
that
best represent the behaviors of the objects you are trying to model.

HTH,

Tim C.
removed_email_address@domain.invalid
Michael K. (Guest)
on 2006-03-20 12:40
(Received via mailing list)
Hello Tim,

I've basically solved the gathering of the data already. So the Business
model
is in principle working so far.

I've been programming with Java for years now, so I do have a _little_
experience in applying OO and MVC concepts.

What I am looking for is an application scope context like the one a
java
servlet i.e. a java web application provides. Maybe simply a hash
instance,
where objects can be put and accessed.

Would be helpful for in-memory-session tracking too. But that's another
story.

So, my question is: _where_ (in which class or file) do I instantiate
the
business object in order to have this _one_ instance available for the
controllers?

Greetings

Michael
Alex Y. (Guest)
on 2006-03-20 12:48
(Received via mailing list)
Michael K. wrote:
>
> Is config/environment.rb the right place? If I instantiate an object in
> config/environment.rb, will it then be available to all controllers?
Yes, but you're better off putting the config information in
config/environment.rb, and then using a model class to wrap access to
your external business logic application.  In pattern-speak, you want a
a delegator to live in your app/model directory.  It might look a little
like this (untested, so YMMV):

require 'drb'
class BusinessLogic < DRbObject
   def initialize
     super(nil, EXTERNAL_LOGIC_URI)
   end
end

Then in config/environment.rb, you can set:

EXTERNAL_LOGIC_URI = "druby://localhost:49812"

or wherever your external logic handler lives.  That should give you the
ability to say in your controller, for example:

def view
   app = BusinessLogic.new
   @message = app.motd
   @system_load = app.load
end

def long_and_complex_calculation
   @status = BusinessLogic.new.do_long_calc(params[:whatever])
end

assuming that the motd(), load() and do_long_calc() methods are defined
on whatever object your BusinessLogic class connects to.

> How would I do that?
What I'd recommend is checking out the example DRb scripts that come
with Ruby.  That'll give you a better handle on
what sort of configuration options you'll need to play with, and how
they might interact with Rails.
Alex Y. (Guest)
on 2006-03-20 12:54
(Received via mailing list)
Michael K. wrote:
> What I am looking for is an application scope context like the one a
> java servlet i.e. a java web application provides. Maybe simply a hash
> instance, where objects can be put and accessed.
There's a reason that this isn't particularly addressed by Rails.  The
scaling model assumes that there is no such thing as an application
scope in the same sense as in a java web application, because it's
designed to scale horizontally simply by adding more separate boxes to a
cluster, and assuming that there's no connection between them.

> So, my question is: _where_ (in which class or file) do I instantiate
> the business object in order to have this _one_ instance available for
> the controllers?
If you instantiate something in environment.rb, it'll be available to
each request, but it might not persist, and it won't be available
between processes.  I've outlined in another email how I approach this
sort of problem.

Another cognitive jump to bear in mind (apologies if you've already made
it, many don't) is that the controllers don't persist at all.  A new one
gets instantiated for each request, so don't expect things like instance
variables to hang around between requests.
Michael K. (Guest)
on 2006-03-20 13:33
(Received via mailing list)
Alex,

first of all: many thanks! That's a neat solution. Almost a little
"application
server" of it's own right.

Well, yes, I knew controllers don't persist. One shouldn't use them
holding
states anyway. That's why I was looking vor  solution to keep track of
memory
sessions too. With the solution you proposed, that should work too.

Thanks once again for your help.

Greetings

Michael K.
Alex Y. (Guest)
on 2006-03-20 14:41
(Received via mailing list)
Michael K. wrote:
> Well, yes, I knew controllers don't persist. One shouldn't use them
> holding states anyway. That's why I was looking vor  solution to keep
> track of memory sessions too. With the solution you proposed, that
> should work too.
There's a quick guide to setting up memory-based sessions with DRb on
the wiki, I think.  Might be worth a look.

>
> Thanks once again for your help.
No worries :-)
Michael K. (Guest)
on 2006-03-20 15:16
(Received via mailing list)
Alex,

that's once again a great hint. I was looking for a solution like that
for a
while already.

Where (in which file/object) would I invoke the startup of the DRb
server
and where would I shut it down?

Greetings

Michael K.
Alex Y. (Guest)
on 2006-03-20 17:13
(Received via mailing list)
Michael K. wrote:
> Alex,
>
> that's once again a great hint. I was looking for a solution like that
> for a while already.
>
> Where (in which file/object) would I invoke the startup of the DRb server
> and where would I shut it down?
You've got a couple of options there.  Either you can handle it entirely
separately, as its own app, or you can tie the startup and shutdown into
the Rails startup and shutdown sequence.  Since you've said that you
want to be able to access it independently of Rails, I'd think that the
former would be more appropriate, because you'd be able to take Rails
offline (if necessary) and still maintain the business logic
functionality for whatever else needed access to it.

If you're handling it as its own app, you get to choose where to put it
and how to handle startup and shutdown.  Again, this is somewhere that a
little familiarity with DRb would help.  Once you've got your buiness
logic wrapped up in the appropriate object, I'd make a simple wrapper
script for it, a little like this (I'm assuming you're on a *nix of some
kind):

require 'drb'
require 'business_logic'
fork and exit
DRb.start_service('druby://0.0.0.0:48912', BusinessLogic.new)
trap('TERM'){ DRb.stop_service and exit }
DRb.thread.join

Of course, that's ludicrously simplified (and, again, untested, but you
get the idea), but that sort of thing's all you really need.  Run it to
start the service, send it a SIGTERM to shut it down.  Simple, really
:-)

--
Alex

(...who is, quite coincidentally, available for consultancy on these
things :-) )
Michael K. (Guest)
on 2006-03-20 17:24
(Received via mailing list)
Hello Alex,

thank again. Well, I wanted the application to be independent of any
external
tools like e.g. cron.

The cleanest deployment option, which I really prefer, would be to have
the DRb
server included in the Rails application. I really don't want to steal
too much
of your time, but if I could get this last bit of information, how to
have the
DRb server tied in into the startup and shutdown seqence, that would
really get
me going.

Greetings

Michael K.
Ben M. (Guest)
on 2006-03-20 18:45
(Received via mailing list)
Well Micheal, I hope your questions have been answered well enough. I
could have saved a
little bit of back and forth by going straight to this: you are looking
for a container;
rails doesn't have a container. Well, I think I was told that Mongrel is
supposed to
fulfill that need, but now I'm not sure.

I went through this java-world-esque withdrawl a while back:

http://thread.gmane.org/gmane.comp.lang.ruby.rails/48539

I eventually shut up because I can't really say that the container route
is any better
than having a DRb process to hold application scope. And it's actually
probably more
scalable. Although ironically I think the ruby/rails/lamp way goes
straight for the
massively scalable solution and makes it more work for the average need
(probably more
like 80%).

Well, I don't have any statistics to back that up, so.... And really my
interest in the
whole issue was that using a servlet container is -- on the whole --
dead simple and it
gives me an application environment to do my work in. I had assumed that
Ruby, being a VM
language, would have taken the same approach. But not only has it not,
but apparently many
rubyists simply don't understand what I'm talking about.

Anyway, that's my take on the issue. I suppose when in Rome.....

b
Alex Y. (Guest)
on 2006-03-20 19:11
(Received via mailing list)
Michael K. wrote:
> Hello Alex,
>
> thank again. Well, I wanted the application to be independent of any
> external tools like e.g. cron.
Fair enough, although I don't think you'd need anything other than a
shell script in the right place.  Which OS are you deploying to?

> The cleanest deployment option, which I really prefer, would be to have
> the DRb server included in the Rails application.
What you could do, although this is pushing the definition of "included
in the Rails application" somewhat, is put your business logic code and
the DRb wrapper in the lib/ directory of the Rails app.  That at least
puts your code all in one place.  I don't know if you've looked at how
you're going to deploy your app yet, but I'd recommend taking a look at
Capistrano.  If you do go that way, you could set up a custom startup
task that kicks off the DRb server, and a shutdown task that stops it,
quite simply.

I'm wondering - how are you planning to test against your business
logic?  Presumably it has some form of state marshalling?

>  I really don't want to
> steal too much of your time, but if I could get this last bit of
> information, how to have the DRb server tied in into the startup and
> shutdown seqence, that would really get me going.
There's really no facility (that I know of, anyway - I might have missed
something) for shutting down like that.  Startup's relatively easy to
bodge together, but...  Rails just doesn't work that way.
Michael K. (Guest)
on 2006-03-20 23:08
(Received via mailing list)
Yep, coming from java and trying to explain one's requirements to Ruby
programmers is like explaining one's customs to somebody from an
entirely
different culture. It's interesting, though ...

The Ruby people are very kind have been very patient with me.

What I found out so far is, that there's usually a "Ruby way" for what
I'm
looking for. But I've just started with Ruby. It all boils down to the
right
communication i.e. translation.

Thanks for sharing your experience with me. So, at least, I know I am
not the
only Java expat in Rubyland ... ;-)

Greetings

Michael
Michael K. (Guest)
on 2006-03-20 23:20
(Received via mailing list)
Hi Alex,

well, regarding the startup of a DRb server from Rails, I believe I
found, what
i was looking for:

http://wiki.rubyonrails.com/rails/pages/HowToCallD...

I am deploying to a FreeBSD server. I am also developing on FreeBSD. So
it's got
cron anyway. But there might be situations, where I might have to deploy
to a
Windows server.

When it comes to deployment, I think, I will simply shovel up all my
files via
scp or ftp the old fashioned way.

Testing? Shame on me! I haven't thought about it yet. First I'd like to
get the
basics running. I don't have a clue about testing yet.

For the time being I'm busy putting the bits and pieces together to be
able to
port my Java app to Ruby. I'm about to get there ...

Greetings

Michael
Alex Y. (Guest)
on 2006-03-21 12:43
(Received via mailing list)
Michael K. wrote:
> Hi Alex,
>
> well, regarding the startup of a DRb server from Rails, I believe I
> found, what i was looking for:
>
> http://wiki.rubyonrails.com/rails/pages/HowToCallD...
Actually, that's the startup of a DRb *client*...  You'll still need the
other end of the connection.

> I am deploying to a FreeBSD server. I am also developing on FreeBSD. So
> it's got cron anyway. But there might be situations, where I might have
> to deploy to a Windows server.
I don't believe you'll need cron.  All you need is a way to daemonize
(BSD, fork()) or servicify (Windows, SAPI?) a single Ruby script.

> When it comes to deployment, I think, I will simply shovel up all my
> files via scp or ftp the old fashioned way.
I can understand keeping things simple for now.  However, make a note in
your diary to learn Capistrano.  It *really* simplifies things.

> For the time being I'm busy putting the bits and pieces together to be
> able to port my Java app to Ruby. I'm about to get there ...
Fair enough.  There are Many Things that don't quite work the same way
in Ruby-land, so be prepared for some surprises (pleasant, I hope :-) )
Michael K. (Guest)
on 2006-03-21 16:12
(Received via mailing list)
Hi Alex,

I got the client and the server working on startup.

DRb.start_service("druby://localhost:9002", AppServer.new)
$client_drb = DRbObject.new(nil, "druby://localhost:9002")

But there seems to be a drawback to starting servers in environmenet.rb:

There's no shutdown process to hook in DRb.stop_service . At least I
haven't
found one, which means I have to start the server outside of rails
separately.

Something strange happens: when I use this kind of DRb startup and I
shutdown
WebBrick or Apache (FCGI) the process still exists. But most amazingly:
I cannot
kill it!

So the port, e.g. remains occupied and thus restarting the Rails
application is
not possible anymore.

What really strikes me most is that I can not kill the process.

Since there

Greetings

Michael
Ezra Z. (Guest)
on 2006-03-22 06:35
(Received via mailing list)
Guys-

	I just wanted to chime in here and give you a little nugget I have
been using for this exact purpose. It's a lib called slave that
creates a forked drb daemon for you and manages a heartbeat between
the server/clent so if one goes down the other goes down the next
time it heartbeats.

http://codeforpeople.com/lib/ruby/slave/slave-0.0.0/README

	You can just create your server and client in one swoop.

###drb slave in environment.rb###
require 'slave'
$app_server_client = Slave.new(AppServer.new).object

	And thats it. Now when you kill rails the forked drb server dies on
its next heartbeat call to the client. Also if you are using any
ActiveRecord classes over the wire like this with drb you need to use
include DrbUndumped in your AppServer class. This way the method
calls will be proxied across the drb channel instead of marshalling
the entire object over the wire.

Enjoy!

-Ezra
Alex Y. (Guest)
on 2006-03-22 10:58
(Received via mailing list)
Ezra Z. wrote:
>     You can just create your server and client in one swoop.
> object over the wire.
>
> Enjoy!
Oh, for crying out loud!  Do you not *sleep*, or something? :-)

Looks fantastic, I'll be trying it out today...
Ezra Z. (Guest)
on 2006-03-22 21:58
(Received via mailing list)
On Mar 22, 2006, at 12:56 AM, Alex Y. wrote:

>> require 'slave'
> Looks fantastic, I'll be trying it out today...
>
> --
>
> Alex


	Haha! I do sleep occasionally. This lib works great for the exact
purpose of this thread ;)

Cheers-
-Ezra Z.
Yakima Herald-Republic
WebMaster
http://yakimaherald.com
509-577-7732
removed_email_address@domain.invalid
This topic is locked and can not be replied to.