2
\$\begingroup\$

I want to update a single column in 4 tables. All relationships are has-many among them.

  • Private schools has many private classes
  • Private classes has many lesson plans
  • Lesson plans has many quizzes
  • Lesson plans has many documents

The code I am working with is:

@private_school.private_classes.each do |private_class|
 private_class.lesson_plans.each do |lesson_plan|
 lesson_plan.update_attribute("price_type", @private_school.price_type)
 lesson_plan.quizzes.update_attribute("price_type", @private_school.price_type)
 lesson_plan.documents.update_attribute("price_type", @private_school.price_type)
 end
 end

Is this a best approach to follow or is there any more option to tackle this? What are best practices about this scenario?

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Feb 17, 2017 at 21:45
\$\endgroup\$
2
  • \$\begingroup\$ Your comment makes sense. How can I achieve it? \$\endgroup\$ Commented Feb 19, 2017 at 18:30
  • \$\begingroup\$ Converted my comment to an answer with some more detail \$\endgroup\$ Commented Feb 19, 2017 at 19:25

2 Answers 2

1
\$\begingroup\$

(Converted a comment into this answer)

If all the records should use @private_school.price_type as their own price_type, then make them fetch it from the school they belong to - don't duplicate the same value across a bunch of tables when you already have it in one place. Keep the database normalized.

Simplest way to do this is to add a price_type method to each of the non-school models. The method simply fetches and returns <belongs_to relation>.price_type. I.e. Document#price_type would call its owner's method, which would be LessonPlan#price_type, which would call it's owner, etc.. until it hits the school's price_type attribute.

It's not the most efficient as it may need to load some records in the chain, but it's a start.

answered Feb 19, 2017 at 19:24
\$\endgroup\$
1
\$\begingroup\$

since you have to cache price_type on every table, you could use callbacks to not have to do this in a... controller action? or wherever. This could be a first step to simplifying.

class Quiz < ApplicationRecord
 belongs_to :lesson_plan
 before_save :set_price_type
 def set_price_type
 price_type = lesson_plan.price_type
 end
end
class Document < ApplicationRecord
 belongs_to :lesson_plan
 before_create :set_price_type
 before_save :set_price_type
 def set_price_type
 price_type = lesson_plan.price_type
 end
end
class LessonPlan < ApplicationRecord
 belongs_to :private_class
 has_many :documents
 has_many :quizzes
 before_save :set_price_type
 after_save :update_relationships
 def set_price_type
 price_type = private_class.price_type
 end
 def update_relationships
 quizzes.update_all(:price_type, price_type)
 document.update_all(:price_type, price_type)
 end
end
class PrivateClass < ApplicationRecord
 belongs_to :private_school
 has_many :lesson_plans
 after_save :update_relationships
 before_save :set_price_type
 def set_price_type
 price_type = private_school.price_type
 end
 def update_relationships
 lesson_plans.update_all(:price_type, price_type)
 document.update_all(:price_type, price_type)
 end
end
class PrivateSchool < ApplicationRecord
 has_many :private_classes
 after_save :update_private_classes
 def update_private_classes
 private_classes.update_all(:price_type, price_type)
 end
end

then you don't have to do anything extra to keep price type up to date.

The much larger and tougher question to answer is why is this variable being cached on each table in the first place? This is going to eventually make maintenance a nightmare. You need to take a hard look at where you are accessing this value and ask yourself if you really need to cache it.

These decisions are made usually in response to slow queries in views or controller actions, but most of the time that slowness can be resolved in better ways. In general, favor query optimization over denormalization

answered Feb 20, 2017 at 6:44
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.