Undefined method for a belongs_to association - ruby-on-rails-3

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

Related

ActiveRecord::ConfigurationError - Association named 'whatever' was not found

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.

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.)

Why does this method not prevent NoMethodError?

I'm using the will_paginate gem, and trying to implement DataTables, per this RailsCast, and discovered that it is a good idea to supply the attribute total_entries, because will_paginate apparently does not do this very well.
So I added this method to my class like so:
class Genotype < ActiveRecord::Base
attr_accessible :allele1, :allele2, :run_date
belongs_to :gmarkers
belongs_to :gsamples
def total_entries
#t = Genotype.count;
return #t
end
end
However, I still get this error when the view tries to load (this is a screenshot of the webserver responses):
(7.6ms) SELECT COUNT(*) FROM "genotypes"
Completed 500 Internal Server Error in 96ms
NoMethodError (undefined method `total_entries' for nil:NilClass):
app/datatables/genotypes_datatable.rb:13:in `as_json'
app/controllers/genotypes_controller.rb:7:in `block (2 levels) in index'
app/controllers/genotypes_controller.rb:5:in `index'
Obviously I must be doing something wrong in defining my method; but what? I am too inexperienced in Rails to stumble my way out of this...
Thanks in advance,
Rick

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.

ActiveRecord::AssociationTypeMismatch in Ruby On Rails 3.2.1

I have some little test for Ruby On Rails 3.2.1 Here is explanation for my models:
class Project < ActiveRecord::Base
has_many :tasks
accepts_nested_attributes_for :tasks
end
class Task < ActiveRecord::Base
belongs_to :project
end
But when I tried to save tasks for my project I get error:
irb(main):037:0> Project.first.tasks = [Task.first.id, Task.last.id]
Project Load (0.2ms) SELECT "projects".* FROM "projects" LIMIT 1
Task Load (0.1ms) SELECT "tasks".* FROM "tasks" LIMIT 1
Task Load (0.1ms) SELECT "tasks".* FROM "tasks" ORDER BY "tasks"."id" DESC LIMIT 1
ActiveRecord::AssociationTypeMismatch: Task(#70101178643360) expected, got Fixnum(#70101143633040)
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/activerecord-3.2.1/lib/active_record/associations/association.rb:204:in `raise_on_type_mismatch'
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/activerecord-3.2.1/lib/active_record/associations/collection_association.rb:308:in `block in replace'
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/activerecord-3.2.1/lib/active_record/associations/collection_association.rb:308:in `each'
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/activerecord-3.2.1/lib/active_record/associations/collection_association.rb:308:in `replace'
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/activerecord-3.2.1/lib/active_record/associations/collection_association.rb:41:in `writer'
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/activerecord-3.2.1/lib/active_record/associations/builder/association.rb:51:in `block in define_writers'
from (irb):37
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands/console.rb:47:in `start'
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands/console.rb:8:in `start'
from /Users/ka8725/.rbenv/versions/1.9.2-p290/lib/ruby/gems/1.9.1/gems/railties-3.2.1/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Please, help me. Why does this exception raise?
Task.first.id and Task.last.id returns number of Fixnum type
You cannot assign Project.first.tasks which expect class Task to an array of number.