2011-03-09 18 views
11

Estoy tratando de dividir un modelo grande en varios archivos para la organización lógica. Así que tengo dos archivos:División de una clase en varios archivos en Ruby on Rails

model1.rb

class Model1 < ActiveRecord::Base 
    before_destroy :destroying 
    has_many :things, :dependent=>:destroy 

    def method1 
    ... 
    end 
    def method2 
    ... 
    end 

end 
require 'model1_section1' 

model1_section1.rb

class Model1 
    def method3 
    ... 
    end 
    def self.class_method4 
    ... 
    end 
end 

pero cuando las cargas de aplicaciones, y hay una llamada a Model1.class_method4, me sale:

undefined method `class_method4' for #<Class:0x92534d0> 

también he probado esto para el requerir:

require File.join(File.dirname(__FILE__), 'model1_section1') 

¿Qué estoy haciendo mal aquí?

+4

@Kaleb Brasee se supone que sea útil? ¿Estás reaccionando a los nombres de clases y métodos (completamente fabricados) o hay una razón legítima más allá de eso para un comentario sarcástico fuera del tema? – ilasno

+1

http://en.wikipedia.org/wiki/Code_smell –

+3

Solo busco ayuda con la sintaxis/estructura del lenguaje aquí, no refactorización u optimización, y ciertamente no para la eliminación técnica de términos. _Esto no es código real_, por supuesto huele. – ilasno

Respuesta

8

Sé que estoy respondiendo esto un poco tarde, pero acabo de hacer esto en una de mis aplicaciones, así que pensé en publicar la solución que utilicé.

de dejar que esto era mi modelo:

class Model1 < ActiveRecord::Base 

    # Stuff you'd like to keep in here 
    before_destroy :destroying 
    has_many :things, :dependent => :destroy 

    def method1 
    end 
    def method2 
    end 

    # Stuff you'd like to extract 
    before_create :to_creation_stuff 
    scope :really_great_ones, #... 

    def method3 
    end 
    def method4 
    end 
end 

Usted puede refactorizar a:

# app/models/model1.rb 
require 'app/models/model1_mixins/extra_stuff' 
class Model1 < ActiveRecord::Base 

    include Model1Mixins::ExtraStuff 

    # Stuff you'd like to keep in here 
    before_destroy :destroying 
    has_many :things, :dependent => :destroy 

    def method1 
    end 
    def method2 
    end 
end 

y:

# app/models/model1_mixins/extra_stuff.rb 
module Model1Mixins::ExtraStuff 

    extend ActiveSupport::Concern 

    included do 
    before_create :to_creation_stuff 
    scope :really_great_ones, #... 
    end 

    def method3 
    end 
    def method4 
    end 
end 

Funciona perfectamente gracias a la limpieza extra que ActiveSupport::Concern da tú. Espero que esto resuelva esta vieja pregunta.

+0

Creo que el modelo debería ser el módulo – stackOverlord

+1

¿Esto funcionó para usted con los métodos de clase? Todavía no funciona para mí cuando lo hago def self.method3 en el módulo. – stackOverlord

+1

@stackOverlord ¿Lo hiciste funcionar con métodos de clase? – baash05

1

Hay una gema aseada llamada modularity que hará exactamente lo que usted quiere.

Una buena guía sobre cómo dividirlos correctamente está en gem-session.

+0

Gracias, lo aprecié, lo había visto pero esperaba poder hacerlo con el idioma en sí y sin gemas ni complementos. – ilasno

1

Si literalmente está tratando de dividir una clase en dos archivos (similar a las clases parciales en C#), no sé de una manera fácil de hacer Ruby para hacer eso.

Sin embargo, una forma común de terminar con las clases que tienen una funcionalidad considerable (incluyendo una gran cantidad de métodos) es a través de Mixins. Los módulos se pueden combinar en una clase y sus métodos se incluyen literalmente en la clase.

2

Sé que llego tarde en esto, pero al tratar de averiguar cómo hacerlo yo mismo tropecé con esta pregunta.

creo que la respuesta a por qué la reapertura de clase no está funcionando como se esperaba en el código de ejemplo es que la clase se define inicialmente como:

(en model1.rb)

class Model1 < ActiveRecord::Base 

y luego un re-abierta como: (en model1_section1.rb)

class Model1 

es decir, la segunda definición carece de la clase heredada.

He utilizado por separado.rb para dividir mis enormes modelos, y me han funcionado muy bien. Aunque admito que solía incluir y algo más parecido a esto:

(en workcase.rb)

class Workcase < ActiveRecord::Base 
    include AuthorizationsWorkcase 
    include WorkcaseMakePublic 
    include WorkcasePostActions 

    after_create :set_post_create_attributes 
    # associations, etc 

    # rest of my core model definition 
    end 

(en workcase_make_public.rb)

module WorkcaseMakePublic 
    def alt_url_subject 
     self.subject.gsub(/[^a-zA-Z0-9]/, '_').downcase 
    end 
    # more object definitions 
    end 

    class Workcase < ActiveRecord::Base 
    def self.get_my_stuff 
     do_something_non_instance_related 
    end 
    # more class definitions 
    end 

Esto me ha permitido incorporar métodos de clase y objeto en cada archivo .rb incluido. La única advertencia (ya que no usé la extensión inquietudes) era que el acceso a las constantes de clase desde los métodos de objeto de módulo requería que la constante se calificara con el nombre de clase (como Workcase :: SOME_CONST) en lugar de directamente como sería permisible si se llama en el archivo primario.

En general, este enfoque parecía requerir la menor cantidad de reescritura de mi código para convertir las cosas en bloques de código manejables.

Tal vez esta no es la verdadera 'forma de Rails', pero parece funcionar muy bien en mi situación particular.