icemage64-PkbjNfxxIARBDgjK7y7TUQ@public.gmane.org
2009-Apr-19 20:16 UTC
Accessing Models via Views
Hi When creating a view to display infromation obtained from a model, should the view always get this information from the controller, or should it get it directly from the model? For example, say I have Class and Student models, and they are in a many to many relationship via the enrolled table. Now my view wants to display the students of a given class. Should the controller run the query and store it in a variable (say @students) that is passed to the view? Or, should the view just access it directly like <% for enrolled in @class.enrolled_students %> <%= enrolled.student.name %> I like the second way because it does not require me to put any code in the controller. I just feel like this is coupling the view and to the model and I can''t tell if that is a bad thing in an MVC framework? I feel like it is. Thanks in advance --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Apr 19, 2009, at 4:16 PM, icemage64-PkbjNfxxIARBDgjK7y7TUQ@public.gmane.org wrote:> Hi > > When creating a view to display infromation obtained from a model, > should the view always get this information from the controller, or > should it get it directly from the model? > > For example, say I have Class and Student models, and they are in a > many to many relationship via the enrolled table. Now my view wants to > display the students of a given class. Should the controller run the > query and store it in a variable (say @students) that is passed to the > view? Or, should the view just access it directly like > > <% for enrolled in @class.enrolled_students %> > <%= enrolled.student.name %> > > I like the second way because it does not require me to put any code > in the controller. I just feel like this is coupling the view and to > the model and I can''t tell if that is a bad thing in an MVC framework? > I feel like it is. > > Thanks in advanceWell, except that you may find an iterator better: <% @class.enrolled_students.each do |enrolled| %> <%= enrolled.student_name %> <% end %> In you controller, you probably want to tell ActiveRecord that you''ll be using enrolled_students, but this is just for performance. It will work in the view as is. @class = Class.find(params[;id], :include => :enrolled_students) and note that I''ve subtly suggested that you don''t chain the method calls in the view (ask Google or Wikipedia about the "Law of Demeter") class EnrolledStudent def student_name self.student ? self.student.name : "anonymous" end end This lets you avoid NoMethodError exceptions if (when!) enrolled.student is nil -Rob Rob Biedenharn http://agileconsultingllc.com Rob-xa9cJyRlE0mWcWVYNo9pwxS2lgjeYSpx@public.gmane.org --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
icemage64-PkbjNfxxIARBDgjK7y7TUQ@public.gmane.org wrote:> When creating a view to display infromation obtained from a model, > should the view always get this information from the controller, or > should it get it directly from the model?Which one is simplest? I think it''s ideal when the controller sets up a single variable, such as @datagram, and then the view uses only first-level method calls on @datagram: @datagram.marbles.each do |marble| <%=h marble.name %> end Simplified eRB, of course, but you get the idea. We did not call @datagram.method.method(42).method.marbles. The model and controller should have set any parameters up for @datagram to do its job, such as provide the 42. (.each is technically a method call, but it''s more stable, and it''s essentially a part of Ruby''s core mechanics, so we give it a pass. We would not give .select{} or .inject{} the same pass!)> For example, say I have Class and Student models, and they are in a > many to many relationship via the enrolled table. Now my view wants to > display the students of a given class. Should the controller run the > query and store it in a variable (say @students) that is passed to the > view? Or, should the view just access it directly like > > <% for enrolled in @class.enrolled_students %> > <%= enrolled.student.name %>I can think of no reason to use ''for in'' in Ruby. I suspect Matz added it early, to imitate languages that must use ''for''... But your enrolled.student.name (is missing an h, and) has too many dots. I suspect that would violate something called the "Law of Demeter" if any of those dots took a "left-turn" into another high-level module. Because you will find enrolled delegating to student frequently, your code is already more dry if enrolled has a def name; student.name; end. That hides a dot in the model, which is the ultimate goal of refactoring - dense models, aggressive but sparse controller actions, and thick views with minimal Ruby method calls. The controller is like the Government. Paraphrasing Abe Lincoln, it should only do what the model and view can''t do for themselves.> I like the second way because it does not require me to put any code > in the controller. I just feel like this is coupling the view and to > the model and I can''t tell if that is a bad thing in an MVC framework? > I feel like it is.Coupling the view to the model is part of MVC. Look up one of the diagrams - I think there''s an arrow from the V to M... -- Phlip http://flea.sourceforge.net/resume.html --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
icemage64-PkbjNfxxIARBDgjK7y7TUQ@public.gmane.org
2009-Apr-19 23:34 UTC
Re: Accessing Models via Views
Thanks Philip. Your comments have helped a lot. I totally forgot about the Law of Demeter learned way back in second year CS. If I just follow that rule then I think most of my complaints about doing what I was in the view will disappear because I will only ever be using 1 level of indirection. I will have to consult the pick-axe again on the nuances of iterators. I haven''t been using them because coming from a major C/Perl style background, for is just more familiar to me. Thanks for pointing this out though, no one else has yet. As for the model <=> view in MVC, I was looking at ''Design Patterns'' and their is indeed a dotted line, where all the rest are solid lines. The book fails to distinguish the difference between the two though. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
icemage64-PkbjNfxxIARBDgjK7y7TUQ@public.gmane.org
2009-Apr-19 23:36 UTC
Re: Accessing Models via Views
Thanks as well Rob. I like how you guys gave basically the same response at the exact same time. It really shows a lot of uniformity in the community. I was honestly expecting to get a lot of flame back about ''do whatever is best'' or something to that effect. On Apr 19, 5:37 pm, Rob Biedenharn <R...-xa9cJyRlE0mWcWVYNo9pwxS2lgjeYSpx@public.gmane.org> wrote:> On Apr 19, 2009, at 4:16 PM, icemag...-PkbjNfxxIARBDgjK7y7TUQ@public.gmane.org wrote: > > > > > > > Hi > > > When creating a view to display infromation obtained from a model, > > should the view always get this information from the controller, or > > should it get it directly from the model? > > > For example, say I have Class and Student models, and they are in a > > many to many relationship via the enrolled table. Now my view wants to > > display the students of a given class. Should the controller run the > > query and store it in a variable (say @students) that is passed to the > > view? Or, should the view just access it directly like > > > <% for enrolled in @class.enrolled_students %> > > <%= enrolled.student.name %> > > > I like the second way because it does not require me to put any code > > in the controller. I just feel like this is coupling the view and to > > the model and I can''t tell if that is a bad thing in an MVC framework? > > I feel like it is. > > > Thanks in advance > > Well, except that you may find an iterator better: > > <% @class.enrolled_students.each do |enrolled| %> > <%= enrolled.student_name %> > <% end %> > > In you controller, you probably want to tell ActiveRecord that you''ll > be using enrolled_students, but this is just for performance. It will > work in the view as is. > > @class = Class.find(params[;id], :include => :enrolled_students) > > and note that I''ve subtly suggested that you don''t chain the method > calls in the view (ask Google or Wikipedia about the "Law of Demeter") > > class EnrolledStudent > def student_name > self.student ? self.student.name : "anonymous" > end > end > > This lets you avoid NoMethodError exceptions if (when!) > enrolled.student is nil > > -Rob > > Rob Biedenharn http://agileconsultingllc.com > R...-xa9cJyRlE0mWcWVYNo9pwxS2lgjeYSpx@public.gmane.org--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I tend to prefer code like: @class.enrolled_students.each do |student| student.name end as Philip mentioned. Enrolled students, if I understand your model(s) correctly, are just a specialized set of students. Not dropped_students, or withdrawn_students, or waitlisted_students, or students_on_hiatus, but those currently enrolled in the class. The ".each do |call it whatever|" gives you the chance to map the ''enrolled_students'' back to their source, and pretty much anyone reading the code will make the leap (however small) that ''name'' is an attribute or method of the ''student'' class. -- Posted via http://www.ruby-forum.com/.
Ar Chron wrote:> I tend to prefer code like: > > @class.enrolled_students.each do |student| > student.name > end > > as Phlip mentioned.Tx - it reminded me to write up "Contractive Delegation" here: http://broadcast.oreilly.com/2009/04/contractive-delegation.html I heard the term from an old Smalltalker, and it stuck... -- Phlip http://flea.sourceforge.net/resume.html