Refactoring module


#1

Dear all

Please see the following module, In module SX3 SX4 and SX5 have similar
class Tasklist, but inherit from different class.

I will use the following code to connect to different data sources
RemoteSX3Model.establish_connection sx3_hash
RemoteSX4Model.establish_connection sx4_hash
RemoteSX5Model.establish_connection sx5_hash

How can I refactor my code in module to look simpler? Thank you very
much


class RemoteSX3Model < ActiveRecord::Base
def readonly?
true
end
end

class RemoteSX4Model < ActiveRecord::Base
def readonly?
true
end
end

class RemoteSX5Model < ActiveRecord::Base
def readonly?
true
end
end

module SX3

class Request < RemoteSX3Model
set_table_name “request”
set_primary_key “req_reqno”
has_many :print_audit, :class_name => “PrintAudit”, :foreign_key =>
“prtaud_reqno”
has_many :request_copy_hist, :class_name => “RequestCopyHist”,
:foreign_key => “reqcp_reqno”
belongs_to :patient, :class_name => “SX9::Patient”, :foreign_key =>
“pat_encounter_group”
end

class RequestCopyHist < RemoteSX3Model
set_table_name “request_copy_hist”
belongs_to :request, :class_name => “Request”, :foreign_key =>
“reqcp_reqno”
end

class Tasklist < RemoteSX3Model
set_table_name “lisg_tasklist”

def self.find_incompete_tasklist
  find(:all, :conditions => ["g_status in (0,10,98) and

g_request_time between ? and ?", 1.day.ago, 30.minute.ago])
end

end
end

module SX4
class Tasklist < RemoteSX4Model
set_table_name “lisg_tasklist”

def self.find_incompete_tasklist
  find(:all, :conditions => ["g_status in (0,10,98) and

g_request_time between ? and ?", 1.day.ago, 30.minute.ago])
end

end
end

module SX5
class Tasklist < RemoteSX5Model
set_table_name “lisg_tasklist”

def self.find_incompete_tasklist
  find(:all, :conditions => ["g_status in (0,10,98) and

g_request_time between ? and ?", 1.day.ago, 30.minute.ago])
end

end
end


#2

you could create an abstract model RemoteModel from which
RemoteSX3/4/5Model inherit.
then you can move the methods self.find_incompete_tasklist and
readonly? to that newly created model. that would shorten your code a
lot. and copy/paste-errors like self.find_incompete_tasklist instead
of self.find_incomplete_tasklist won’t happen.


#3

MaD wrote:

you could create an abstract model RemoteModel from which
RemoteSX3/4/5Model inherit.
then you can move the methods self.find_incompete_tasklist and
readonly? to that newly created model. that would shorten your code a
lot. and copy/paste-errors like self.find_incompete_tasklist instead
of self.find_incomplete_tasklist won’t happen.

Thanks for reply.

As I am a beginner, could you give me some example for reference?

Thanks again.
Valentino


#4

class GenericModel < ActiveRecord::Base

GenericModel implements many methods that a specific model class can

then

override in its own definition if needed.

self.abstract_class = true

def some_method(some_param = nil)
# this defined the “default” behavior
end
end

class Project < GenericModel

if this doesnt declare some_method, it uses the method in

GenericModel

end

class Scenario < GenericModel
def some_method(some_param = ‘sam’)
# scenario uses this method, not the one from GenericModel
end
end

class Testcase < GenericModel

uses the GenericModel version of some_method

end

NOTE: You can also do this with controllers… I have many in my app
that
are little more than:

class ProjectsController < GenericController
def action1_specific_to_this_model
end

def action2_specific_to_this_model
end
end

GenericController does all the standard stuff (index, edit, show, save,
update, delete) by looking at the params[:controller] and doing things
like

@object =
params[:controller].singularize.camelcase.constantize.find(params[:id])


#5

Sorry, what MaD and I were hinting at was something more along the lines
of:

ActiveRecord > RemoteModel > RemoteSX(n)Model

where all the common things (like the readonly? and the
find_incomplete_tasklist methods, or any new common methods) are defined
in the RemoteModel class

RemoteModel is declared an abstract_class. When RemoteSX3Model (or 4 or
5 - your ‘concrete’ classes) inherits from RemoteModel, those classes
don’t need to define the methods already present in RemoteModel (unless
they are overriding the definition), and you get a single source for
your method code that is shared among the concrete models.


#6

Ar Chron wrote:

RemoteModel is declared an abstract_class. When RemoteSX3Model (or 4 or
5 - your ‘concrete’ classes) inherits from RemoteModel, those classes
don’t need to define the methods already present in RemoteModel (unless
they are overriding the definition), and you get a single source for
your method code that is shared among the concrete models.

Thanks for your help.

Sorry that I am a green programmer and not really familiar with OO, I am
confused now. My understanding is that

class GenericModel < ActiveRecord::Base
self.abstract_class = true
def method_1
end
def method_2(a=10)
a + 10
end
def method_3
end
end

class RemoteSX3Model < GenericModel
end

class RemoteSX4Model < GenericModel
end

class RemoteSX5Model < GenericModel
end

For module SX3, is the class Tasklist, Request and Dictionary can call
method_1-3?

module SX3
class Tasklist < RemoteSX3Model
end

class Request < RemoteSX3Model
end

class Dictionary < RemoteSX3Model
end
end

For module SX4, is the class Tasklist can only call method_2 defined in
GenericModel, but not method_1 and method_2?

module SX4
class Tasklist < RemoteSX4Model
def method_2
end
end
end

For module SX5, is the class Tasklist can only call method_2, and the
return value is 110?

module SX5
class Tasklist < RemoteSX5Model
def method_2(a=100)
end
end
end

Million thanks
Valentino


#7

(Without repeating the example definitions from the previous post)

For module SX3, is the class Tasklist, Request and Dictionary can call
method_1-3?

The inheritance hierarchy for Tasklist is:

Tasklist < RemoteSX3Model < GenericModel < ActiveRecord::Base

This class can use methods defined in Tasklist (its self),
RemoteSX3Model, GenericModel, and ActiveRecord::Base. If the same method
is defined in more than one of these classes, Tasklist will use the
“closest” definition it finds, tracing from Tasklist to
ActiveRecord::Base. The same logic holds for Request, and Dictionary.

For module SX4, is the class Tasklist can only call method_2 defined in
GenericModel, but not method_1 and method_2?

Nope, Tasklist from SX4 will use its “method_2” (which takes no
parameters), but method_1 and method_3 are still available via the
Tasklist < RemoteSX4 < GenericModel path.

For module SX5, is the class Tasklist can only call method_2, and the
return value is 110?

Tasklist from SX5 can still employ method_1 and method_3, but will use
its definition of method_2, with a different default for a.


#8

Thanks for your reply

Refer to my module. Each module inherit from difference class.

if I use A general class, GeneralTasklist. i.e.
class GeneralTasklist < ActiveRecord::Base
def method_1
end
def method_2
end
end

How can I preserve the super class as RemoteSX3Model…and so on?
Because I have to use the following code to establish connection to
difference data servers.
RemoteSX3Model.establish_connection sx3_hash
RemoteSX4Model.establish_connection sx4_hash
RemoteSX5Model.establish_connection sx5_hash

Any other better solution??

module SX3
class Tasklist < RemoteSX3Model
end
end

module SX4
class Tasklist < RemoteSX4Model
end
end

module SX5
class Tasklist < RemoteSX5Model
end
end

Thanks again
Valentino


#9

Many thanks to Ar Chron clear explanation. I think I got the concept of
abstract class now.

But how about if I have more than one Generic Class?

class Request
set_table_name “request”
set_primary_key “column_a”
def method_1a
end
end

class Tasklist
set_table_name “tasklist”
def method_1b
end
end

and so on…

Each module SX3, SX4, SX5 will have these classes. How do I implement
this?

Sorry that I am inexperience to OO and I got so many dummy question.

Thanks for your help. You’ve been really helpful.
Valentino


#10

you can implement as many classes as you like. if you have something
that is common to all of your Tasklist-classes you can of course
create class GenericTasklist that holds the common code and form which
Tasklist inherits.

you should take a look into a book that explains OOP though. without
that knowledge, you will get stuck over and over again.


#11

Valentino L. wrote:

Each module SX3, SX4, SX5 will have these classes. How do I implement
this?

Hmm… why the modules?

Could you address the connection issue with just

class RemoteSX3Model
self.establish_connection sx3_hash
end

or is there more to the modules than we’ve seen?

But MaD’s correct, taking time to read through something on OO design
and programming would be a good investment for you. First generic OOP,
then take a look at Ruby, and how it handles OO.


#12

Hmm… why the modules?

Actually, I am writing some scripts to monitor several data server. For
example, there are 10 data servers
SX1
SX2

SX10

Each data server has it own table schema, some table shared same schema.
So, I use 10 modules to define the model.

For some case, SX9 have relation to SX1.

module SX9
class Patient < RemoteSX9Model
set_table_name “patient”
set_primary_key “pat_encounter”
validate_present_of …

has_many :requests, :class_name => "SX1::Request", :foreign_key => 

“req_encounter_group”
end
end

I can write some script to require ‘my_model’, such that I can make
multiple AR connections to manipulate the data.
i.e.
require ‘my_model’
RemoteSX1Model.establish_connection sx1_hash

RemoteSX9Model.establish_connection sx9_hash
a = SX1::Tasklist.find(…)
b = SX2::Tasklist.find(…)
c = SX9::Patient.find(…)

But I don’t know how to implement my_model if I have several generic
class.

class GenericRequest
set_table_name “request”
set_primary_key “column_a”
def method_1a
end
end

class GenericTasklist
set_table_name “tasklist”
def method_1b
end
end

such that in my module can do something like…
module SX1
class Tasklist < RemoteSX1Model
# inherit all the stuff from class GenericTasklist
end
class Request < RemoteSX1Model
# inherit all the stuff from class GenericRequest
end
class OtherModel < RemoteSX1Model
end
end

module SX2
class Tasklist < RemoteSX2Model
# inherit all the stuff from class GenericTasklist
end
class Request < RemoteSX2Model
# inherit all the stuff from class GenericRequest
end
class OtherModel < RemoteSX2Model
end
end

I think the class Tasklist cannot inherit from GenericTasklist
directly…because I will not be able to work for later
RemoteSX?Model.establish_connection.

I want my_model to be DRY…So, I am finding way to factoring it.

Once again, thank you very much for your kind assistance. I will make a
lot of effort in OOP.

Thanks again
Valentino.