How can I get model names from inside my app? - ruby-on-rails

I have a bunch of models in a sub-directory that inherit from a model in the models root directory. I want to be able to set a class variable in another model that lists each inherited model class.
i.e
##groups = sub_models.map do { |model| model.class.to_s }
Not sure how to get at this info though...

There is a full answer here. Basically, you can either troll through the files or monkey-patch Class (or ActiveRecord). Those are two ways to go, at least.
Edit: On second thought, Rails won't load your Models until necessary, so while the "files" way seems weak, it's probably your only option (unless you want to do something in your models themselves).

In Rails, in production env this should work
Object.subclasses_of ClassInModelDir
You have to load the files manually If Rails.env.development?

You will not be able to do this unless you preload your descendant models. This is the reason why it is prudent to reengineer your code to use Class#ancestors instead of descendants (also descendants are not a core Ruby feature).

Related

How to manually load all classes inside rails application?

How to load & get collection of all active-record models used inside rails app.
It should give classes from gems, plugins as well as subclasses having active-record base in parent hierarchy.
ActiveRecord::Base.descendants.collect(&:name)
gives me list but its only after all classes gets loaded.
Is there any way to load all classes inside rails app manually ?
The problem with Ruby is that "all classes" is a somewhat difficult thing to ascertain. Some of them may be generated dynamically and conditionally.
Sometimes you can just load what's present in app/models:
Dir.glob(File.expand_path("app/models/*.rb", Rails.root)).each do |model_file|
require model_file
end
If there's other locations that may contain models you'll need to include those, too.
You might have dependencies, though, and that can preclude model A from loading before model B. This is why the autoloader is used by default and things just aren't loaded in.
The only reliable way to get them all loaded is to somehow exercise them all at least once.
Getting model list based upon db tables -
ActiveRecord::Base.connection.tables.collect{|t| t.singularize.camelize.constantize rescue nil}.compact

Rails: Tableless model that calls other models

I have a Rails app with a few model classes (e.g. Category, Subcategory, User, etc.). In order to implement a not-too-trivial filter functionality, I built a hierarchy of filter classes: FilterCategory, FilterSubcategory, etc., that derive from FilterBase. Each of them uses the appropriate "sister" model class (e.g. Category.find :all).
I quickly realized that I can't simply call the "sister" model class without using "require" first. However, I now suspect that using "require" is the main reason for two other problems I posted here and here, which probably mess up the class caching when config.cache_classes=false.
Is there another way for me to call these other models without requiring them?
I tried using the BaseWithoutTable plugin, but when I call the "sister model", I end up getting "Not a valid constant descriptor: nil", which occurs since Rails looks for "FilterCategory::Category" rather than "Category".
Any thoughts of the best way to do that?
I'm using Rails 2.3.8, Ruby 1.8.7.
Thanks,
Amit
I wonder if you want ::Category - getting Category from the top-level namespace rather than scoping it to FilterCategory?
If your models are in the app/models directory, you shouldn't need to explicitly require them - Rails already takes care of that.

how does one load a model with a custom name in to a controller

I'm trying to access a model for global system settings. It should be loaded in almost every controller. The problem is I can't find any help on getting rails to load the dam thing.
If this helps, the model is called Config and has two columns; 'key' and 'value'
I come from a background in PHP. I remember codeigniter could load models via.
$this->load->model('a_model_name');
The controllers I'm trying to load the model in do not have the same name as the model.
The problem here is actually the name of the model. Config is used by other Rails classes - see the list of reserved names on the Rails wiki
Rails autoloads classes when it needs them. So long as the class is in a file with the same name, and it's in one of the directories Rails looks for classes in, you just use the class as if it was loaded and Rails will load it automatically
You can add before_filter in ApplicationController:
before_filter :load_config
...
private
def load_config
something
end
By default all controllers in Rails inherits from ApplicationController, so all controllers will execute load_config method at the begining.
By the way I really like rails-settings gem/plugin for configuration. It is probably something that you need. And it loads data when it is needed, so you don't have to load config in each controller, but just when you need some value, then you just do:
Settings.key
and you get what you want.
Presumably, if you want to load a piece of information with a particular key you could use Config.find_by_key('the_key_you_want') to get the record in question.
I'm not sure that this would be the best way to handle your configuration, but it really depends on how your system needs to work.
EDIT:
Didn't see your update to the question before I posted my answer, seems like I misunderstood what you meant. Leaving this answer here in case it's useful, Gareth's answer seems like a fair answer.

Rails: Best practice for model dependency class locations?

I have a rails app moving along fairly well, but the fact that I'm doing this myself means that some poor sod is eventually going to see this and say, "What the hell were you thinking? Why did you put this here?!?!"
Where is that poor, sorry soul going to expect to see a series of classes that aren't used by anything but a single model class? Obviously, I could chuck it in the_model.rb along with class TheModel, but this may expand beyond the planned two classes...
I thought about lib, but it doesn't need to clutter everyone's view of the world....
Thank you.
My predecessor thanks you.
Leave them in the_model.rb until you need them in more than one place. If you refactor needlessly, you're not doing the simplest thing that could possibly work. You aren't gonna need it.
At that point, the general pattern is to create a directory for "concerns". See this weblog post by Jamis Buck or this one by Peter Marklund for more information.
In general: follow the Rails naming conventions when translating class names into filesystem locations. (that is: keep the class FooHelper::Bar in foo_helper/bar.rb)
You can make exceptions for small helper classes that are only used once and keep them in the same file as your model, but those should be exceptions. (but the converse is also true, don't create one-line thousands of single line files)
Use modules and class namespaces to your advantage. If you have a helper class that is only used by (and dependent on) your model, put them into the namespace of the model class:
class TheModel::HelperClass
end
the location in the file system would be app/models/the_model/helper_class.rb
And something that is not dependent on your model can probably still be namespaced
module Bar
class Foo
end
end
living in bar/foo.rb, of course
You should probably not be afraid to put things that are not models into lib -- that's what this directory is for
I'd say concerns, while useful, are not really the right way to go because that is a way to split a single class into multiple files and you don't seem to be doing that.

constant values in Rails

I have some data that I want to store somewhere in my Rails app because I use it for generating form fields, checking a submitted form to ensure its values are valid, etc. Basically, I want the data in one location because I make use of it in several places.
Previously, I was defining an initialize method in my controller and initializing instance variables within that method, e.g. #graph_types = ['bar', 'line']. This seemed a bad idea because that's really all initialize was being used for (initializing those values) and the instance variables could be changed later, which I don't want.
Now, I define constants outside of any method in my controller, right up at the top after my filters, and I freeze them, e.g. GraphTypes = ['bar', 'line'].freeze.
I didn't want to store such data in a config file because then I would have to keep track of an extra file, read in the file and parse it, etc. I didn't want to store this data in the database because that seems like overkill; I don't need to do any crazy LEFT OUTER JOIN-type queries combining available graph types with another of my constants, say Themes = ['Keynote', 'Odeo', '37 Signals', 'Rails Keynote'].freeze. I didn't want to store the data in environment.rb because this data only pertains to a particular controller.
Considering all this, am I going about this 'the Ruby way'?
For constants that don't really belong anywhere else I have a StaticData class.
class StaticData
GRAPH_TYPES = ['bar', 'line']
SOMETHING_ELSE = ['A', 'B']
end
Then I get at it with
StaticData::GRAPH_TYPES
The same answer I wrote previously to a similar question applies and posting as this answer still comes up in search results.
Putting a constant in the controller makes some sense as the constant pertains directly to it. Constants should otherwise be put in the dedicated initializer file: Rails.root/config/initializers/constants.rb.
As per the comment listed in application.rb:
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded
This is still valid as of Rails 3.
I believe what you are currently doing is fine; you said the data only pertains to one controller, and therefore that's where it belongs. If it was needed for multiple controllers, or if they were more complex than constant values, other approaches may make sense.
Yes, what you are doing is fine. It's more idiomatic Ruby to call your constant GRAPH_TYPES though.
Incidentally, I would avoid defining initialize in your controllers. Seems like it could lead to trouble.
I would agree some what with IDBD and paradisepete. Using constants in the model would be the best way to go so that the controller is skinny and the model fat. see Rails view tips
For example if you had a metrics controller linked to a metric model. In the metric model
class Metric < ActiveRecord::Base
GRAPHTYPES = ['bar', 'line']
Then in the view you could do something like
f.select :graph_type, Metric::GRAPHTYPES
If you are generating forms that are related to some resource then it will be good variant to store it in the models. You don't need to store it in DB because it can be simple class or instance variables/methods.
The same idea is for validation. If you are validating resources/model instances then it will be reasonable choice to store validation parameters inside model class.
Anyways, it will be much closer to the 'thick model and thin controller' pattern then any of the variants you mentioned.

Resources