Oh! 1. You could just have a 'Participant' table, containing students, professors, teachers, evaluators as distinguished by a role, is_active, etc.. 2. You could just have a 'Evaluation_Detail' table, containing at a row level student_id, class_id, teacher_id, professor_id, evaluator_id for each question, its response, then its evaluation as a comment and/or look-up value from a grading table, etc..
Queries would obviously be more 'where' intensive, but your associations wouldn't be as deep. Liz On Monday, August 17, 2015 at 10:52:40 AM UTC-4, Scott Goci wrote: > > Hey Liz, > > Thanks for responding. Here's some initial responses: > > > 1. While I understand the need in an actual application for things > like a *Classroom* model (owned by a *Professor*), and then something > like a *StudentClassroom* model (setting up *Students* to a > *Classroom*) to better help organize the data, what I'm looking for > really is how associations fit together when deeply nested outside of the > context of the actual application. I set up this example simply as a way > of > exploring some of the problems it poses. > - Ditto for a *School* model -- we can assume that a *School *has_many > :professors, etc. > 2. The idea is that as we get deeper into our models, it becomes > harder and harder to get back to the beginning. > - In my example, From an *Evaluation*, we would need 5 hops to get > back a *School* model for example (imagine > evaluation.response.question.exam.professor.school) > - Similarly, from the reverse side, it would be hard to query for > all *Evaluations* for a *School:* > - *@school = School.first* > - *@all_professors = @school.professors* > - *@all_exams = Exam.where(professor_id: > @all_professors.pluck(:id))* > - *@all_exam_questions = Question.where(exam_id: > @all_exams.pluck(:id))* > - *@all_exam_responses = Response.where(question_id: > @all_exam_questions.pluck(:id))* > - *@all_exam_evaluations = Evaluation.where(response_id: > @all_exam_responses.pluck(:id))* > - While the above works, it took 6 lines to get there! Not to > mention the expense of doing a crazy amount of lookups > 3. So instead, what's the solution? > - We could write an "all_evaluations" method in what would be our > *School* model using the above code > - Solves the multiple lines problem, but not the query > complexity problem > - Perhaps using delegate? Little more elegant than perhaps a > method, but again the complexity problem > - Adding an extra foreign key to a model somewhere and > denormalizing the database a bit > - Eg for *Evaluation*, maybe add exam_id to the class > - To get back to a *School* now, it's 2 less hops ( > evaluation.exam.professor.school) > - To get all *Evaluations* for a *School*, we can now do the > following, which is two less lines of code (and less joins): > - *@school = School.first* > - *@all_professors = @school.professors* > - *@all_exams = Exam.where(professor_id: > @all_professors.pluck(:id))* > - *@all_exam_evaluations = Evaluation.where(exam_id: > @all_exams.pluck(:id))* > - This feels arbitrary though > - if we are going to do this, why not just add a school_id to > an evaluation? > - Or a bunch of other foreign keys to all the tables to make > all hops 1-2 at most > > In the end, I'm mostly trying to understand which strategy to use under > which scenarios -- I see a lot of blog posts talking about the law of > demeter and simplifying your associations (usually using delegate), but > most of them have pretty simple connections like > business.location.city_name, nothing as complex as chaining through 4-5 > associations to get back to the original object. It also feels dangerous to > chain that much -- if at any point in the > evaluation.response.question.exam.professor.school the associated object > ends up being deleted somehow, then you break your ability to get back to > the original object. > > Hope that helps explain my question more. > > > On Monday, August 17, 2015 at 8:45:51 AM UTC-4, Elizabeth McGurty wrote: >> >> Before I respond, I think that it would be helpful if you provided your >> database entity–relationship model. Also, I don't see that you have a >> Classes, the school variety, table. >> Liz >> >> On Monday, August 17, 2015 at 1:18:38 AM UTC-4, Scott Goci wrote: >>> >>> I've been wrestling with database normalization and the "Rails Way" and >>> I wanted to get peoples opinions as to if there's a best practices guide to >>> how to do it. Here's some background: >>> >>> Let's assume we have a model/schema similar to the following: >>> >>> class Student < ActiveRecord::Base >>> has_many :student_exams >>> has_many :exams, through: :student exams >>> end >>> >>> class StudentExam < ActiveRecord::Base >>> belongs_to :student >>> belongs_to :exam >>> end >>> >>> class Exam < ActiveRecord::Base >>> has_many :questions >>> belongs_to :professor >>> has_one :college, through: :professor >>> end >>> >>> class Question < ActiveRecord::Base >>> belongs_to :exam >>> has_many :responses >>> >>> # question_text: text >>> end >>> >>> class Response < ActiveRecord::Base >>> belongs_to :question >>> belongs_to :student >>> >>> # response_text: text >>> end >>> >>> class Evaluation >>> belongs_to :response >>> belongs_to :professor >>> >>> # grade: integer >>> end >>> >>> >>> The idea is that a *Professor* creates an *Exam* and* Questions*, and >>> then assigns students through *StudentExam* to take that exam. The >>> students then generate *Responses* to the exam questions, and then >>> those *Responses* are graded by *Evaluations* done by the *Professor*. >>> Now, given the above background, I wanted to ask a few questions to get >>> peoples opinions on how to structure this app: >>> >>> *Questions* >>> >>> 1. In general, are there any changes you guys would make with the >>> given associations? >>> 2. For the *Response* model, does it make sense to do "belongs_to >>> :student", or should it instead be "belongs_to :student_exam"? It >>> feels more logical to have the former, because we can get the exam >>> through >>> the question if need be (response.question.exam), and its really a >>> student responding to it, not a student_exam. But if we used >>> student_exam, >>> we could use response.student_exam.exam to get back to the exam, and >>> response.student_exam.student to get back to the student. >>> 3. If we were on an *Evaluation* and we wanted to back to a exam, it >>> would seem quite cumbersome to do evaluation.response.question.exam >>> just to get back to the exam. >>> - Now we could always create a method on the model that just >>> shortened it for us, but *is there a point when you are chaining >>> associations that somewhere along the line you add in another >>> foreign_key >>> to a table for easy lookup*? >>> 4. If we wanted to see all *Evaluations* for an *Exam*, what would >>> be the best way to do that? >>> - Only way I could see to do it easily would be to break it up, >>> something like: >>> - @questions = @exam.questions >>> - @responses = Response.where(question_id: >>> @questions.pluck(:id) >>> - @evaluations = Evaluation.where(response_id: >>> @responses.pluck(:id) >>> - This seems kind of painful >>> >>> >>> Let me know your thoughts -- or if you have any great books on the best >>> strategies for normalizing/denormalizing within or without the scope of a >>> rails app, I'd love to hear them. >>> >>> >>> >>> -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-talk+unsubscr...@googlegroups.com. To post to this group, send email to rubyonrails-talk@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/20044b4d-7363-4a5c-a080-730a304ce5d9%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.