Raven the Bard Raven the Bard - 6 months ago 8
Ruby Question

How do I modify a record in a different model

I'm a rails begginer and I was coding a simple app to train the language and other stuff.

In my app, I have three different scaffolds generated, one for People, one for House Activities and one last to link them together called Assignments. It's a many to many dependency situation.

So I was trying to calculate the total time a person would have to spend doing all the house activities assigned to them and store it inside the Person in an attribute called "time_allocated". So if I have two activities assigned to someone, it would return the sum of the duration of those activities.

After searching I discovered that creating an attribute with three dependencies is no good, but I don't know how to do it other way.

These are the models and the things that I tried to do:

Person Model

class Person < ActiveRecord::Base
has_many :assignments, dependent: :destroy
has_many :house_activities, through: :assignments
extend FriendlyId
friendly_id :name, use: :slugged
end


House Activity Model

class HouseActivity < ActiveRecord::Base
has_many :assignments, dependent: :destroy
has_many :people, through: :assignments
extend FriendlyId
friendly_id :name, use: :slugged
end


Assignment Model

class Assignment < ActiveRecord::Base
belongs_to :person
belongs_to :house_activity

def self.time_allocation #fulltime
Assignment.all.each do |assignment|
if (assignment.person.time_allocation.present?)
assignment.person.time_allocation += assignment.house_activity.duration
else
assignment.person.time_allocation = assignment.house_activity.duration
end
end
end

end

Answer

If I understand correctly, you're trying to get the sum of the durations of all of a Person's house_activities. You can get this directly from the database using Rails' ActiveRecord::Calculations#sum method:

person = Person.find(123)
puts person.house_activities.sum(:duration)
# => 500

Of course, you could create a helper method for this as well:

class Person < ActiveRecord::Base
  # ...

  def total_activities_duration
    house_activities.sum(:duration)
  end
end

person = Person.find(123)
puts person.total_activities_duration
# => 500

I would advise against storing this sum in the database, because then you have to ensure its consistency (e.g. every time an Assignment is created, edited, or deleted, you have to ensure that the associated Person is updated with the new sum). You might think that calculating the sum anew every time will slow down your app, and it may at some time in the future when you have thousands of records, but there's no need to optimize this unless and until an actual performance problem arises.

Comments