I have the following (newbie) problem: in my 'app/models' folder is a
class (User) with more then 1000 lines of code. I want to split the
model in different files into a subfolder (a separat file for
validations, filter, additional methods, ...). How can I do this as
simple as possible? Can I extend the class directly (see below) or is it
necessary to include modules (the files can contain class and instance
methods)?
e.g.
# app/models/user.rb
def User
# elementary code
end
# app/models/user/validations.rb
def User
# validations
end
# app/models/user/attributes.rb
def User
# additional attributes
end
...
The require 'user/validations' etc. does not work for me (?). It runs
well in the console but not for the rails application (the class content
is only found at the first request – I extended the load_path with
config.load_paths << "#{RAILS_ROOT}/app/models/user" in the
environment.rb).
I have the following (newbie) problem: in my 'app/models' folder is a
class (User) with more then 1000 lines of code. I want to split the
model in different files into a subfolder (a separat file for
validations, filter, additional methods, ...). How can I do this as
simple as possible? Can I extend the class directly (see below) or is it
necessary to include modules (the files can contain class and instance
methods)?
e.g.
# app/models/user.rb
def User
# elementary code
end
# app/models/user/validations.rb
def User
# validations
end
# app/models/user/attributes.rb
def User
# additional attributes
end
...
The require 'user/validations' etc. does not work for me (?). It runs
well in the console but not for the rails application (the class content
is only found at the first request – I extended the load_path with
config.load_paths << "#{RAILS_ROOT}/app/models/user" in the
environment.rb).
You should use require_dependency rather than require. Also I wouldn't
add models/user to the load path: if you follow this approach with
several models then doing just require 'validations' could pick any of
them (depending on the order in which you add those folders to the
load path).
Use modules, which are included not required. This is much cleaner than
overriding the class as you are doing above. You might find that you
can factor out some functionality such that other classes can use it as
well. Put the modules in lib and keep your models folder with just the
class definitions.
I have the following (newbie) problem: in my 'app/models' folder is a
class (User) with more then 1000 lines of code. I want to split the
model in different files into a subfolder (a separat file for
validations, filter, additional methods, ...). How can I do this as
simple as possible? Can I extend the class directly (see below)
Yes, but then Rails' autoloader may not find all the pieces unless you
explicitly requre them.
or is it
necessary to include modules (the files can contain class and instance
methods)?
It would be better to include modules. That also means you can reuse
the modules in other classes.
But why the heck do you have 1000 LOC in your model to begin with?
Smells like something more fundamental is wrong.
Use modules, which are included not required. This is much cleaner than
overriding the class as you are doing above. You might find that you
can factor out some functionality such that other classes can use it as
well. Put the modules in lib and keep your models folder with just the
class definitions.
I am trying to do just that. I have a large model with lots of
attributes - I am not trying to factor out code to share between models,
I just want to break the model up into a few files for sanity's sake.
But if I, for example, do this:
class Project < ActiveRecord::Base
include ProjectValidations
end
module ProjectValidations
validates_presence_of :project_name
end
then I get the following error:
undefined method `validates_presence_of' for ProjectValidations:Module
You want to do this, as its the class that needs to evaluate this
method, not the module.
module ProjectValidations
def self.included(base)
base.send :validates_presence_of, :project_name
end
end
Thanks for the pointer, Rob. But I've got a lot more of these than the
simple use case shows, and I'd have to modify a lot of code to
modularize things that way. After some more experimentation, I've come
up with this:
def self.included(base)
base.class_eval {
validates_presence_of :project_name
...
}
end
This way I can just cut/paste all of the validations from the original
model class file into the base.class_eval block; much less mucking
around.