Should models call action mailers, or should those calls always originate from controllers? For example, should user.forgot_password send the email, or should the user_controller.forgot_password? Just looking for some opinions... Thanks, Tom
TomRossi7 wrote:> Should models call action mailers, or should those calls always > originate from controllers? For example, should user.forgot_password > send the email, or should the user_controller.forgot_password? > > Just looking for some opinions... > > Thanks, > TomTom, While not knowing your problem domain at all, I have a preference for thin dumb controllers (that fit easily within REST), I would move the mailer down into models/ or lib/ hth ilan -- Posted via http://www.ruby-forum.com/.
Quoting TomRossi7 <tom-5bxIUPmzHicFraO2wh7vUA@public.gmane.org>:> > Should models call action mailers, or should those calls always > originate from controllers? For example, should user.forgot_password > send the email, or should the user_controller.forgot_password? >Unless the action changes the state of a user or requires details not available through the public API of the user model, I''d put it in the controller. It is invoked by a HTML request and should (in my mind) go with the rest the HTML request logic. Unless of course it is being invoked by a cronjob or similar non-HTML request action/event. Just my $0.02USD, Jeffrey
On Aug 6, 10:43 am, TomRossi7 <t...-5bxIUPmzHicFraO2wh7vUA@public.gmane.org> wrote:> Should models call action mailers, or should those calls always > originate from controllers? For example, should user.forgot_password > send the email, or should the user_controller.forgot_password? > > Just looking for some opinions...With the caveat that I''m exactly two days into learning Ruby/Rails, I''d offer this from a purely MVC perspective. The sending of email is application functionality. The model is for business logic and data manipulation. When I think about situations like this, I consider an API. If I were developing an API that allowed a user to reset their password, would I want my code to send an email? My answer is "probably not". I''d want the application that _calls_ the API to send that email - if the developer chose to do so. That tells me that the model probably isn''t the right place. Hope that helps.
Rob Wilkerson wrote:> With the caveat that I''m exactly two days into learning Ruby/Rails, I''d > offer this from a purely MVC perspective. The sending of email is > application functionality. The model is for business logic and data > manipulation.> When I think about situations like this, I consider an API. If I were > developing an API that allowed a user to reset their password, would I > want my code to send an email? My answer is "probably not". I''d want the > application that _calls_ the API to send that email - if the developer > chose to do so. That tells me that the model probably isn''t the right > place.You just said "Dependency Inversion Principle". Look that up.
In almost every case that I''ve crossed this bridge, I''ve moved this logic down into models. I On Thu, Aug 6, 2009 at 7:43 AM, TomRossi7<tom-5bxIUPmzHicFraO2wh7vUA@public.gmane.org> wrote:> > Should models call action mailers, or should those calls always > originate from controllers? For example, should user.forgot_password > send the email, or should the user_controller.forgot_password? > > Just looking for some opinions... > > Thanks, > Tom > > >-- Robby Russell Chief Evangelist, Partner PLANET ARGON, LLC design // development // hosting w/Ruby on Rails http://planetargon.com/ http://robbyonrails.com/ http://twitter.com/planetargon aim: planetargon +1 503 445 2457 +1 877 55 ARGON [toll free] +1 815 642 4068 [fax]
Now you can see why I posted this for discussion. Two voices in my head (1) put it in the model and use dumb controllers (2) emails are related to user interaction logic and belong in the controller. On Aug 7, 9:42 am, Robby Russell <ro...-/Lcn8Y7Ot69QmPsQ1CNsNQ@public.gmane.org> wrote:> In almost every case that I''ve crossed this bridge, I''ve moved this > logic down into models. I > > On Thu, Aug 6, 2009 at 7:43 AM, TomRossi7<t...-5bxIUPmzHicFraO2wh7vUA@public.gmane.org> wrote: > > > Should models call action mailers, or should those calls always > > originate from controllers? For example, should user.forgot_password > > send the email, or should the user_controller.forgot_password? > > > Just looking for some opinions... > > > Thanks, > > Tom > > -- > Robby Russell > Chief Evangelist, Partner > > PLANET ARGON, LLC > design // development // hosting w/Ruby on Rails > > http://planetargon.com/http://robbyonrails.com/http://twitter.com/planetargon > aim: planetargon > > +1 503 445 2457 > +1 877 55 ARGON [toll free] > +1 815 642 4068 [fax]
tomrossi7 wrote:> Now you can see why I posted this for discussion. Two voices in my head > (1) put it in the model and use dumb controllers (2) emails are related to > user interaction logic and belong in the controller.Which is easier to test?
I''m not sure there is a significant difference. They are both easily tested. On Aug 7, 11:02 am, "Phlip" <phlip2...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> tomrossi7 wrote: > > Now you can see why I posted this for discussion. Two voices in my head > > (1) put it in the model and use dumb controllers (2) emails are related to > > user interaction logic and belong in the controller. > > Which is easier to test?
Note that Rails has a subtle way of stating the framework''s position on this: mailers are (by default) generated in app/models. Just sayin''. --Matt Jones On Aug 7, 9:46 am, tomrossi7 <t...-5bxIUPmzHicFraO2wh7vUA@public.gmane.org> wrote:> Now you can see why I posted this for discussion. Two voices in my > head (1) put it in the model and use dumb controllers (2) emails are > related to user interaction logic and belong in the controller. > > On Aug 7, 9:42 am, Robby Russell <ro...-/Lcn8Y7Ot69QmPsQ1CNsNQ@public.gmane.org> wrote: > > > > > In almost every case that I''ve crossed this bridge, I''ve moved this > > logic down into models. I > > > On Thu, Aug 6, 2009 at 7:43 AM, TomRossi7<t...-5bxIUPmzHicFraO2wh7vUA@public.gmane.org> wrote: > > > > Should models call action mailers, or should those calls always > > > originate from controllers? For example, should user.forgot_password > > > send the email, or should the user_controller.forgot_password? > > > > Just looking for some opinions... > > > > Thanks, > > > Tom > > > -- > > Robby Russell > > Chief Evangelist, Partner > > > PLANET ARGON, LLC > > design // development // hosting w/Ruby on Rails > > >http://planetargon.com/http://robbyonrails.com/http://twitter.com/pla... > > aim: planetargon > > > +1 503 445 2457 > > +1 877 55 ARGON [toll free] > > +1 815 642 4068 [fax]
Matt Jones wrote:> Note that Rails has a subtle way of stating the framework''s position > on this: mailers are (by default) generated in app/models. Just > sayin''.And that''s completely irrelevant to the question at hand. Of course an ActionMailer object is a model, but the OP was asking whether its deliver_* methods should be called from a controller or from another model.> > --Matt JonesBest, -- Marnen Laibow-Koser http://www.marnen.org marnen-sbuyVjPbboAdnm+yROfE0A@public.gmane.org -- Posted via http://www.ruby-forum.com/.
Hi -- On Thu, 6 Aug 2009, TomRossi7 wrote:> > Should models call action mailers, or should those calls always > originate from controllers? For example, should user.forgot_password > send the email, or should the user_controller.forgot_password? > > Just looking for some opinions...I keep the ActionMailer model files themselves in models/, where they land automatically, but then allow the controller to talk to those models as it would to any other. So I''ll put this in a controller: if params[:forgot_password] UserNotifier.deliver_pw_help(@user) else... and so on. I don''t think it''s necessary to wrap it in another layer of modeling. Controllers are allowed to be one step away from model logic, and the methods to deliver are already built into the ActionMailer models. David -- David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com Q: What''s the best way to get a really solid knowledge of Ruby? A: Come to our Ruby training in Edison, New Jersey, September 14-17! Instructors: David A. Black and Erik Kastner More info and registration: http://rubyurl.com/vmzN
Hi -- On Fri, 7 Aug 2009, Phlip wrote:> > tomrossi7 wrote: > >> Now you can see why I posted this for discussion. Two voices in my head >> (1) put it in the model and use dumb controllers (2) emails are related to >> user interaction logic and belong in the controller. > > Which is easier to test?I''m very wary of using ease of testing as a criterion for this kind of application design decision. Ease of testing generally has to do with the state of testing tools, as well as some potentially very divergent views on what makes for "easy" testing. In the case of the ActionMailer question, I don''t think either is easier. In both scenarios the test mode of ActionMailer will append the message to AM::Base.deliveries, where it can be examined. Or you can just write unit tests for the mailer itself, and then use a mock mailer in the controller and/or User model tests. David -- David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com Q: What''s the best way to get a really solid knowledge of Ruby? A: Come to our Ruby training in Edison, New Jersey, September 14-17! Instructors: David A. Black and Erik Kastner More info and registration: http://rubyurl.com/vmzN
Ilan Berci wrote:> While not knowing your problem domain at all, I have a preference for > thin dumb controllers (that fit easily within REST), I would move the > mailer down into models/ or lib/ > > hth > ilan+1 (FWIW!) Views should be dumb, Controllers thin, and Models fat. If the deliver_ call were one line, it qualifies for the Controller. But... The delivered template is itself a View. Hence it should be dumb. Hence anything powering it belongs in the _Model_, where fat things belong. -- Phlip
On Aug 7, 11:54 pm, Phlip <phlip2...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Ilan Berci wrote: > > While not knowing your problem domain at all, I have a preference for > > thin dumb controllers (that fit easily within REST), I would move the > > mailer down into models/ or lib/ > > > hth > > ilan > > +1 (FWIW!) > > Views should be dumb, Controllers thin, and Models fat. > > If the deliver_ call were one line, it qualifies for the Controller. But... > > The delivered template is itself a View. Hence it should be dumb. Hence anything > powering it belongs in the _Model_, where fat things belong. > > -- > PhlipOpinions opinions, oh my! As I guess has been the general theme of this thread, it really depends on the context in which the mailing is taking place. If its as simple as user clicking a button on your site and in turn some mail goes out, that''s controller domain. But if the mailing is part of some more complex logic (simple example: user signs up; requested name needs to be checked, perhaps an invite token counter needs to be decremented, maybe you''ll queue this ish etc, and the email goes out at the end), then you''ll call the mailer in the part of the model that handles that processing. Send an emailing is a *general enough activity* that there are no rules that say where you should do it in the MVC context.
pharrington wrote:> On Aug 7, 11:54�pm, Phlip <phlip2...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> Views should be dumb, Controllers thin, and Models fat. >> >> If the deliver_ call were one line, it qualifies for the Controller. But... >> >> The delivered template is itself a View. Hence it should be dumb. Hence anything >> powering it belongs in the _Model_, where fat things belong. >> >> -- >> � �Phlip > > > Opinions opinions, oh my! > > As I guess has been the general theme of this thread, it really > depends on the context in which the mailing is taking place. If its as > simple as user clicking a button on your site and in turn some mail > goes out, that''s controller domain. But if the mailing is part of some > more complex logic (simple example: user signs up; requested name > needs to be checked, perhaps an invite token counter needs to be > decremented, maybe you''ll queue this ish etc, and the email goes out > at the end), then you''ll call the mailer in the part of the model that > handles that processing. Send an emailing is a *general enough > activity* that there are no rules that say where you should do it in > the MVC context.My two pence worth. This is the fundamental pronciple of MVC If something needs to happen under certain circumstances then that''s business logic. It''s about autonomy A browser that it can get and send information to and from the controller but it doesn''t care about anything other than how to display the data and information it has been given and it doesn''t care what a controller does with the info after it has sent it. All the browser cares about is that it has someone to talk to that knows what it''s doing. The controller does not and should not care about how the information it sends to the browser is displayed or used. The job of the controller is to know where to get the information from and where to send it to. what happens before it gets the info and after it sends the info (to either a model or a view) is absolutely none of the controllers business at all. All a controller should need to know is what model to use to get and send what information to. The job of the model is to get data from a source, manipulate that data into a format that whatever wants to use it makes sense and send it there again what happens after it has been sent and received is nothing to do with the model. The model should know which storage engine to use but how that storage engine works internally is nothing to do with the model. Putting business logic like this into a controler is like asking a model to know how to the job of the database engine. It''s just plain wrong. Think about it. Views are meant to view data, controller control where the data is sent to and from and models model the data and determine what happens when data is in diffewrent states, databases store data and retrieve data. It''s a no brainer. What would happen if you built a rake task that did something with your data? Would you expect the task to have to know which controller and action irt should use or should it simply go get the data from a model and send that data back to the model and have evereything work as it should. James -- Posted via http://www.ruby-forum.com/.
Hi -- On Fri, 7 Aug 2009, pharrington wrote:> > On Aug 7, 11:54 pm, Phlip <phlip2...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote: >> Ilan Berci wrote: >>> While not knowing your problem domain at all, I have a preference for >>> thin dumb controllers (that fit easily within REST), I would move the >>> mailer down into models/ or lib/ >> >>> hth >>> ilan >> >> +1 (FWIW!) >> >> Views should be dumb, Controllers thin, and Models fat. >> >> If the deliver_ call were one line, it qualifies for the Controller. But... >> >> The delivered template is itself a View. Hence it should be dumb. Hence anything >> powering it belongs in the _Model_, where fat things belong. >> >> -- >> Phlip > > > Opinions opinions, oh my! > > As I guess has been the general theme of this thread, it really > depends on the context in which the mailing is taking place. If its as > simple as user clicking a button on your site and in turn some mail > goes out, that''s controller domain. But if the mailing is part of some > more complex logic (simple example: user signs up; requested name > needs to be checked, perhaps an invite token counter needs to be > decremented, maybe you''ll queue this ish etc, and the email goes out > at the end), then you''ll call the mailer in the part of the model that > handles that processing. Send an emailing is a *general enough > activity* that there are no rules that say where you should do it in > the MVC context.I agree, and I think part of the answer too is that ActionMailer *already* deals with these questions. Controllers are allowed to make use of the models'' APIs. Having a fat model philosophy doesn''t mean you can''t do this: Thing.find(params[:id]) in the controller. Similarly, given an ActionMailer model, there''s no reason at all not to use its API in the controller. If there''s more complexity to the mailing -- for example, if it has to search and filter for particular users before it emails them -- then *that* logic can be put in a model. In other words, rather than this in a controller: User.find(:all, :conditions => ["staff = ?", true]).each do |staff| Notifier.deliver_whatever(staff) end you would certainly push both the specialized find operation and the delivery into a model, so the controller could just do this: User.mail_to_staff or Notifier.notify_staff But in the simple case, where all you need to do is call a single class method of ActionMailer, there''s no reason not to just call it from the controller. David -- David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com Q: What''s the best way to get a really solid knowledge of Ruby? A: Come to our Ruby training in Edison, New Jersey, September 14-17! Instructors: David A. Black and Erik Kastner More info and registration: http://rubyurl.com/vmzN
Hi -- On Fri, 7 Aug 2009, Phlip wrote:> > Ilan Berci wrote: > >> While not knowing your problem domain at all, I have a preference for >> thin dumb controllers (that fit easily within REST), I would move the >> mailer down into models/ or lib/ >> >> hth >> ilan > > +1 (FWIW!) > > Views should be dumb, Controllers thin, and Models fat. > > If the deliver_ call were one line, it qualifies for the Controller. But... > > The delivered template is itself a View. Hence it should be dumb. Hence anything > powering it belongs in the _Model_, where fat things belong.That''s exactly what ActionMailer does: it keeps the fine-grained stuff in the model, and allows you to control it from the controller using high-level commands (class methods). I''m becoming very skeptical about the whole thin/fat thing. It''s a sound principle, and it''s served an important purpose, but as it''s purely quantitative, it doesn''t provide much real technical guidance. I''m starting to think more along the lines of "shallow" and "deep". The controller has shallow interaction with the model classes and objects; those classes and objects have a dimension of depth into the database and so forth. I''ll mull it over and report back :-) David -- David A. Black / Ruby Power and Light, LLC / http://www.rubypal.com Q: What''s the best way to get a really solid knowledge of Ruby? A: Come to our Ruby training in Edison, New Jersey, September 14-17! Instructors: David A. Black and Erik Kastner More info and registration: http://rubyurl.com/vmzN
On Aug 6, 10:43 am, TomRossi7 <t...-5bxIUPmzHicFraO2wh7vUA@public.gmane.org> wrote:> Should models call action mailers, or should those calls always > originate from controllers? For example, should user.forgot_password > send the email, or should the user_controller.forgot_password? > > Just looking for some opinions...Consider the questions this way: Are there occasions when models should call models directly? Should all model interaction only be mediated by an external controller? The answers are clearly Yes in the first instance and No in the second. Consider the entire idea of associations for just one example of model to model calls without discrete controllers being necessary or desirable. The names that you have given your examples somewhat muddy the situation, however. #forgot_password is, in my opinion, a controller type action since it handles an external state, only the user can say whether or not they have forgotten their password, which only the user can communicate to the application. However, #email_password is more likely than not a model method since the email address and password are bound to the user instance regardless of whether the user has forgotten their password or not. The fact that #email_password is an action rather than simply state is besides the point. Models may have lots of actions. In the first case one is specifying when to act, whilst in the second what to do. "When" is a question I believe best answered in a controller, whether interactive or batch. "What" is a question that really is bound to the model that provides it. So, in my conceptualisation of this situation, users_controller.forgot_password would look something like this: def forgot_password @current_user.email_password end Now, as for the matter of ALWAYS. This issue rather turns on the nature of the request I should think. If one is speaking of a single instance, as in the case of @current_user, then the approach taken above seems suitable. But, what of the case when we are dealing with collections? Say the issue was who to transmit a personalised newsletter to, given a set of criteria. In this case, does it make sense to use a model method to send the email or should a controller mediate between the set of qualified addressees and the message to send? I should think that an external controller seems more appropriate here, as the implementation of such a feature in the model would in all likelihood require a class method that would probably start to look an awful lot like a controller method. IMHO of course.