ActiveRecord unknown attribute with polymorphic association - ruby-on-rails

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.

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 association in concerns

I am using concerns for my rails application. I've different kind of users so I have made a loggable.rb concern.
In my concern I have
included do
has_one :auth_info
end
because every of my user that will include the concern will have an association with auth_info table.
The problem is, what foreign keys I need to put in my auth_info table?
E.G
I've 3 kind of users:
customer
seller
visitor
If I had only customer, in my table scheme I would have put the field
id_customer
but in my case?
You can solve this with polymorphic associations (and drop the concern):
class AuthInfo < ActiveRecord::Base
belongs_to :loggable, polymorphic: true
end
class Customer < ActiveRecord::Base
has_one :auth_info, as: :loggable
end
class Seller < ActiveRecord::Base
has_one :auth_info, as: :loggable
end
class Visitor < ActiveRecord::Base
has_one :auth_info, as: :loggable
end
Now you can retrieve:
customer.auth_info # The related AuthInfo object
AuthInfo.first.loggable # Returns a Customer, Seller or Visitor
You can use rails g model AuthInfo loggable:references{polymorphic} to create the model, or you can create the migration for the two columns by hand. See the documentation for more details.
Since user has roles 'customer', 'seller', 'visitor'.
Add a column called role to Users table.
Add a column called user_id to auth_infos table.
class AuthInfo < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :auth_info
end
you can do
user = User.first
user.auth_info
Now you a additional logic to your concerns.

ActiveModel::MissingAttributeError: can't write unknown attribute `ad_id' with FactoryGirl

I have the following models:
class Ad < ActiveRecord::Base
belongs_to :page
has_one :image
has_one :logo
end
class Page < ActiveRecord::Base
has_many :logos
has_many :images
has_many :ads
end
class Image < ActiveRecord::Base
belongs_to :page
has_many :ads
end
And I have defined the following Factories:
factory :page do
url 'test.com'
end
factory :image do
width 200
height 200
page
end
factory :ad do
background 'rgb(255,0,0)'
page
image
end
When I try to do this:
ad = FactoryGirl.create(:ad) I get the following error ActiveModel::MissingAttributeError: can't write unknown attribute ad_id' right in the line where I decide the image association in the ad Factory.
What am I doing wrong here?
When you say:
has_one :image
Rails expects you to define an ad_id field at the images table. Given the way your associations are organised, I assume you have an image_id and a logo_id a the ads table so instead of:
class Ad < ActiveRecord::Base
belongs_to :page
has_one :image
has_one :logo
end
You probably mean:
class Ad < ActiveRecord::Base
belongs_to :page
belongs_to :image
belongs_to :logo
end
If that's not the case then you need to add ad_id columns to both Image and Logo.
If you are getting this error while running the specs, it may be the newly added field that are not migrated in the test environment. So migrate it in the test environment with the below command
rake db:migrate db:test:prepare
I ran into this same error and it took a while to figure out a fix. Just in case this helps someone else in the future, here's my scenario and what worked for me. Class names have been changed as this is for work:
I had 2 namespaced models:
Pantry::Jar
has_many :snacks, class_name: Pantry::Snack
accepts_nested_attributes_for :snacks
Pantry::Snack
belongs_to :pantry_jar, class_name: Pantry::Jar
When I would create a new jar with new snacks, I would get:
ActiveModel::MissingAttributeError: can't write unknown attribute `jar_id'
The fix was to change the has_many to be more explicit about the foreign key:
has_many :snacks, class_name: Pantry::Snack, foreign_key: :pantry_jar_id
Check your test database.
In my case, sometimes I did not modify the columns in the test database after modifying the development database after an incorrect migration.
If you're getting the error while testing and you're using different repositories accessing the same test database, check if the migrations are equal among projects.
If you reset the database each time you're running the tests, only migrations available in that repository will be run, hence triggering the error related to the missing foreign key
ActiveModel::MissingAttributeError: can't write unknown attribute ad_id'
You should have the migration file with something like:
class AddAdReferenceToImage < ActiveRecord::Migration[5.0]
def change
add_reference :images, :ad, foreign_key: true
end
end
In my case this message appeared because I tried setting a reference (with a column name different from the class name) like this:
Entity.create(reference: some_obj).save!
Although I'm not sure what exactly caused the issue, I was able to fix it by using the column name instead of the reference name:
Entity.create(reference_id: some_obj.id).save!

RoR polymorphic association stack level too deep error

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.

Resources