eladmeidar / rails_indexes

A rake task to track down missing database indexes. does not assume that all foreign keys end with the convention of _id.
http://blog.eizesus.com/2009/9/find-where-to-index-your-tables-on-a-rails-app/
MIT License
489 stars 35 forks source link

uninitialized constant <MODEL> #2

Closed alg closed 15 years ago

alg commented 15 years ago

If there's a plugin with an unused model in the app, like Account that comes with Authlogic, the tool finds it through file scan, but Rails doesn't know it as it never loaded into memory. An attempt to constantize in indexer.rb:122 (table_name = model_name.constantize.table_name) fails with an exception.

Hope it helps.

eladmeidar commented 15 years ago

mmm, since i can't distinct using a simple file scan between loaded/not loaded libs/classes in the vendor tree, i guess i'll just wrap it around a rescue block and notify the user, what do you think?

alg commented 15 years ago

Sounds right. I would refactor that whole part out into a separate method as it's getting busy, but basically it's the way to go. Alternatively, you could peek how Rails looks for loaded classes itself to have a clean check without catching exceptions. Here's a bit of a stack trace to give you idea where to look if you want to take this path:

uninitialized constant Account /activesupport-2.3.2/lib/active_support/dependencies.rb:443:in load_missing_constant' /activesupport-2.3.2/lib/active_support/dependencies.rb:80:inconst_missing' /activesupport-2.3.2/lib/active_support/dependencies.rb:92:in const_missing' /activesupport-2.3.2/lib/active_support/inflector.rb:361:inconstantize' /activesupport-2.3.2/lib/active_support/inflector.rb:360:in each' /activesupport-2.3.2/lib/active_support/inflector.rb:360:inconstantize' /activesupport-2.3.2/lib/active_support/core_ext/string/inflections.rb:162:in constantize' /rails_indexes/tasks/../lib/indexer.rb:122:inscan_finds'

Thanks for a great idea and tool!

eladmeidar commented 15 years ago

Thanks a bunch, i will check into it. Well, in Production all the classes are loaded anyway, and since you should really run those tasks only on production environment, i guess that's basically a cosmetic fix rather than a real issue. I will push in some kind of a work-through soon.

Thanks again!

alg commented 15 years ago

Don't mention it. Not sure why do you say in Production the greater set of classes will be loaded. There are many cases when the set of classes loaded depends on the particular configuration (config/environements/*.rb and any run-time initialization) of the environment and gems / plugins, and to me, it's the only case when the Development environment can differ from the Production. To load the complete environment in your rake task, you place a dependence on :environment, but that's what you do.

Am I missing something?

eladmeidar commented 15 years ago

What you refer to (i think) is the new lazy-loading approach by rails, that classes (+models) load only when they are required to.

The part in question is where i part "Model.find*" statements and try to split it into fields. For some reason, in your application, my regexp matched a line that says something like "Account.find", i assume that any class name followed by a #find method, is an AR::Base decedent, and therefore use #constantize. Can you check the context of any line you might have that contain that pattern? (Account.find...), and even more important, is Account < ActiveRecord::Base ?

alg commented 15 years ago

Sure, I know exactly where and why it happens. That's what I was trying to tell. In one of my projects I use ResourceController plugin (git://github.com/giraffesoft/resource_controller.git). It has tests with a sample model Account and a few controllers that do Account.find in them, all sitting inside the /vendor/plugins/resource_controller/test folder. The classes from this test environment aren't loaded in dev, production or any other environment except when the plugins are tested. That's why it wouldn't be the right thing to take them into account. I believe it makes a perfect sense to exclude any RAILS_ROOT/(spec|test|vendor/plugin/[^/]+/(spec|test|vendor)) directories from scan.

Is there anything else I can do to help?

eladmeidar commented 15 years ago

well, i just pushed a version that excludes test/ resident *.rb files. pull and try again when you can... and thanks for your help.

alg commented 15 years ago

Worked like charm. Great job!

I tried to read code to check a couple of edge cases, but got lost. :) I'll just list my ideas here, so see if you can make use of them:

Again, I couldn't figure if you have this covered. Good luck!

eladmeidar commented 15 years ago

well, that's the point where i think it would make more sense to leave it to the developer/DBA to decide... i don't think that adding features like that (consideration in MySQL features) is something that i need to waste my time on. it's something that should be added by the person responsible of the DB maintenance. Anyway, i was thinking of adding something that will find more indexes inside :conditions, scopes and maybe validates_uniqueness_of ...

eladmeidar commented 15 years ago

Fixed?

alg commented 15 years ago

Haven't followed the progress since then. Sorry, can't provide more info at the moment.

eladmeidar commented 15 years ago

Oh, that question mark slipped in :)

alg commented 15 years ago

Ha, thanks then! :)