In my rails application, i'm unable to save the model object when associations are present.
I'm using mongo as db.
Brief explanation:
I have a model object,
#obj1 = User.create(name: "name1")
When i do #obj1.save, it works fine. Now i added a relationship say,
has_many :offices
and then i try to save the same object with new entry.
#obj1 = User.create(name: "name2")
I get a error like
/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:230:in `block in constantize'
gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:229:in `each'
Edit:
Full error trace:
NameError: uninitialized constant Office
from /home/workspace/.rvm/gems/ruby-1.9.3-p286#cv_app/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:230:in `block in constantize'
from /home/workspace/.rvm/gems/ruby-1.9.3-p286#cv_app/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:229:in `each'
from /home/workspace/.rvm/gems/ruby-1.9.3-p286#cv_app/gems/activesupport-3.2.9/lib/active_support/inflector/methods.rb:229:in `constantize'
from /home/workspace/.rvm/gems/ruby-1.9.3-p286#cv_app/gems/activesupport-3.2.9/lib/active_support/core_ext/string/inflections.rb:54:in `constantize'
In your user model
class User < ActiveRecord::Base
has_many :offices
end
In your office model
class Office < ActiveRecord::Base
belongs_to :user
end
Now, try this
#user = User.new
#user.name = "xyz"
#user.save
for relationship
#user = User.offices.build
Check whether the office model and table has created or not. It these two were created it won't give this kind of error.
Related
I'm making a system to generate pub quizzes for pubs. To ensure that a pub doesn't receive the same quiz twice, pubs and quizzes have a many to many association.
class Quiz < ActiveRecord::Base
has_and_belongs_to_many :pubs
serialize :rounds, Array
before_create :generate_rounds
def generate_rounds
# Round class initializes with array of pubs
NUMBER_OF_ROUNDS.times { rounds << Round.new(pubs: self.pubs) }
end
end
class Pub < ActiveRecord::Base
has_and_belongs_to_many :quizzes
end
A quiz has rounds (an array of Round objects that contain questions) that are serialized using the ActiveRecord method serialize.
When I run this code:
q = Quiz.new
q.pubs << Pub.create
q.save
I got:
ArgumentError: undefined class/module HABTM_Pubs
Previously, I had a belongs_to relation (a quiz belonged to one pub) and this error didn't occur.
When I comment out the before_create callback (so rounds don't get created), the q.save action succeeds.
From my schema.rb
create_table "pubs_quizzes", id: false, force: true do |t|
t.integer "pub_id"
t.integer "quiz_id"
end
Things like Quiz.new.pubs work.
Edit: the stack trace
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/class_loader.rb:53:in `path2class'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/class_loader.rb:53:in `resolve'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/class_loader.rb:45:in `find'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/class_loader.rb:27:in `load'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:360:in `resolve_class'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:87:in `deserialize'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:122:in `visit_Psych_Nodes_Scalar'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/visitor.rb:15:in `visit'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/visitor.rb:5:in `accept'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:31:in `accept'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:302:in `block in revive_hash'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:300:in `each'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:300:in `each_slice'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:300:in `revive_hash'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/to_ruby.rb:161:in `visit_Psych_Nodes_Mapping'
from /home/geert/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych/visitors/visitor.rb:15:in `visit'
It must have something to do with serialization.
Relevant item?
YAML::load raises undefined class/module error
Serializing an array with objects that reference an ActiveRecord association seems to cause the error.
replacing
Round.new(pubs: self.pubs)
with
Round.new(pub_ids: self.pubs.map { |pub| pub.id })
and fetching the pubs in the Round class itself makes the error go away.
I have an example of code not passing in test but working in the console.
Failing Test:
describe ImporterProfile do
it 'sends defaults method to EventAttribute model' do
expect(ListPage).to receive(:new) #passes
expect(EventAttribute).to receive(:new) #fails
ImporterProfile.new.standard_profile
end
1) ImporterProfile standard_profile sends new method to associated objects
Failure/Error: importer_profile.standard_profile
NoMethodError:
undefined method `each' for nil:NilClass
# ./app/models/importer_profile.rb:51:in `standard_profile'
# ./spec/models/importer_profile_spec.rb:29:in `block (3 levels) in <top (required)>'
Models:
class ImporterProfile < ActiveRecord::Base
has_one :list_page, dependent: :delete
has_many :event_attributes, dependent: :delete_all
accepts_nested_attributes_for :list_page
accepts_nested_attributes_for :event_attributes
def standard_profile
self.list_page = ListPage.new
self.event_attributes = EventAttribute.new
end
end
class EventAttribute < ActiveRecord::Base
belongs_to :importer_profile
end
class ListPage < ActiveRecord::Base
belongs_to :importer_profile
end
However, running this method in the console instantiates a new ImporterProfile, ListPage and several EventAttribute objects.
Anyone understand what is going on here?
I suspect that the problem is that you are mocking EventAttribute.new, but only returning nil, so Rails can't enumerate the active records as is required by the self.event_attributes = statement. (It needs to set the foreign key attribute of the EventAttribute records to the id of the ImporterProfile record.)
If you don't mind continuing with execution, you can do:
expect(EventAttribute).to receive(:new).and_call_original
Alternatively, you can return a double, but you'll need to provide stubs for whatever methods ActiveRecord requires, either by using a library such as http://rubygems.org/gems/rspec-active_record_mocks/versions/0.1.4 or by rolling your own.
As an aside, this question would have been a little easier to answer if you'd provided some way to associate the line numbers in the error stack trace with the sources you provided. Also, the comments on your expect statements that the first passes and the second fails is confusing because it appears that you are raising an error before the expectations are being checked.
I wan't to test a has_many association on a class:
class Course < ActiveRecord::Base
has_many :modules
end
For this I wrote a test (Rspec):
describe Course do
it { should have_many(:modules) }
end
For some reason however this test fails:
1) Course should have many modules
Failure/Error: it { should have_many(:modules) }
NoMethodError:
undefined method `column_names' for Module:Class
# ./spec/models/course_spec.rb:4:in `block (2 levels) in <top (required)>'
Does someone has an idea why this test fails? I created a Module class:
class Module > ActiveRecord::Base
belongs_to :course
end
Could it be that 'Module' is a reserved keyword, and therefore I cannot create a class Module?
Thanks for your help,
Anthony
Module is "reserved" name in Ruby (since Ruby has build-in - and very important - Module class). This is probably source of your error.
I have this custom validation method which makes sure you can't vote on your own content, and it causes quite a few RSpec test to fail with undefined method 'user_id' for nil:NilClass
Is there a way to rewrite the custom validation, or use a native rails validation?
failing tests
12) Vote votable type
Failure/Error: #vote = FactoryGirl.create(:vote)
NoMethodError:
undefined method `user_id' for nil:NilClass
# ./app/models/vote.rb:18:in `ensure_not_author'
# ./spec/models/vote_spec.rb:5:in `block (2 levels) in <top (required)>'
validate :ensure_not_author
vote.rb
attr_accessible :value, :votable_id, :votable_type
belongs_to :votable, polymorphic: true
belongs_to :user
def ensure_not_author
votable = self.votable_type.downcase
errors.add(:user_id, "You can't vote on your own content.") if self.votable.user_id == self.user_id
end
if anyone needs more code just shout
it looks like self.votable is nil. It appears as though this test should view the vote from the votable's point of view. If that's the case, then create the vote in the factory for your votable and move the test to your votable entity's suite, as you're really testing that the votable should not be able to vote on its own content.
I am learning Rails with the book Agile Web Development with Rails 4th edition.
Given the code for the migration below:
class CombineItemsInCart < ActiveRecord::Migration
def up
Cart.all.each do |cart|
sums = cart.line_items.group(:product_id).sum(:quantity)
sums.each do |product_id, quantity|
if quantity > 1
cart.line_items.where(product_id: product_id).delete_all
cart.line_items.create(product_id: product_id, quantity: quantity)
end
end
end
end
def down
LineItem.where("quantity>1").each do |line_item|
line_item.quantity.times do
LineItem.create(cart_id: line_item.cart_id, product_id: line_item.product_id, quantity: 1)
end
line_item.destroy
end
end
end
The following error occurs:
== CombineItemsInCart: migrating =============================================
rake aborted!
An error has occurred, this and all later migrations canceled:
Can't mass-assign protected attributes: quantity/home/richard/projects/pickaxe/mini-projects/depot-app/db/migrate/20130607003533_combine_items_in_cart.rb:9:in `block (2 levels) in up'
/home/richard/projects/pickaxe/mini-projects/depot-app/db/migrate/20130607003533_combine_items_in_cart.rb:6:in `each'
/home/richard/projects/pickaxe/mini-projects/depot-app/db/migrate/20130607003533_combine_items_in_cart.rb:6:in `block in up'
/home/richard/projects/pickaxe/mini-projects/depot-app/db/migrate/20130607003533_combine_items_in_cart.rb:3:in `each'
/home/richard/projects/pickaxe/mini-projects/depot-app/db/migrate/20130607003533_combine_items_in_cart.rb:3:in `up'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Now I read somewhere that this book was written before attr_accessible was required by default, but it hasnt really touched on how to use it properly yet. I have tried adding :line_item or :line_items to my attr_accessible line in the Cart model, but no luck.
Could someone educate me on what is happening here?
Can't mass-assign protected attributes: quantity
try attr_accessible :quantity
you will need to list all of the attributes in that list.
You need to make the attributes accessible. In the model:
class Object ActiveRecord::Base
attrib_accessible :attrib1, :attrib2, :attrib3
end
Obviously you would replace the attrib1 etc. with your model's attributes.
You try to access mass attributes from your migration. When you want to access database table attributes from your code then you need to allowing mass assignment of that attributes to tell your model that you can able to assign data for the field by the code. For this pusrpose, just add the desired field as a attr_accessible and for your issue specific solution is bellow :
class LineItem < ActiveRecord::Base
attr_accessible :quantity, :product_id, :cart_id
end