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

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

Related

As of Rails 5, when is :inverse_of necessary to set manually?

I've read in various places that it gets automatically inferred in some circumstances, but I've found the documentation on this feature to be hard to follow. Can anyone shed some light on the principles? Specifically when will Rails be able to infer and when will Rails not be able infer inverses?
I'd like to consider
polymorphic associations
single tabled inheritance (e.g. where BundleProduct and IndividualProduct both inherit from Product and use a products table)
regular has_one/has_many/belongs_to associations
has many through: associations
Some context: I'm maintaining a reasonably large 9-year-old Rails application with many, many tables. I'd like to have some guidance on which models require addition of inverse_of: rather than having to change every model in the system.
If you do not set the :inverse_of record, the association will do its
best to match itself up with the correct inverse. Automatic inverse
detection only works on has_many, has_one, and belongs_to
associations.
-- Rails API docs - ActiveRecord::Associations::ClassMethods
In cases where you have "non-standard" naming you may however need to provide the option:
The automatic guessing of the inverse association uses a heuristic
based on the name of the class, so it may not work for all
associations, especially the ones with non-standard names.
-- Rails API docs - ActiveRecord::Associations::ClassMethods
For example:
class Pet < ApplicationRecord
belongs_to :owner, class_name: 'User'
end
class User < ApplicationRecord
has_many :pets
end
If we call pet.owner it may incur a database hit even if we have already loaded that record.
If we add the inverse_of option:
class Pet < ApplicationRecord
belongs_to :owner, class_name: 'User', inverse_of: :pets
end
class User < ApplicationRecord
has_many :pets, inverse_of: :owner
end
Now if we already have that owner record in memory then pet.owner will point to the same owner.
In general there is no harm in explicitly setting the inverse_of so you can set it for each case where you are unsure. You can also manually test if it is needed by seeing if accessing the assocation creates a DB query via the console or by using shoulda-matchers with your test suite.
You can look up exact inferring procedure in ActiveRecord::Reflection::AssociationReflection#automatic_inverse_of.
Rails tries to detect inverse for has_many, has_one and belongs_to that do not have through, foreign_key options and scope and have standard names (this is also described in official guide).

How does attribute class_name effect my model?

In my web dev class we were given the following code:
class User < ActiveRecord::Base
has_many :shouts
has_many :followed_user_relationships, class_name: "FollowingRelationship"
has_many :followed_users, through: :followed_user_relationships
def follow(other_user)
followed_users << other_user
end
end
I understand everything except what class_name does. Does it add information to the model relationship somehow or does it just make this relationship an alias of that class name? I checked out the documentations and it seemed pretty worthless for someone new to rails.
Rails needs to know which class to instantiate for an association. It does this by guessing based on the association name, but it can only do this when your class and association are named predictably. Specifically, it uses String#classify to turn an association name into a class name. classify converts from underscore case to camel case, and singularizes the word:
"some_kind_of_records".classify => "SomeKindOfRecord"
In your particular case, your association name and class name aren't related this way.
:followed_user_relationships would cause Rails to look for a class called FollowedUserRelationship, which isn't the right class, FollowingRelationship.
Because you've deviated slightly from this convention, you have to explicitly tell Rails the name of the class involved. That's all class_name does. It tells Rails the name of the class to use, when Rails isn't able to guess correctly.
Consider a simpler example:
class User < ActiveRecord::Base
end
class Post < ActiveRecord::Base
belongs_to :author, class_name: 'User'
end
How could Rails know that a Post is associated with a User, if all we had written was belongs_to :author?

Struggles with has_many and belongs_to association when relationships are 2-3 deep

I'm pretty new to Rails and setting up associations, so I suspect I'm missing something pretty obvious. I'm trying to set up an app where one model has two models that it has_many of. The second model belongs_to the first and has_many of the third. And the third can either belong to the first or the second model.
Specifically, I have a wall model that holds pictures and collages. The wall can hold either pictures or collages or neither. Collages can hold pictures.
class Wall < ActiveRecord::Base
belongs_to :user
has_many :collages
has_many :pictures
end
class Collage < ActiveRecord::Base
belongs_to :user
belongs_to :wall
has_many :pictures
end
class Picture < ActiveRecord::Base
belongs_to :user
belongs_to :wall
belongs_to :collage
end
The error I'm getting is telling me:
undefined method `picture?' for #Wall
Is there something I'm doing wrong with the associations I'm creating?
has_many association on any model gives plural form of that method
Therefore Wall class has method #pictures available by this line:
If you want #picture method to be available you should use association as belongs_to
We can debug more into the exact problem if you tell where actually you are getting this error and what is your feature to implement.
Also name for Picture class should be with capital P
#cvibha's answer should help you with the associations
However, there's another problem you may need to consider. You're calling this method:
undefined method `picture?' for #Wall
Rails associations basically create a record as per how you define the association (has_many :pictures creates #wall.pictures). However, you're calling picture?
--
If you've got a custom method called picture?, this should work (albeit without the association working - as described in the other answer). The problem you have is I don't think you've defined picture?
I would do this:
#app/models/wall.rb
Class Wall < ActiveRecord::Base
...
def picture?
#your code
end
end
Alternatively, if you're looking to validate the existence of a picture, you may wish to use in your view:
#wall.pictures.any?
#wall.pictures.first.present?

Is the has_may relationship on rails necessary or the belong_to is enough?

I have a model with a var reference to another one.
User -> Profile
When I have generated the Profile model I used the references
feature so it has generated the corresponding migration
....
t.references :user
....
My question is do I have to add a relationship on the User model too?
has_one :Profile
Yes, you need both code in two models and the migration you mentioned.
class User < AR
has_one :profile
end
class Profile < AR
belongs_to :user
end
has_one and belongs_to are just methods which adds some more methods to your model. This means, you can have belongs_to defined on one model and no has_one on the other. The only problem is that you would be able to call profile.user, but no user.profile.
It is absolutely up to you which methods you want to be defined and which you don't need. If you never ever want anyone to call profile.user, but want user.profile just call has_one :profile. In general those method shares nothing except that their using same foreign key column.
It is however worth mentioning, that this is usually advised to declare reverse association - it is not needed for things to work though.

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