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.
Related
I've been using ActiveAdmin eager loading in almost all my models. For instance, this works great for my Coach model:
app/admin/coaches.rb
ActiveAdmin.register Coach do
controller do
def scoped_collection
Coach.includes(:addresses, :user, :sport, {:user => :user_metric})
end
end
end
However, when I recently tried this same thing with my Search model (which I use to record searches users have done):
app/admin/searches.rb
ActiveAdmin.register Search do
controller do
def scoped_collection
Search.includes(:sport)
end
end
end
I get the following error when I try to visit /admin/searches
NoMethodError in Admin::SearchesController#index
undefined method `includes' for
ActiveAdmin::ResourceController::Collection::Search:Module
app/admin/searches.rb:5:in `scoped_collection'
I believe what may be happening here is the constant Search I'm using in my eager loading is referring to some internal ActiveAdmin module rather than my ActiveRecord model. Is there a way to prevent this name collision? Maybe ActiveRecord::Search (or something like that)? Or possibly something else entirely is going on here?
The constant Search works everywhere else on the site, and the ActiveAdmin searches page worked fine before trying to implement eager loading.
As #Fivell recommended, try ::Search instead of Search.
It looks like your reference to Search in app/admin/searches.rb:5 is actually referencing ActiveAdmin::ResourceController::Collection::Search.
If that doesn't solve the issue, and it might not, I recommend renaming your Search class to something else, as name collisions tend to crop up weird bugs...
Good luck!
I'm In the process of migrating from Rails 2.3.11 to Rails 3.1.3 and I am now on Rails 3.0.11 and sorting out all the issues that this brings.
The first one I can't solve is: in Rails 2.3.11, I could do the following and get the required records back
#event_type_time_units = TimeUnit.find(#event.event_type.time_units)
In Rails 3.0.11, I've tried using
#event_type_time_units = TimeUnit.find_with_ids(#event.event_type.time_units)
and
#event_type_time_units = TimeUnit.find_some(#event.event_type.time_units)
The code for both of those doesn't do anything magical and I expected them not to work.
Does anyone have a pointer for me, please.
Thank you
edit: the error I get is TypeError in MeetingsController#create
Cannot visit TimeUnit
Rails 3 uses Arel aka relational algebra to fetch associations. Assuming your EventType model has an association to has_many :time_units, you can just do the following:
#event_type_time_units = #event.event_type.time_units
Furthermore, you can optimize your queries using EventType as a join model (ish):
# app/models/event.rb
belongs_to :event_type
has_many :time_units, :through => :event_type
# app/models/event_type.rb
has_many :events
has_many :time_units
Now, you can query directly, saving a SQL call:
#event_time_units = #event.time_units
In short, there's no reason to do a find on an association. The association returns an "Array" of the records. (I use "Array" in quotes, because it's not really an array, but an ActiveRecord::Association which behaves much like an array)
Aside
I highly recommend just migrating to Rails 3.1.3. It's just as difficult to migrate from Rails 2 -> 3 as 3 => 3.1. Save yourself the middle headache. In fact, given the legacy of your application, I recommend the following:
Create a new, empty Rails 3.1.3 application
Copy all your models, views, controllers, and libs to this new application
Search your existing projects for gems -> add them to your Gemfile
Review everything in config/*. This is where a LOT of changes have take place. If you have application-specific code in your existing application, port it over to the new one. Otherwise, leave it alone.
I stumbled over a SystemStackError and found where it is caused in the source code. Though, I did not quite understand why it happens. Maybe you can help me.
Here is the scenario:
There are two models Facility and Location given by their model definitions in the following.
class Location < ActiveRecord::Base
belongs_to :facility
accepts_nested_attributes_for :facility
end
class Facility < ActiveRecord::Base
has_many :locations
accepts_nested_attributes_for :locations
end
Now I create an object of each class in the Rails console: rails c.
location = Location.create(...)
facility = Facility.create(...)
Then I want to associate both with each other.
location.facility = facility
facility.locations << location
I cannot execute the last command when I executed the first before - it raises a SystemStackError: stack level too deep. Though, I can run the association commands separate from each other or sequential but in reverse order. The problem is that I cannot add the location again. Why?
Why do both?
This line:
facility.locations << location
Will already set the location's facility to be the specified facility. Both lines in this case are doing the same thing. What I would recommend doing is to use the association builder, like this:
facility.locations.create!(...)
This way, Rails takes care of setting the facility_id field, rather than you doing a manual assignment after it.
The first thing that I would suspect here is that the has_many association is really has_too_many. In other words, you may have too many locations in the relationship.
In fact, given the code you posted, you seem to have created an infinite loop of associations. You wrote:
accepts_nested_attributes_for :facility
I am assuming that this causes ActiveRecord to open the facility attribute where it finds another location with yet another facility attribute ad infinitem. before you dig too deeply, try this to see if it works:
facility.locations << location
location.facility = facility
However, be wary because this might just push the stack error to some other place in the app. If you Google for that error message you can find several people who have run into infinite recursion problems, generally related to saving a record.
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.
Apologies for the long title, but this is bothering me. I'm new to Rails, so this is my first project. Rails 3.0.3.
In my model, a User may or may not have read many Entries; this is tracked in a model called ReadEntries. This many-to-one relationship is properly defined in the code, I think.
User.rb:
has_many :read_entries
Entry.rb:
has_many :read_entries
ReadEntry.rb:
belongs_to :entry
belongs_to :user
This table has to be populated at some point. If I try to do this:
user.read_entries.find_or_create_by_entry_id(entry.id, :read => false)
I get the error Unknown key(s): read. Leave out trying to set :read, and it works.
However, if I create the same row with this, it works:
ReadEntry.find_or_create_by_entry_id_and_user_id(entry.id, user.id, :read => false)
Logically, these methods should be identical, right? Thanks.
I've also had weird experiences with find_or_create. I would love it if it worked, but it seems inconsistent.
I'm currently having the same issue as you, and I think it may be due to calling find_or_create on an association as opposed to the model directly. Here's my example:
permission_assignments.find_or_create_by_role_id(:role_id => role_id, :is_allowed => false)
This works to create the assignment, except the "is_allowed" field gets set to it's default of "true". This code works for me (in the Permission model, hence the self reference)
PermissionAssignment.find_or_create_by_permission_id_and_role_id(:permission_id => self.id, :role_id => role_id, :is_allowed => false)
It's more verbose, unfortunately, but it works. The only problem that I still notice is that the object that is returned has no id assigned (the record does get created in the database, however, but if I wanted to update any more attributes I wouldn't be able to without the id). Don't know if that's a separate issue or not.
Rails 3.0.4 here with Postgres 8.4
You cannot pass in other fields like that as Rails will assume they are options for the find. Instead, you will need to make your method call longer:
user.read_entries.find_or_create_by_entry_id_and_read(entry.id, false)
Or alternatively use a shorter, custom syntax for that.
For your final example, my thoughts are that Rails will take the second argument and use that as options. Other than that, I am not sure.