Forum: Ruby on Rails Refactoring module

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.
Af3cecc8af253b5acd3c09c5b67c0074?d=identicon&s=25 Valentino Lun (on9west)
on 2009-03-17 12:28
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
80e4cb97cae5c8d745f72337d93fd8f2?d=identicon&s=25 MaD (Guest)
on 2009-03-17 12:51
(Received via mailing list)
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.
Af3cecc8af253b5acd3c09c5b67c0074?d=identicon&s=25 Valentino Lun (on9west)
on 2009-03-17 13:11
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
D188e591eac11021329b8821a5f954c7?d=identicon&s=25 Ar Chron (railsdog)
on 2009-03-17 14:39
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])
Af3cecc8af253b5acd3c09c5b67c0074?d=identicon&s=25 Valentino Lun (on9west)
on 2009-03-17 16:16
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
D188e591eac11021329b8821a5f954c7?d=identicon&s=25 Ar Chron (railsdog)
on 2009-03-17 17:00
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.
Af3cecc8af253b5acd3c09c5b67c0074?d=identicon&s=25 Valentino Lun (on9west)
on 2009-03-17 17:24
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
D188e591eac11021329b8821a5f954c7?d=identicon&s=25 Ar Chron (railsdog)
on 2009-03-17 18:14
(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.
Af3cecc8af253b5acd3c09c5b67c0074?d=identicon&s=25 Valentino Lun (on9west)
on 2009-03-18 02:53
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
80e4cb97cae5c8d745f72337d93fd8f2?d=identicon&s=25 MaD (Guest)
on 2009-03-18 08:05
(Received via mailing list)
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.
D188e591eac11021329b8821a5f954c7?d=identicon&s=25 Ar Chron (railsdog)
on 2009-03-18 15:01
Valentino Lun 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.
Af3cecc8af253b5acd3c09c5b67c0074?d=identicon&s=25 Valentino Lun (on9west)
on 2009-03-18 16:28
> 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.
This topic is locked and can not be replied to.