Issue with has_many and belong_to association, can't find method - ruby-on-rails

This is a many(proposaltracking)-to-one(partner) relationship.
I am getting undefined method 'reference' for ProposalTracking:Class error with #company.proposalTracking.reference
When I run #company.proposalTracking it returns me the ProposalTracking object.
Here is my model:
class ProposalTracking < ActiveRecord::Base
set_table_name "Proposal_Tracking"
belongs_to :partner
end
class Partner < ActiveRecord::Base
has_many :proposalTracking
end
What I want to get is the attributes of proposalTracking like
#company = Partner.find(params[:id])
#company.proposalTracking.reference
but this results in the error undefined method 'reference' for ProposalTracking:Class
I have read solutions where it is because since it is a one-to-many relation, the partner may have more than one track proposal so I would have to grab the first one using .first but I tried this and it then says
You have a nil object when you didn't expect it!
The error occurred while evaluating nil.reference
Any help would be much appreciated!

It should be
class Partner < ActiveRecord::Base
has_many :proposal_trackings
end
and you can access it via #company.proposal_trackings. But that's actually an array of ProposalTracking instances (because of has_many) that you have to iterate over to get each attribute
#company.proposal_trackings.map(&:reference)

Related

Why create_* method doesn't exist for has_many relationships?

I have the following models:
class Post < ApplicationRecord
has_many :metrics
end
class Metric < ApplicationRecord
belongs_to :post
end
I would like to know why there isn't a create_metrics method in a post instance. If the relationship was:
class Post < ApplicationRecord
has_one :metric
end
class Metric < ApplicationRecord
belongs_to :post
end
There would be a method create_metric in a post instance.
There is a collection.create method specified here: https://guides.rubyonrails.org/association_basics.html#methods-added-by-has-many-collection-create-attributes
In this particular case, you can call:
#metric.posts.create
And pass an array of objects with the data you want.
If you flip this question on its end you can see that for belongs_to and has_one you have the build_other and create_other methods since the association is nil by default.
So if you called thing.other.create you're calling .create on nil. Not good. While you could get around it by creating some kind of proxy object that would break code that relies on it being nil.
has_many and has_and_belongs_to_many don't have this problem since an empty association is an AssociationProxy object. You can think of this as kind of like an empty array. And even empty arrays have methods.
Its far more natural to call foo.bars.new or foo.bars.create than some metaprogramming method. And much easier to find the correct documentation.
Not sure why the convenience methods aren't there, but there is definitely a post.metrics.create(...) method. Most of these dynamic methods are on the collection itself, not the original model. See the official Rails ActiveRecord Associations Guide for more details.

Ruby on Rails - Get object association values with array of symbols

For example, have the models:
class Activity < ActiveRecord::Base
belongs_to :event
end
class Event < ActiveRecord::Base
has_many :activities
attr_accessible :foo
end
I can get the activity's event foo by using activity.event.foo (simple enough).
But I want to make a generic function that finds out first if an object has a belongs_to association and then get that object's foo through the belongs_to association (pretend that all objects have a foo through the belongs_to association)?
So far I have the following with gives me a reflection:
def get_foo(object)
object.class.reflect_on_all_associations(:belongs_to).each do |belongs_to|
return object.??????
end
end
I can either get an array of the reflection's class name via belongs_to.klass (e.g. [Event]) or an array of symbols for the belongs_to association via belongs_to.name (e.g. [:event]).
How do I get the object's belongs_to's foo given what I get from the reflection?
Is there an easier way to do this without using the reflection?
I'm hoping this is something simple and I'm just spacing out on how to solve this. I also hope I am being somewhat clear. This is my first Stack Overflow question.
You can do this but its not exactly pretty:
def get_foo(object)
object.class.reflect_on_all_associations(:belongs_to).map do |reflection|
object.send(reflection.name).try(:foo)
end
end
That will give you an array of all the foos associated with the object. You can change it to not do map and do a first or something.

Deleting first occurrence from many to many collection entry at rails?

In many to many fields delete method is deleting all the occurrence of collection. Say I have:
class user < ActiveRecord::Base
has_and_belongs_to_many :cars
end
class car < ActiveRecord::Base
has_and_belongs_to_many :users
end
users and cars are many to many relationship, I have defined my users_cars table. Now user can have repetitive car entry as relation. For example:
Car: A,B,C
User: U1,U2,U3
U1=[A,B,C,A,A,A,B]
Which can be implemented using many to many relationship, the way I have implemented. BUT, at the time when I want to delete one of the car entries of user the problem occurs.
User.cars.delete(car) #deletes all occurrence of car
User.cars.delete_at(User.cars.find_index(video_card)) #delete_at does not exist
Now how to resolve this?
First of all, you can't call User.cars unless you have defined a class level method cars in your User model, but in this way, you would return all cars, and that - in no way - would make sense.
Second, delete_at is a method that works on Array objects, and expects an integer to be passed in. So as a little hack, you can turn your ActiveRecord::Associations object into an array, and then call delete_at method.
user = User.first
user.cars.to_a.delete_at(Car.last.id) # assuming that the last car belongs
# to the first user, something you would never do in actual
# production code.
Edit:
You can also try the following to achieve the same functionality:
user = User.first
user.cars.where("cars.id = ?", Car.first.id).first.delete
Edit 2:
For what you asked in comment, you can have a model for the table cars_users.
rails g model CarUser
class Car < ActiveRecord::Base
has_many :cars_users
has_many :users, through: car_users
end
class User < ActiveRecord::Base
has_many :cars_users
has_many :cars, through: car_users
end
class CarUser < ActiveRecord::Base
belongs_to :car
belongs_to :user
end
And now, you can do:
CarUser.where("car_id = ? AND user_id = ?", Car.first.id, User.first.id).first.delete

How to get all the associated models from ActiveRecord object?

For example I have
class Order < ActiveRecord::Base
has_many :shippings
has_one :contact_information
belongs_to :shop
end
How to get an array of associated objects from Order. For example
Order.associations
# [:shipping, :contact_information, :shop]
Order.reflect_on_all_associations.map(&:class_name)
You can pass a type of relation as a parameter:
Order.reflect_on_all_associations(:has_one)
Read about ActiveRecord::Reflection::ClassMethods
EDIT
Just realised, you've asked about object's associated models.
So, having what I've already shown, you can simply do something along the following lines:
associated_models = Order.reflect_on_all_associations.map(&:class_name)

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?

Resources