RoR polymorphic association stack level too deep error - ruby-on-rails

I've got polymorphic association which looks like
class Certificate < ActiveRecord::Base
attr_accessible :certification_id, :certified_id, :certified_type
belongs_to :certification
belongs_to :certified, :polymorphic => true
end
class Certification < ActiveRecord::Base
attr_accessible :name, :slug
belongs_to :association
end
class Association < ActiveRecord::Base
has_many :certifications
attr_readonly :name, :id
attr_protected :name
end
assuming User model
class User < ActiveRecord::Base
has_many :certificates, :as => :certified
end
i am trying to access association object from within polymorphic association
u = User.first
u.certificates returns array of instances of Certificate
u.certificates.first.certification returns instance of Certification
but
u.certificates.first.certification.association returns stack level too deep error and on the second run console/server crashes with illegal hardware instruction message
I do realize that this expression is hardly a queen of code beauty, but it should work, shouldn't it?

Firstly I think that Association may be an unfortunate choice for a model name.
ActiveRecord::Base already has an instance method called association which you've just overridden for your Certification model by setting up an association to a model called Association. I haven't had a chance to trace exactly what that's going to do, but I'd guess a method called "association" is probably quite important in reflecting on and operating over a model's associations and overriding it is going to have exciting consequences.
I'd also suggest that given how awkward the above paragraph is to read that Association maybe isn't an optimal name for a Rails model anyway!
Try renaming that model and the associations to it to see if it fixes your problem.

Related

Rails couldn't find a valid model for - but association exists

I have a polymorphic table in rails MetaFieldsData which also belongs to a table MetaFields
class MetaFieldsData < ApplicationRecord
belongs_to :owner, polymorphic: true
belongs_to :meta_field
end
class MetaField < ApplicationRecord
belongs_to :organization
has_many :meta_fields_data
end
One model which is connected to the polymorphic table is called orders:
class Order < ApplicationRecord
belongs_to :organization
...
has_many :meta_fields_data, as: :owner
...
owner is my association class (the same what is imageable from the official RoR guide)
Now I see a strange behaviour when I want to create a record on a the Order model:
MetaFieldsData.create(owner: order, meta_field: some_meta_field)
It throws:
NameError Exception: Rails couldn't find a valid model for MetaFieldsDatum association.
Please provide the :class_name option on the association declaration. If :class_name is already provided, make sure it's an ActiveRecord::Base subclass.
What is weird is that there is no class MetaFieldsDatum (note the typo here, coming from Rails). I searched all my code and there is no typo in there, also not in the class name definition.
This makes it impossible for me to create an actual MetaFieldsData on this table as Rails seems to interpret the naming wrong.
What could possibly be wrong here?
Thank you
I had the same problem, but my solution was different.
I had a typo in my belongs_to model which invalidated the model.
I discovered it was an invalid model by trying to access it in the console. Because it was invalid, Rails didn't load it and subsequently couldn't find it.
The error disappeared when I corrected the typo.
Datum is used as a plural form of data. Notice that you have has_many :meta_fields_data and if you would to change that into a singular it would also be has_one :meta_fields_data.
This is called inflection and it is a way of detecting plural forms of words, you can read up on how rails does it here https://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html
In general you can either simply obide to what the error tells you and use datum in relationship name (specify class_name if you do so), or define your own inflection

Rails 4 Accept nested attributes with has_one association

I have a question about Rails Nested Attributes.
I'm using Rails 4 and have this model:
model Location
has_one parking_photo
has_many cod_photos
accepts_nested_attributes_for :parking_photo
accepts_nested_attributes_for :cod_photos
end
When I use for example:
Location.find(100).update(cod_photo_ids: [1,2,3]) it works.
But Location.find(100).update(parking_photo_id: 1) doesn't works.
I don't know what difference between nested attributes has_one and has_many.
Or do we have any solution for my case, when I already have child object and want to link the parent to the child and don't want to use child update.
Thank you.
The problem has nothing to do with nested attributes. In fact you're not even using nested attributes at all in these examples.
In this example:
Location.find(100).update(cod_photo_ids: [1,2,3])
This will work even if you comment out accepts_nested_attributes_for :cod_photos as the cod_photo_ids= setter is created by has_many :cod_photos.
In the other example you're using has_one where you should be using belongs_to or are just generally confused about how you should be modeling the association. has_one places the foreign key on the parking_photos table.
If you want to place the parking_photo_id on the locations table you would use belongs_to:
class Location < ActiveRecord::Base
belongs_to :parking_photo
# ...
end
class ParkingPhoto < ActiveRecord::Base
has_one :location # references locations.parking_photo_id
end
Of course you also need a migration to actually add the locations.parking_photo_id column. I would really suggest you forget about nested attributes for the moment and just figure out the basics of how assocations work in Rails.
If you really want to have the inverse relationship and put location_id on parking_photos you would set it up like so:
class Location < ActiveRecord::Base
has_one :parking_photo
# ...
end
class ParkingPhoto < ActiveRecord::Base
belongs_to :location
validates_uniqueness_of :location_id
end
And you could reassign a photo by:
Location.find(100).parking_photo.update(location_id: 1)

Rails ActiveRecord: two has_one relationships between the same models

I have a model, Project, that has 2 associations to the same model:
belongs_to :source_connection, class: Connection
belongs_to :destination_connection, class: Connection
That works fine - I can access connection methods through project without any issues.
I'm a little confused on how to do the inverse, however. I started with a rather optimistic:
has_one :project
on the Connection model, and unsurprisingly, it throws an
ActiveModel::MissingAttributeError: can't write unknown attribute 'connection_id'
error when I try to access the project from the connection itself.
If anyone knows how I can declare the association on the connection side, I'd be appreciative. Cheers.
Associations
You will probably be best looking at the foreign_key arguments for ActiveRecord Associations:
#app/models/project.rb
Class Project < ActiveRecord::Base
belongs_to :source_connection, class: "Connection", foreign_key: "source_connection_id"
belongs_to :destination_connection, class: "Connection", foreign_key: "destination_connection_id"
end
#app/models/connection.rb
Class Connection < ActiveRecord::Base
has_many :projects, foreign_key: "source_connection_id"
end
The issue you have is that since you're not using the foreign_key option in your associations, Rails will be looking for the standard foreign_key associations inside your schema (typically model_name_id).
--
Error
can't write unknown attribute 'connection_id'
I don't know why it's complaining about writing, but the reason is likely that you don't have the correct foreign key set up for your association. Typically, Rails will be looking for the model_name_id - but since you're not, you'll need to set the relative key in your models (as demonstrated)
has_one :project, foreign_key: 'source_connection_id'
Rails is looking for connection_id as the error says, as you've used source_connection and destination_connection you need to tell it to use the correct foreign key to look it up.
You might want to define them as:
has_one :source_project, foreign_key: 'source_connection_id'
has_one :destination_project, foreign_key: 'destination_connection_id'
Because you won't be able to call them both project.

ActiveRecord unknown attribute with polymorphic association

I have the following models
class Business < ActiveRecord::Base
has_one :name_object, as: :nameable
end
class NameObject < ActiveRecord::Base
has_one :user
belongs_to :nameable, polymorphic: true
end
However, when I try to build a business with a name and user, like so:
business = Business.new
business.build_name_object
business.name_object.build_user
Rails throws the error ActiveRecord::UnknownAttributeError in BusinessesController#new unknown attribute: name_object_id.
I've created the database with nameable_id and nameable_type columns for the name_objects table, but I don't think I need a name_object_id foreign key on the business table as well. What am I missing?
Seems like since your NameObject has_one :user, that the User would be the one that belongs_to :name_object, therefore Rails is looking for name_object_id to be a field in the user table and its throwing that error. Just a hunch so, maybe, post your User model code.

Rails many-to-many relations and nested forms: associate with object if it already exists

I'm having an issue with several many-to-many relations in my Rails project. It can be illustrated with an example:
Say I have the models Person and PhoneNumber, joined by PersonPhoneNumber. The relation is many-to-many because people can have more than one phone number, and more than one person can be reached at the same phone number (in a case such as a help desk).
class Person < ActiveRecord::Base
has_many :person_phone_numbers
has_many :phone_numbers, :through => :person_phone_numbers
end
class PhoneNumber < ActiveRecord::Base
has_many :person_phone_numbers
has_many :people, :through => :person_phone_numbers
validates :number, :uniqueness => true
end
class PersonPhoneNumber < ActiveRecord::Base
belongs_to :person
belongs_to :phone_number
end
I have a person form that lets me create/update people's contact information. I use it to assign the number 555-555-1212 to Bob. If a PhoneNumber object with that number doesn't exist, I want it to be created (as in the standard accepts_nested_attributes_for behavior). But if it does exist, I want to just create a PersonPhoneNumber object to associate Bob with that PhoneNumber.
How can I accomplish this most elegantly? I tried putting a before_validation hook in PersonPhoneNumber to look for a matching PhoneNumber and set phone_number_id, but this caused really bizarre behavior (including making my Rails server crash with the message Illegal instruction: 4).
You can use exists? method to check for existence first, like this:
#person.phone_numbers.build(number: "555-555-1212") unless #person.phone_numbers.exists(number: "555-555-1212")
Or you can do something like this:
PhoneNumber.find_or_create(person_id: #person.id, number: "555-555-1212")
Rachel the Rails documentation says this:
A has_and_belongs_to_many association creates a direct many-to-many connection with another model, with no intervening model.
What is the difference?

Resources