How do you solve FixtureClassNotFound: No class attached to find - ruby-on-rails-3

When running my tests I get this error:
FixtureClassNotFound: No class attached to find
What causes this error and how to fix it?

Most likely this happens because a custom table name is used for a Model (using the set_table_name) or the model is in a module.
To solve, you need to add a set_fixture_class line in the test_helper.rb before the fixtures :all line:
class ActiveSupport::TestCase
self.use_transactional_fixtures = true
.
.
.
set_fixture_class my_table_name: MyModule::MyClass
fixtures :all
end
In this case the fixtures file should be called my_table_name.yml

NOTE: It would be helpful if you included the stack trace and the full error message.
In your test/test_helper.rb class, there is a line like
fixtures :all
This tells the framework to look in the directory test/fixtures and try to load each of the YAML files that it sees there and then save them to the DB. So my hunch is that you have a file in there that does not have class in app/models with the singularized name. In other words, if there is a file test/fixtures/posts.yml, then when you run your tests, the framework will look for a class named Post to load your data in.
So the first thing I would do is check to see if you have a fixture file that is not associated with one of your model classes (maybe you deleted a model but forgot to delete the fixture?)
If that doesn't work, try changing the line in your test helper to explicitly load the fixtures you need. So if you only want to load fixtures for an object named Post and an object named User, you will change:
fixtures :all
to
fixtures :posts, :users
in test_helper.rb and you should see the error go away (although other errors may now appear because your fixtures are not loaded.0

In the Event that the Class is an irregular class in terms of naming such as fish, sms
it could have been created by using the --force-plural flag
i.e
rails g model sms --force-plural
in that case you would set up an inflection which is set up under
config/initializers/inflections.rb
an example of such is this
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.plural /^(ox)$/i, '\1en'
inflect.singular /^(ox)en/i, '\1'
inflect.irregular 'person', 'people'
inflect.uncountable %w( fish sheep )
end
In this way the class can be recognized as you declared it

I got this error when I made a mistake generating some scaffold code. I used a plural model name, and that just confused the fixture loading, I guess. Regenerating the scaffold with a singular model name fixed the problem.

Related

Create module that throws exception in rails if conditions not met on load

I have a module in a rails 3 app that's included in multiple models. I want to force the app to fail to load if any of the models do not have an appropriate attr_accessor defined. Due to the architecture of the app it's not feasible to include the attr_accessors as a part of the module to be added to the class during the self.included function.
Here's what I've tried at present:
module MyModule
def included(base)
raise "Accessor 'enabled' is not defined in #{base.name}" unless base.method_defined? :enabled
end
end
class MyModel < ActiveModel::Base
# attr_accessor :enabled
attr_accessor :attr_1, :attr_2
include MyModule
end
In this instance, I'd want the app to fail to load because MyModel does not have an enabled method.
Your code should work - on production. In development the classes in app/models are only loaded if used unless you set
config.cache_classes = true
in config/environments/development.rb. But that makes developing really no fun, since you have to restart your webserver every change to test your changes. On rails 4 you have another configuration option
config.eager_load = true
So you do not need to cache classes to get the behaviour to have loaded every class on starting your server / console.
If it's really only attribute accessor you check, it's better just to set it on including the module. And if you work with modules in rails: have a look into http://www.rubydoc.info/docs/rails/3.2.8/ActiveSupport/Concern
There you can just call attr_accessor :enabled in the included block.

Troubles with Rails 3 and classes in nested directories

I have a rails project that I inherited. I'm working on upgrading it from rails 2 to rails 3. I'm at 3.0.15 right now, working my way up to 3.2. In the app directory there is a support folder with classes in it. Like so:
app/
support/
sweeper.rb
grouped_list/
item.rb
list.rb
item.rb looks like this:
class Support::GroupedList::Item
attr_accessor :name, :count, :link
def initialize(name, count, link)
#name = name
#count = count
#link = link
end
end
In one of the controllers the Items class is called like this:
Support::GroupedList::Item.new name, count, link
when I try and load a page I get the error:
uninitialized constant ApplicationController::Support
My first thought was that the paths where not in the autoload so I added
config.autoload_paths += %W(#{config.root}/app/support #{config.root}/app/support/grouped_list)
in my application.rb but that didn't change anything. After looking around for examples I found that people where creating empty module in their directory structure so I created a support.rb file in the support folder that looks like this:
module Support
end
Now my error changes to
uninitialized constant Support::GroupedList
Hey! That's interesting, I don't understand why it changed but its progress right? So I add a grouped_list.rb file in the grouped_list directory. It looks like this:
module Support::GroupedList
end
But then I get
Expected ***/app/support/grouped_list/grouped_list.rb to define GroupedList
Ugh! so I change it to:
module GroupedList
end
But then I'm back to:
uninitialized constant Support::GroupedList
So clearly there is some fundamental knowledge I'm missing about loading classes in modules. This structure worked in rails 2 but breaks in rails 3.0.15. I'd really like to understand so if anyone can help me out I'd really appreciate it.
class GroupedList::Item
attr_accessor :name, :count, :link
def initialize(name, count, link)
#name = name
#count = count
#link = link
end
end
This should work. Then in your controller:
GroupedList::Item.new name, count, link
Also remember to restart your rails server/console, after you make these changes.

Rails 3 - table name being pulled from PARENT model?! (ApplicationModel)

I just inherited a project. That project has upgraded to Rails3, and is lacking an application_model. I'm trying to implement it. I've extended all other models from it. The problem is that for some reason, when trying to determine the table name, ActiveRecord is using ApplicationModel, rather than the child model so I'm getting:
Table "your_db.application_models" doesn't exist.
Any thoughts? Why would it be pulling from the app model? Any idea on how to fix?
Thanks!
Apparently, here's the issue (according to what I found on this page: rails - root model or application model):
ActiveRecord normally detects when you subclass an already subclassed ActiveRecord::Base and uses this to turn STI (single table inheritance) on.
ApplicationModel will be an actual model that is expected to have a table in your database. This can lead to problems down the line.
To fix these two problems, you have to set abstract_class to true for ActiveRecord to properly function.
class ApplicationModel < ActiveRecord::Base
self.abstract_class = true
end
In contrast to an abstract ActionController, abstract_class must set to true which means the developer must know they cannot remove this line from ApplicationModel. With ApplicationController you can do pretty much whatever you want to it.

Rail3 | How to create standard route/action for ALL controllers?

Well, DRY! So i thought it should be easy to add a new action (like the existing new, edit) to all my controllers (in my case copy). But how do you setup a new route for ALL controllers?
Without going in to 'loops' (i.e. %w().each ...) inside the routes.rb ?
I mean, we want DRY right? So you don't want copy your action inside the routes file for each resource. I guess you should be able to extend the default actions/routes (index, new, edit,etc.) easy?
Thanks!
AFIK no way to do this by default. You could monkey-patch resources to include this functionality:
https://github.com/rails/rails/blob/b229bc70e50ec0887c5bb3aaaa9c6ee8af054026/actionpack/lib/action_dispatch/routing/mapper.rb#L982
...but my hunch is you would be better off re-considering whether this functionality can be created another way, since what you want to do is "off the Rails".
One option is create a CloneController#new that accepts a model and id and creates a clone. This seems like it would be drier, and wouldn't require you to pepper a gazillion "clone_article" "clone_blog" "clone_user" paths all over the place.
Obviously you would want to carefully white-list the models/ids that can be passed in.
Looking through the source there isn't a way to add to the default actions for a resource.
But, as #juwiley says, the methods resources :item is just a shortcut for creating a load of member and collection methods.
All you need to do is something like this
class ActionDispatch::Routing::Mapper
def resources_with_copy(*resources, &block)
block_with_copy = lambda do
block.call
member do
post :copy
end
end
resources(*resources, &block_with_copy)
end
end
Then in your routes.rb just say
resources_with_copy :items
resources_with_copy :posts do
member do
post :share
end
end
...

Rails 3 namespacing requires model to be defined twice?

I'm pulling my hair out trying to understand namespacing in Rails 3. I've tried following a few different tutorials, and the only way I can get my models to work is if I define my model in both the base directory and my namespace directory.
If I only define the model in the namespace directory it expects it to define both Model and Namespace::Model, as below:
LoadError (Expected .../app/models/plugins/chat.rb to define Chat):
or
LoadError (Expected .../app/models/plugins/chat.rb to define Plugins::Chat):
I'm sure I'm missing something obvious, but I could really use a pointer in the right direction.
Here are the relevant excerpts.
/models/plugins/chat.rb
class Plugins::Chat
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
...
end
/controllers/plugins/chats_controller.rb
class Plugins::ChatsController < Plugins::ApplicationController
load_and_authorize_resource
...
end
/config/routes.rb
namespace :plugins do
resources :chats
end
/config/application.rb
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Edit
This is some kind of bad interaction with CanCan, the gem we're using for permissions. The line load_and_authorize_resource is somehow at fault. Will keep digging...
I noticed a reference to load_and_authorize_resource in your controller. This method is used by the CanCan gem to create an instance of your model and then test if the user has access to it. If you are using a namespaced model you will need to specify the class:
class Plugins::ChatsController < Plugins::ApplicationController
load_and_authorize_resource :class "Plugins::Chat"
...
end
It sounds like at some point you're referencing the Chat constant \by itself before it's loaded. Rails then tries to find that by looking at models/chat.rb, can't find it, and complains. Check your constant usage (the backtrace should tell you where it's being invoked from), and clean it up, and Rails should be less complain-y.