I have a project with class Matrix < ActiveRecord::Base, and I'm hitting situations where Matrix.where is crashing because it's trying to access the Matrix < Enumerable class from ruby.
Is there a way to specify which Matrix I want, like ActiveRecord::Base::Matrix?
I know I could rename the model, but it would be a pain (old spaghetti project)
Rename it or be forever battling Ruby core. You can't get around this. Rails chose to put model names in the root namespace as it's very convenient, but leads to problems when that conflicts with either Rails or Ruby.
Solutions:
Try and force-load your model before the Ruby Matrix has a chance to usurp it
This may have unintended consequences (like a crash) should require 'matrix' show up somewhere
This could also mess up gems that expect Matrix to be the Ruby thing and not your random model
Move it into a namespace like MyProject::Matrix
Rename it to something dumb like MMatrix as a reminder that this name was a bad idea from the outset
The good news is that if this is a fairly unique string, then a global replace of Matrix to the alternate name is probably not going to be that bad.
Related
I am only looking for answers from senior/more experienced Ruby/Rails developers on this one, since I think this is a bit more advanced of a question.
I have a gem I am working on that adds some behavior to AR models. I have to test it for a lot of different associations (has_many, habtm, has_one etc), and I also have to test behavior when different options are passed for the associations (e.g. :foreign_key). Now with all these different models, I can use the same table in the database because the fields themselves do not need to change, only behavior specified through has_many, belongs_to and so on.
Keep in mind there are a lot of different options, so the number of models is quite large.
First I don't think it would be bad practice to have the definition of the models next to / in the test itself, for readability purposes (if I have multiple tests that use the same model then I would group them together and use the before method). So this is one of my goals, and you can comment on this if you don't agree.
The second thing I am not sure of is I wanted to keep the simple/same name of the model in all the tests, for example "Task", instead of TaskWithManySubtasksAndForeignKey or something ugly like that. The problem is there are so many models it's hard to come up with meaningful and simple names. I'm not quite sure about this - using the same name, since it's a constant, is a little problematic. I have a solution with a proxy class but I don't think this is the optimal solution. I was considering using variables (with the let method) like "taskModel", but it seemed a little verbose and unusual.
One other option that comes to mind, but I am not sure is possible to do easily, is to remove an existing association and then define a new one. So e.g. add a has_many and then remove it, add a habtm...
How would you go about doing this?
Defining unique models in the spec files is not necessarily a bad idea since it makes it easy to see exactly how each model is defined. The obvious problem with this approach is if you want to reuse the models in other test files. The Rails approach to this is to define all the models in separate files and then just require them in the tests that need it.
I think it really just depends on how many models you have and how much you want to reuse. In one of my gems, I took the approach of defining the models in the spec file, in another gem, I defined them in the spec helper, and in yet another I took the Rails approach and used a separate directory for them. If you asked me which one I preferred, I'd probably go with the spec that also contains the models because it's all in one place. Definitely a subjective problem though.
Another approach I've taken on occasion is to create an anonymous class that's guaranteed to only be around for the life of that test:
describe 'my test' do
let(:my_class) do
Class.new(Task) do
has_many :things
belongs_to :something_else
end
end
it 'should have many things' do
my_class.should have(100).things
end
end
I'm using Rails 3.1 on a project, and bundler has added quite a few gems that I do not really know the contents of that well.
For some reason in development mode (probably because it keeps unloading classes), I intermittently run into an ActiveRecord::AssociationTypeMismatch. That look like this:
Character(#31360520) expected, got Character(#23815500)
I believe that one of the gems has defined a class "Character" and it's conflicting with my ActiveRecord "Character" model. I'm having trouble searching down the source of this problem as it comes up with a bunch of generic results, and I'm not sure what those numbers are called by the Ruby community (class id?).
So a few questions that I'd love help with:
what is that number in the parens after the class name?
How can I look up where that class is from (in which gem) based on the id reported in the exception?
What is the best practice here for commonly named ActiveRecord models? Should I be namespacing my models, or is the blame more with the author of the gem?
i'm sort of a noob, so don't consider all i say as an established truth - but i think i might help.
question 1
Not sure, but i suspect those numbers are object_ids of the expected Class. In ruby, classes are objects too (singleton objects, though), so they have an object_id as would any other object (you can call object_id on any object to get its unique id). If you want to get an Hash of every classes loaded in your environment along with their id, you can try something like this in the console :
all_classes = ObjectSpace.each_object.select {|o| o.class == Class}
with_ids = Hash[ all_classes.map {|c| [c,c.object_id] } ]
question 2
In the console, all classes are displayed showing their full namespace path, so you should be able with the above script to distinguish your two Character classes if they belong to a different namespace.
If the namespace is identical though, the problem may become hairy because one of your class definition will override the other, depending on the load order. I would not be surprised if using ri in your shell would help you to find the culprit gem in this case.
question 3
I would say : avoid vague, too common names for your models ; but in this case, i'd say the gem is to blame, because someone providing a gem should be really careful not to pollute the namespace, especially if it pollutes the ActiveRecord::Base namespace.
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.
I'm writing a rails application, and I need to name one of my model Test, and inside that model I need a class attribute - when I tried the first one, I couldn't run any UT since Test ceased to be a module - so I ranamed to Tst. I haven't even tried naming a column class - I went with clss. What names would you use? Are there any conventions known amongs RoR developers for such situations?
I haven't seen anything for Test but class is typically changed to klass.
Ruby and Rails have several different objects part of a standard library. You cannot use an already-defined class name as name for your models.
For instance, you cannot call a model Thread or Object because Ruby already defines a Thread and Object class.
Likewise, Ruby has a library called Test::Unit so you can't use the Test namespace as model name.
There isn't a real full list of reserve objects because it really depends on your current environment. However, in order to successfully use Rails, you should at least have a basic Ruby knowledge so that you know the names of the most common standard library classes.
I've run up against this a few times (writing educational software--where you regularly want to model 'tests' :-). Depends exactly what you're modeling I suppose, but I usually opt for 'quiz' to avoid conflicts. I'd love to hear a better solution, since I find 'quizzes' an awkward plural.
Like dj2 said, class is usually done as 'klass'.
Please check the following page for Rails reserved words: http://reservedwords.herokuapp.com/ None of these words should be used as class or attribute name.
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.