ActiveRecord::ConfigurationError - Association named 'whatever' was not found - ruby-on-rails-3

I have a complicated case where I'm developing a Rails 3 Engine and I only intermittently get the error in the title. Here's the stacktrace:
ActiveRecord::ConfigurationError - Association named 'whatever' was not found; perhaps you misspelled it?:
activerecord (3.2.18) lib/active_record/associations/preloader.rb:150:in `block in records_by_reflection'
activerecord (3.2.18) lib/active_record/associations/preloader.rb:146:in `records_by_reflection'
activerecord (3.2.18) lib/active_record/associations/preloader.rb:139:in `grouped_records'
activerecord (3.2.18) lib/active_record/associations/preloader.rb:130:in `preload_one'
activerecord (3.2.18) lib/active_record/associations/preloader.rb:109:in `preload'
activerecord (3.2.18) lib/active_record/associations/preloader.rb:98:in `block in run'
activerecord (3.2.18) lib/active_record/associations/preloader.rb:98:in `run'
activerecord (3.2.18) lib/active_record/relation.rb:181:in `block in exec_queries'
activerecord (3.2.18) lib/active_record/relation.rb:180:in `exec_queries'
activerecord (3.2.18) lib/active_record/relation.rb:160:in `block in to_a'
activerecord (3.2.18) lib/active_record/explain.rb:41:in `logging_query_plan'
activerecord (3.2.18) lib/active_record/relation.rb:159:in `to_a'
activerecord (3.2.18) lib/active_record/relation/delegation.rb:39:in `+'
/Users/me/src/appointment_engine/app/controllers/appointment_engine/appointments_controller.rb:42:in `block (3 levels) in index'
/Users/me/src/appointment_engine/app/controllers/appointment_engine/appointments_controller.rb:41:in `block (2 levels) in index'
actionpack (3.2.18) lib/action_controller/metal/mime_responds.rb:196:in `respond_to'
/Users/me/src/appointment_engine/app/controllers/appointment_engine/appointments_controller.rb:12:in `index'
To summarize: There's a model named Appointment in the engine which is polymorphically associated with has_many :through to the host app's User model (this is a requirement because we also associate to another model). Here's the has_many declaration in Appointment
class Appointment < ActiveRecord::Base
has_many :scheduleables,
through: :appointments_scheduleables,
source_type: KAE.scheduleable_class.name
has_many :schedulers,
through: :appointments_schedulers,
source_type: KAE.scheduler_class.name
end
Here I ran into my first problem; I need to set the :source_type on has_many :through polymorphic associations (It doesn't work without it) and for that I need to know the class of the associated model but, when my engine's Appointment model loads it does so before the host app's User model loads and therefore my engine's module KAE hasn't received the value for KAE.scheduleable_class yet.
Here's how KAE receives that value:
# in host app
class User < ActiveRecord::Base
acts_as_scheduler
end
I wrote acts_as_scheduler as an AR mixin, it will declare the has_many :through association to Appointment.
My first attempt to fix this: I put the Appointment's has_many declaration in a hook inside a railtie:
ActiveSupport.on_load :after_initialize do
KAE::Appointment.class_eval do
has_many :scheduleables,
through: :appointments_scheduleables,
source_type: KAE.scheduleable_class.name
has_many :schedulers,
through: :appointments_schedulers,
source_type: KAE.scheduler_class.name
end
end
Ok now that works, I wait till the host app loads completely and now I have the values for KAE.scheduleable_class and KAE.scheduler_class, great.
Except I get the error in the title intermittently!
I can boot up fine, use the app for a while (10-30 mins) and then out of nowhere boom! I've tried it under rails server, thin, and unicorn; all the same so it must be an app/framework level bug. I look in the active record preloader class to where the top of the stacktrace points to:
# lib/active_record/associations/preloader.rb:150
def records_by_reflection(association)
records.group_by do |record|
reflection = record.class.reflections[association]
unless reflection
raise ActiveRecord::ConfigurationError, "Association named '#{association}' was not found; " \
"perhaps you misspelled it?"
end
reflection
end
end
How can a model forget some of it's associations?
So now I'm doing this directly in the Appointment model and it seems to be working so far but it's really ugly:
class Appointment < ActiveRecord::Base
if KAE.scheduler_class && KAE.scheduleable_class
has_many :scheduleables,
through: :appointments_scheduleables,
source_type: KAE.scheduleable_class.name
has_many :schedulers,
through: :appointments_schedulers,
source_type: KAE.scheduler_class.name
else
binding.pry # TODO
ActiveSupport.on_load :after_initialize do
KAE::Appointment.class_eval do
has_many :scheduleables,
through: :appointments_scheduleables,
source_type: KAE.scheduleable_class.name
has_many :schedulers,
through: :appointments_schedulers,
source_type: KAE.scheduler_class.name
end
end
end
end
Anybody know of a better way of declaring has_many :through polymorphic associations in a Rails 3 Engine?
I've been looking at open source projects like acts_as_taggable_on_steroids and paper_trail to see how they do their associations but they don't have polymorphic has_many :through.
Anybody know any projects that have this type of association?

Load ordering can be a pain with Rails autoloading+auto-reloading magic. In these situations I just make my dependencies more explicit. I suggest you try using Rails's require_dependency in your host to ensure this doesn't occur:
# in host app
require_dependency 'appointment'
class User < ActiveRecord::Base
acts_as_scheduler
end
It's ActiveSupport's version of require that also plays well with the development environment's auto-reloading, which is probably why you're experiencing this issue intermittently when working on your application.

Related

No Mass assignment with attr_accessible set in model Rails 3.2.2

I have am creating a twitter style following relationship between users in my Rails 3.2.2 application. I have User and Relationship models.
class Relationship < ActiveRecord::Base
belongs_to :user
belongs_to :follower, :class_name => 'User'
attr_accessible :follower, :follower_id, :status
end
class User < ActiveRecord::Base
has_many :authentications, class_name: 'UserAuthentication'
has_many :relationships
has_many :followers, :through => :relationships
has_many :following, :through => :relationships, :foreign_key => 'follower_id', :source => :follower
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :omniauthable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
end
I decided to leave the devise and omniauth stuff in there incase it happened to be part of the issue, though I doubt it.
In the command line I am working with two users u1 and u2.
I run the command
u1.followers.build(:follower_id=>u2.id)
and receive this error
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: follower_id
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.2/lib/active_model/mass_assignment_security/sanitizer.rb:48:in `process_removed_attributes'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.2/lib/active_model/mass_assignment_security/sanitizer.rb:20:in `debug_protected_attribute_removal'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.2/lib/active_model/mass_assignment_security/sanitizer.rb:12:in `sanitize'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.2/lib/active_model/mass_assignment_security.rb:228:in `sanitize_for_mass_assignment'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/attribute_assignment.rb:75:in `assign_attributes'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/base.rb:495:in `initialize'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/reflection.rb:183:in `new'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/reflection.rb:183:in `build_association'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/associations/association.rb:233:in `build_record'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/associations/has_many_through_association.rb:91:in `build_record'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/associations/collection_association.rb:112:in `build'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.2/lib/active_record/associations/collection_proxy.rb:46:in `build'
from (irb):29
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.2/lib/rails/commands/console.rb:47:in `start'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.2/lib/rails/commands/console.rb:8:in `start'
from /Users/bradleyp/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.2/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
It's the first time I have used the build method on an association but it seems quite convenient if I can get it to work. If you need any more information please ask. Thanks for your help!
The follower_id is a field on Relationship. When you call u1.followers.build you are building a User which doesn't have a follower_id column. Since you are using attr_accessible, rails doesn't let you know that column doesn't exist, it just tells you you don't have access to it. (Which is good form a security perspective.)
Regardless, looks like you want to do:
u1.relationships.build(:follower_id => u2.id)
or maybe
u1.followers << u2
(With the code you showed I'm not 100% sure the second case will work off the type of my head -- you might need to further tweak your attr_accessible to get this second method to work. First one will definitely work, though.)

undefined method `selector' for #<ActiveRecord::Relation:0xbb8710c> when using mongoid to save a record

undefined method `selector' for #<ActiveRecord::Relation:0xbb8710c>
I am getting this error while trying to execute the follwoing code:
c = Content.first
c.is_processed = true
c.save # or c.update_attributes(:is_processed => true)
My Content model looks like this:
class Content
include Mongoid::Document
field :username
field :name
filed :is_processed, :type => Boolean
belongs_to :language
has_many :translations
end
I am using Mongoid 2.4, bson_ext 1.5, Ruby 1.9.2, Rails 3.2.5
I found the mistake. My Content model had this line:
has_many :translations
I had migrated the content model from ActiveRecord to Mongoid. But, all the other tables are still in ActiveRecord. The has_many was referring to a ActiveRecord model. This caused the issue. I commented the line and now update is working fine.

Undefined method for a belongs_to association

My code:
class User < ActiveRecord::Base
belongs_to :university
end
class University < ActiveRecord::Base
has_many :users, dependent: :destroy
end
and my model User has a university_id attribute.
If I do University.find(1).users I get the list of users, but if I do User.find(1).university (and I checked that university_id is not nil here) I get:
NoMethodError: undefined method `university' for #<User:0x00000003859fc8>
from /home/mari/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.0.10/lib/active_model/attribute_methods.rb :392:in `method_missing'
from /home/mari/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.0.10/lib/active_record/attribute_methods. rb:46:in `method_missing'
from (irb):14
from /home/mari/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:44:in`start'
from /home/mari/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands/console.rb:8:in start'
from /home/mari/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.0.10/lib/rails/commands.rb:23:in
`<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
What am I doing wrong? I have another models and they are working just fine. Any suggestions? Thanks in advance
I still can't comment so I'll burn an answer:
Somehow the belongs_to :university in the User model isn't being recognized. When testing, are you certain that the User model has been saved and is in the right place and that the server or console has been refreshed? Most commonly, in my experience, when I'm meddling with models, I have to refresh my server and console often to get clean results.
Try
User.where("id =?", 1).first.university

ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes:

I am following along the tutorial Ruby on Rail 3 Essential Training from Lynda.com. I am having a difficult time creating an Active Record Entry. This is the error I get in my console.
1.9.3p125 :007 > user = User.new(:first_name => "Mike", :last_name => "Jones")
ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: first_name, last_name
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/activemodel-3.2.3/lib/active_model/mass_assignment_security/sanitizer.rb:48:in `process_removed_attributes'
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/activemodel-3.2.3/lib/active_model/mass_assignment_security/sanitizer.rb:20:in `debug_protected_attribute_removal'
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/activemodel-3.2.3/lib/active_model/mass_assignment_security/sanitizer.rb:12:in `sanitize'
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/activemodel-3.2.3/lib/active_model/mass_assignment_security.rb:230:in `sanitize_for_mass_assignment'
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.3/lib/active_record/attribute_assignment.rb:75:in `assign_attributes'
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/activerecord-3.2.3/lib/active_record/base.rb:498:in `initialize'
from (irb):7:in `new'
from (irb):7
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands/console.rb:47:in `start'
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands/console.rb:8:in `start'
from /home/mark/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.3/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>`
This is what I have in my Model:
class User < ActiveRecord::Base
attr_accessible :first_name, :last_name
end
What am I doing wrong. I have rails 3.2.3
From what I know that lynda course was developed on rails3 and in rails 3.2.3 there is no mass assignment by default. You have to go your model and add attr_accessible :name, :position, :visible. Basically you have to add every attribute you want to mass assign.
Try to restart the console. If you have created the model for user after the console was launched, you should restart it.
Without any precautions Mass-assignment allows attackers to set any database column’s value, hence it has been disabled by default.
def signup
params[:user] # => {:name => “ow3ned”, :admin => true}
#user = User.new(params[:user])
end
The detailed description is in the Ruby On Rails Security Guide.
I just added the attr_accessible :first_name, :last_name, :username line to the models file.
This worked for me.
I was too following along the tutorial Ruby on Rail 3 Essential Training from Lynda.com, if anybody had the same problem here is what worked for me,
Turn off the security setting. Open config/application.rb and change config.active_record.whitelist_attributes to false instead of true. This makes your app a little less secure, but allows you to quickly move forward with the tutorial.
this is from: http://www.lynda.com/Ruby-on-Rails-3-tutorials/essential-training/55960-2/faqs
Make sure to put attr_accessible :first_name, :last_name in the User model and not in the controller.

Ruby on Rails 3 (3.1) ActiveModel Associations (tableless nested models)

How to impliment ActiveModel associations (tableless nested models)?
For example:
book has many chapters
With ActiveRecord I would create two models and assosiate them with has_many and belongs_to. But ActiveModel doesn't have such functionality. How can I implement this?
With rails versions >= 2.3.x you can use the activerecord-tableless gem. With that gem you can have associations and validations without a database.
Update
I have been added as author to the gem and I have updated the gem to support newer Rails versions. So now we can have tableless models with associations in Rails versions >= 2.3
You simply can't do it that way. It is not active record.
You can check ActiveModel documentation (and source code) at :
https://github.com/rails/rails/tree/master/activemodel
I guess you have to do it old fashion way, using an array of chapters and a reference to the book in the chapters.
Hope this helps!
You can check out this answer for another way to do it.
class Tableless < ActiveRecord::Base
def self.columns() #columns ||= []; end
def self.column(name, sql_type = nil, default = nil, null = true)
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
end
attr_accessor :id, :name, :value
has_many :stuff_things
has_many :things, :through => :stuff_things
end