I''m working on a small project with a friend, and one of the things we needed to do was send off an email whenever someone signs up an account. His implementation was pretty simple - throw a deliver_welcome call inside the controller after the signup. I''m sure that this is a pretty common thing to do. The problem, in my mind, was that the app now became tied to two places - the controller and model - for handling business logic. What do I mean? Well if I open script/console and do Account.register(...) Then no email is sent. According to our business rules, a welcome email should be delivered whenever an account is registered. With his implementation, the only way to correctly register an account is to do it through the controller. So what do you guys think about this? In my opinion I should only have to type one command in console to make everything happen (Account.register), and the controller should call the exact same code, and only set up page info, error messages, etc. One thing I''d like to point out is that if I send the email from within Account.register, now the Account class gets tied to ActionMailer and ActionPack. That seems pretty crappy too, really, and I actually posted about that maybe a month ago. My solution was to create a new Message model and have a separate app occasionally poll the db to mail out messages, using the account_id to build the message. To boil it down, do you think you should be able to manage your application 100% through your domain model if you so desire? Pat
Your register method is a business logic and shouldn''t be in the model. The model is usually only for storing and retrieving data. The simple fact that you want an email to go out after someone registers is further implication that the register method is business logic. Chris -----Original Message----- From: rails-bounces@lists.rubyonrails.org [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox Sent: Thursday, May 04, 2006 3:19 PM To: Rails Mailing List Subject: [Rails] Should controllers be "smart"? I''m working on a small project with a friend, and one of the things we needed to do was send off an email whenever someone signs up an account. His implementation was pretty simple - throw a deliver_welcome call inside the controller after the signup. I''m sure that this is a pretty common thing to do. The problem, in my mind, was that the app now became tied to two places - the controller and model - for handling business logic. What do I mean? Well if I open script/console and do Account.register(...) Then no email is sent. According to our business rules, a welcome email should be delivered whenever an account is registered. With his implementation, the only way to correctly register an account is to do it through the controller. So what do you guys think about this? In my opinion I should only have to type one command in console to make everything happen (Account.register), and the controller should call the exact same code, and only set up page info, error messages, etc. One thing I''d like to point out is that if I send the email from within Account.register, now the Account class gets tied to ActionMailer and ActionPack. That seems pretty crappy too, really, and I actually posted about that maybe a month ago. My solution was to create a new Message model and have a separate app occasionally poll the db to mail out messages, using the account_id to build the message. To boil it down, do you think you should be able to manage your application 100% through your domain model if you so desire? Pat _______________________________________________ Rails mailing list Rails@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails
Noooo! Model-View-Controller architecture wants you to put your business logic into the controller. Chris -----Original Message----- From: rails-bounces@lists.rubyonrails.org [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox Sent: Thursday, May 04, 2006 4:29 PM To: rails@lists.rubyonrails.org Subject: Re: [Rails] Should controllers be "smart"? I know that the register method is business logic, which is why I put it in the model. Isn''t that where the business logic is supposed to go? Where else would you put it? Pat On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote:> > Your register method is a business logic and shouldn''t be in themodel.> The model is usually only for storing and retrieving data. > > The simple fact that you want an email to go out after someoneregisters> is further implication that the register method is business logic. > > > > Chris > > > > -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox > Sent: Thursday, May 04, 2006 3:19 PM > To: Rails Mailing List > Subject: [Rails] Should controllers be "smart"? > > I''m working on a small project with a friend, and one of the things we > needed to do was send off an email whenever someone signs up an > account. His implementation was pretty simple - throw a > deliver_welcome call inside the controller after the signup. I''m sure > that this is a pretty common thing to do. > > The problem, in my mind, was that the app now became tied to two > places - the controller and model - for handling business logic. What > do I mean? Well if I open script/console and do > > Account.register(...) > > Then no email is sent. According to our business rules, a welcome > email should be delivered whenever an account is registered. With his > implementation, the only way to correctly register an account is to do > it through the controller. > > So what do you guys think about this? In my opinion I should only > have to type one command in console to make everything happen > (Account.register), and the controller should call the exact same > code, and only set up page info, error messages, etc. > > One thing I''d like to point out is that if I send the email from > within Account.register, now the Account class gets tied to > ActionMailer and ActionPack. That seems pretty crappy too, really, > and I actually posted about that maybe a month ago. My solution was > to create a new Message model and have a separate app occasionally > poll the db to mail out messages, using the account_id to build the > message. > > To boil it down, do you think you should be able to manage your > application 100% through your domain model if you so desire? > > Pat > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >_______________________________________________ Rails mailing list Rails@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails
I know that the register method is business logic, which is why I put it in the model. Isn''t that where the business logic is supposed to go? Where else would you put it? Pat On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote:> > Your register method is a business logic and shouldn''t be in the model. > The model is usually only for storing and retrieving data. > > The simple fact that you want an email to go out after someone registers > is further implication that the register method is business logic. > > > > Chris > > > > -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox > Sent: Thursday, May 04, 2006 3:19 PM > To: Rails Mailing List > Subject: [Rails] Should controllers be "smart"? > > I''m working on a small project with a friend, and one of the things we > needed to do was send off an email whenever someone signs up an > account. His implementation was pretty simple - throw a > deliver_welcome call inside the controller after the signup. I''m sure > that this is a pretty common thing to do. > > The problem, in my mind, was that the app now became tied to two > places - the controller and model - for handling business logic. What > do I mean? Well if I open script/console and do > > Account.register(...) > > Then no email is sent. According to our business rules, a welcome > email should be delivered whenever an account is registered. With his > implementation, the only way to correctly register an account is to do > it through the controller. > > So what do you guys think about this? In my opinion I should only > have to type one command in console to make everything happen > (Account.register), and the controller should call the exact same > code, and only set up page info, error messages, etc. > > One thing I''d like to point out is that if I send the email from > within Account.register, now the Account class gets tied to > ActionMailer and ActionPack. That seems pretty crappy too, really, > and I actually posted about that maybe a month ago. My solution was > to create a new Message model and have a separate app occasionally > poll the db to mail out messages, using the account_id to build the > message. > > To boil it down, do you think you should be able to manage your > application 100% through your domain model if you so desire? > > Pat > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
One of the things that DHH always talks about is having a rich domain model. This is why we have stuff like validations, associations, etc all being inside the model. I''ve actually never really understood the point of the controller. Everywhere I''ve read says that the business logic goes in the model, and the controller just connects it to the view. Maybe I''m just confused. If business logic goes in the controller, how are you supposed to modify the application other than by using a web interface? Pat On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote:> Noooo! > > Model-View-Controller architecture wants you to put your business logic > into the controller. > > > > Chris > > > -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox > Sent: Thursday, May 04, 2006 4:29 PM > To: rails@lists.rubyonrails.org > Subject: Re: [Rails] Should controllers be "smart"? > > I know that the register method is business logic, which is why I put > it in the model. Isn''t that where the business logic is supposed to > go? Where else would you put it? > > Pat > > On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote: > > > > Your register method is a business logic and shouldn''t be in the > model. > > The model is usually only for storing and retrieving data. > > > > The simple fact that you want an email to go out after someone > registers > > is further implication that the register method is business logic. > > > > > > > > Chris > > > > > > > > -----Original Message----- > > From: rails-bounces@lists.rubyonrails.org > > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox > > Sent: Thursday, May 04, 2006 3:19 PM > > To: Rails Mailing List > > Subject: [Rails] Should controllers be "smart"? > > > > I''m working on a small project with a friend, and one of the things we > > needed to do was send off an email whenever someone signs up an > > account. His implementation was pretty simple - throw a > > deliver_welcome call inside the controller after the signup. I''m sure > > that this is a pretty common thing to do. > > > > The problem, in my mind, was that the app now became tied to two > > places - the controller and model - for handling business logic. What > > do I mean? Well if I open script/console and do > > > > Account.register(...) > > > > Then no email is sent. According to our business rules, a welcome > > email should be delivered whenever an account is registered. With his > > implementation, the only way to correctly register an account is to do > > it through the controller. > > > > So what do you guys think about this? In my opinion I should only > > have to type one command in console to make everything happen > > (Account.register), and the controller should call the exact same > > code, and only set up page info, error messages, etc. > > > > One thing I''d like to point out is that if I send the email from > > within Account.register, now the Account class gets tied to > > ActionMailer and ActionPack. That seems pretty crappy too, really, > > and I actually posted about that maybe a month ago. My solution was > > to create a new Message model and have a separate app occasionally > > poll the db to mail out messages, using the account_id to build the > > message. > > > > To boil it down, do you think you should be able to manage your > > application 100% through your domain model if you so desire? > > > > Pat > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
I am sure many people have different opinions about this, however in the strictest sense business logic belongs in the controller. Along with the strictness in mind, some people would argue if validation is business logic or part of the data model. But I would guess that a "rich domain model" means all the things needed to maintain data integrity and, in some cases, to make it easy to get things out of the data model (by using associations) should be in the model. But in most cases, associations and validations are common across all business logic, so it makes great sense to put those in the data layer. But a controller is indeed for business logic. Controllers aren''t only for web access, although they are strongly tied to it in this framework because it IS a web framework, they can "speak" xml, soap, xml-rpc, and a host of other ways to allow other applications access through your controller. Let''s assume that you left your register method inside your Accounts model. Let''s further assume you just bought up Company xyz and you are going to take all of their web users and integrate them into your site. So would you still use your register method with your standard email that says "Thanks for registering on our website..."? This might confuse people because, after all, they didn''t register, they were added by you. So your business logic to register these new clients, would be different than if a client registered from your existing website. You would probably want to send them a special email that says "We just bought Company xyz and since you were registered on xyz site, we have seamlessly integrated your account into our site, simple use your same username and password and login here". It''s obvious that this is an oversimplified "what-if", but you get the idea--I hope? Also, I couldn''t possibly imagine that DHH (please chime in at anytime) would advocate NOT using controllers furthermore continue to develop something that was deemed useless. I think you are getting a little bogged down in theory and over analyzing these things. You should look at what other projects have done. You can download the source to typo or a host of other rails apps to see what is common practice. Chris -----Original Message----- From: rails-bounces@lists.rubyonrails.org [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox Sent: Thursday, May 04, 2006 4:50 PM To: rails@lists.rubyonrails.org Subject: Re: [Rails] Should controllers be "smart"? One of the things that DHH always talks about is having a rich domain model. This is why we have stuff like validations, associations, etc all being inside the model. I''ve actually never really understood the point of the controller. Everywhere I''ve read says that the business logic goes in the model, and the controller just connects it to the view. Maybe I''m just confused. If business logic goes in the controller, how are you supposed to modify the application other than by using a web interface? Pat On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote:> Noooo! > > Model-View-Controller architecture wants you to put your businesslogic> into the controller. > > > > Chris > > > -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox > Sent: Thursday, May 04, 2006 4:29 PM > To: rails@lists.rubyonrails.org > Subject: Re: [Rails] Should controllers be "smart"? > > I know that the register method is business logic, which is why I put > it in the model. Isn''t that where the business logic is supposed to > go? Where else would you put it? > > Pat > > On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote: > > > > Your register method is a business logic and shouldn''t be in the > model. > > The model is usually only for storing and retrieving data. > > > > The simple fact that you want an email to go out after someone > registers > > is further implication that the register method is business logic. > > > > > > > > Chris > > > > > > > > -----Original Message----- > > From: rails-bounces@lists.rubyonrails.org > > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Pat Maddox > > Sent: Thursday, May 04, 2006 3:19 PM > > To: Rails Mailing List > > Subject: [Rails] Should controllers be "smart"? > > > > I''m working on a small project with a friend, and one of the thingswe> > needed to do was send off an email whenever someone signs up an > > account. His implementation was pretty simple - throw a > > deliver_welcome call inside the controller after the signup. I''msure> > that this is a pretty common thing to do. > > > > The problem, in my mind, was that the app now became tied to two > > places - the controller and model - for handling business logic.What> > do I mean? Well if I open script/console and do > > > > Account.register(...) > > > > Then no email is sent. According to our business rules, a welcome > > email should be delivered whenever an account is registered. Withhis> > implementation, the only way to correctly register an account is todo> > it through the controller. > > > > So what do you guys think about this? In my opinion I should only > > have to type one command in console to make everything happen > > (Account.register), and the controller should call the exact same > > code, and only set up page info, error messages, etc. > > > > One thing I''d like to point out is that if I send the email from > > within Account.register, now the Account class gets tied to > > ActionMailer and ActionPack. That seems pretty crappy too, really, > > and I actually posted about that maybe a month ago. My solution was > > to create a new Message model and have a separate app occasionally > > poll the db to mail out messages, using the account_id to build the > > message. > > > > To boil it down, do you think you should be able to manage your > > application 100% through your domain model if you so desire? > > > > Pat > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >_______________________________________________ Rails mailing list Rails@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails
On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote:> I am sure many people have different opinions about this, however in the > strictest sense business logic belongs in the controller. Along with > the strictness in mind, some people would argue if validation is > business logic or part of the data model. But I would guess that a > "rich domain model" means all the things needed to maintain data > integrity and, in some cases, to make it easy to get things out of the > data model (by using associations) should be in the model. But in most > cases, associations and validations are common across all business > logic, so it makes great sense to put those in the data layer.We''re not dealing with MVC in the strictest sense though, are we? We''re dealing with it in the Rails sense. Does that change anything?> But a controller is indeed for business logic. Controllers aren''t only > for web access, although they are strongly tied to it in this framework > because it IS a web framework, they can "speak" xml, soap, xml-rpc, and > a host of other ways to allow other applications access through your > controller.Okay so if I wanted to easily manage my app through the console, what would be the best way to do this? Do I create a web services interface?> Let''s assume that you left your register method inside your Accounts > model. Let''s further assume you just bought up Company xyz and you are > going to take all of their web users and integrate them into your site. > So would you still use your register method with your standard email > that says "Thanks for registering on our website..."? This might > confuse people because, after all, they didn''t register, they were added > by you. So your business logic to register these new clients, would be > different than if a client registered from your existing website. You > would probably want to send them a special email that says "We just > bought Company xyz and since you were registered on xyz site, we have > seamlessly integrated your account into our site, simple use your same > username and password and login here". It''s obvious that this is an > oversimplified "what-if", but you get the idea--I hope?I kind of don''t...the business logic changed. I''m going to have to change my code around whether it''s in the controller or the model. As you said, this is a very simplified example, and in this case it''s just a case of sending a different email, so it''s not clear to me why it''d be preferable to keep that logic in the controller.> I think you are getting a little bogged down in theory and over > analyzing these things. You should look at what other projects have > done. You can download the source to typo or a host of other rails apps > to see what is common practice.Will do. Thanks for discussing this with me. I thought I had it down, but apparently I''m very confused. Pat
Uhhh this is absolutly positively wrong. On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote:> > Your register method is a business logic and shouldn''t be in the model. > The model is usually only for storing and retrieving data. > > The simple fact that you want an email to go out after someone registers > is further implication that the register method is business logic. > >Business logic belongs into the model unless its http related. In the case of sending an email after a signup i think the controller is the correct please to put this code. In a sense writing a email as part of a signup procedure is directly tied to http, you wouldn''t send the user a email when you create him on the console for instance. However i would put the call to send the email in the model. My user models usually have a method like user.deliver_welcome_email which just delegates to the UserMailer. This keeps the logic in the model but makes it explicit. -- Tobi http://shopify.com - modern e-commerce software http://typo.leetsoft.com - Open source weblog engine http://blog.leetsoft.com - Technical weblog
Hey, after doing some light research on this issue, here what I was able to find "Head First: Design Patterns" from page 559: Q: Does the controller ever implement any application logic? A: No, the controller implements behavior for the view. It is the smarts that translates the actions from the view to actions on on the model. The model takes those actions and implements the application logic to decide what to do in response to those actions. The controller might have to do a little work to determine what methods calls to make on the model, but that''s not considered the "application logic". The application logic is the code that manages and manipulates your data and it lives in the model. -Conrad On 5/4/06, Pat Maddox <pergesu@gmail.com> wrote:> > On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote: > > I am sure many people have different opinions about this, however in the > > strictest sense business logic belongs in the controller. Along with > > the strictness in mind, some people would argue if validation is > > business logic or part of the data model. But I would guess that a > > "rich domain model" means all the things needed to maintain data > > integrity and, in some cases, to make it easy to get things out of the > > data model (by using associations) should be in the model. But in most > > cases, associations and validations are common across all business > > logic, so it makes great sense to put those in the data layer. > > We''re not dealing with MVC in the strictest sense though, are we? > We''re dealing with it in the Rails sense. Does that change anything? > > > > But a controller is indeed for business logic. Controllers aren''t only > > for web access, although they are strongly tied to it in this framework > > because it IS a web framework, they can "speak" xml, soap, xml-rpc, and > > a host of other ways to allow other applications access through your > > controller. > > Okay so if I wanted to easily manage my app through the console, what > would be the best way to do this? Do I create a web services > interface? > > > > Let''s assume that you left your register method inside your Accounts > > model. Let''s further assume you just bought up Company xyz and you are > > going to take all of their web users and integrate them into your site. > > So would you still use your register method with your standard email > > that says "Thanks for registering on our website..."? This might > > confuse people because, after all, they didn''t register, they were added > > by you. So your business logic to register these new clients, would be > > different than if a client registered from your existing website. You > > would probably want to send them a special email that says "We just > > bought Company xyz and since you were registered on xyz site, we have > > seamlessly integrated your account into our site, simple use your same > > username and password and login here". It''s obvious that this is an > > oversimplified "what-if", but you get the idea--I hope? > > I kind of don''t...the business logic changed. I''m going to have to > change my code around whether it''s in the controller or the model. As > you said, this is a very simplified example, and in this case it''s > just a case of sending a different email, so it''s not clear to me why > it''d be preferable to keep that logic in the controller. > > > > I think you are getting a little bogged down in theory and over > > analyzing these things. You should look at what other projects have > > done. You can download the source to typo or a host of other rails apps > > to see what is common practice. > > Will do. Thanks for discussing this with me. I thought I had it > down, but apparently I''m very confused. > > Pat > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060505/b34d1e64/attachment.html
On 5/4/06, Tobias L?tke <tobias.luetke@gmail.com> wrote:> Uhhh this is absolutly positively wrong. > > On 5/4/06, Chris Bruce <cbruce@sleeter.com> wrote: > > > > Your register method is a business logic and shouldn''t be in the model. > > The model is usually only for storing and retrieving data. > > > > The simple fact that you want an email to go out after someone registers > > is further implication that the register method is business logic. > > > > > > Business logic belongs into the model unless its http related. > > In the case of sending an email after a signup i think the controller > is the correct please to put this code. In a sense writing a email as > part of a signup procedure is directly tied to http, you wouldn''t send > the user a email when you create him on the console for instance. > > However i would put the call to send the email in the model. My user > models usually have a method like user.deliver_welcome_email which > just delegates to the UserMailer. This keeps the logic in the model > but makes it explicit. > > > > -- > Tobi > http://shopify.com - modern e-commerce software > http://typo.leetsoft.com - Open source weblog engine > http://blog.leetsoft.com - Technical weblog > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >Keeping with the welcome email example, would you then just make your model a bit more fine-grained? # controller code u = User.register(...) u.deliver_welcome_email I don''t know, I''d still stick the email delivery call inside User.register. All it does is create the user and deliver the email. If you don''t want to send the email, just call User.create instead. Pat
> Keeping with the welcome email example, would you then just make your > model a bit more fine-grained? > > # controller code > u = User.register(...) > u.deliver_welcome_email > > > I don''t know, I''d still stick the email delivery call inside > User.register. All it does is create the user and deliver the email. > If you don''t want to send the email, just call User.create instead.It depends on your requirements, if you have some situations where you may want to create them without delivering, I''d do it like tobi has there. However, I can say that we currently send our welcome emails from our equivalent of ''User.register'' -- Cheers Koz
On May 4, 2006, at 6:19 PM, Pat Maddox wrote:> > One thing I''d like to point out is that if I send the email from > within Account.register, now the Account class gets tied to > ActionMailer and ActionPack. That seems pretty crappy too, really, > and I actually posted about that maybe a month ago. My solution was > to create a new Message model and have a separate app occasionally > poll the db to mail out messages, using the account_id to build the > message.You could put the delivery in an observer that fires on create. This way it''s not tightly coupled to the model, and if you want to create accounts without firing off email, just don''t instantiate the observer.> > To boil it down, do you think you should be able to manage your > application 100% through your domain model if you so desire?Absolutely -Scott
Ok, Sorry for the confusion. The others are absolutely right. I have translated the traditional 3-tired architecture (data layer, business layer, presentation layer) right into the MVC pattern. This is completely incorrect. Prior to ORM tools and the like, I would typically create my classes to be data (direct calls to from database), business (handles all business specific functions and calls the data object), and presentation jsp/php, etc. I somehow associated that as being the same as MVC. Sorry, Chris -----Original Message----- From: rails-bounces@lists.rubyonrails.org [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Michael Koziarski Sent: Thursday, May 04, 2006 6:29 PM To: rails@lists.rubyonrails.org Subject: Re: [Rails] Should controllers be "smart"?> Keeping with the welcome email example, would you then just make your > model a bit more fine-grained? > > # controller code > u = User.register(...) > u.deliver_welcome_email > > > I don''t know, I''d still stick the email delivery call inside > User.register. All it does is create the user and deliver the email. > If you don''t want to send the email, just call User.create instead.It depends on your requirements, if you have some situations where you may want to create them without delivering, I''d do it like tobi has there. However, I can say that we currently send our welcome emails from our equivalent of ''User.register'' -- Cheers Koz _______________________________________________ Rails mailing list Rails@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails
+1 to what Tobias said. The Rails approach to MVC is to push a lot of things down into the model. Whether or not you think this is the right way to do things (which, for the record, I don''t), you shouldn''t try to fight it when developing Rails code. Here''s an example from some code I''ve been working on lately to illustrate the point: I hate dropdowns, so I don''t want to use the standard date picker for a date field on my model. I''d rather have a text field and parse the date, but this obviously requires validation. So, here''s the code from my model: (Just take date_is_valid? and parse_date as givens for now.) attr_writer :date_as_text def date_as_text @date_as_text ||= (date && date.strftime(''%d %b %Y'') end validate :validate_date_as_text def validate_date_as_text if @date_as_text if date_is_valid?(@date_as_text) self.date = parse_date(@date_as_text) else errors.add(''date'', must be a valid date'') end end end "But wait!", I hear you cry, "Why are you doing this in your model? It''s clearly a user interface issue, and belongs elsewhere!" In theory, you''re absolutely right. In practice, Rails puts all validations in the model and you''re best not to fight it. Here''s what happens if I try to handle the date_as_text field in the controller: def new @my_model = MyModel.new if request.post? date_is_valid = date_is_valid?(params[:date_as_text]) @my_model.date = parse_date(params[:date_as_text]) if date_is_valid if @my_model.valid? and date_is_valid @my_model.save else @my_model.errors.add(''date'', ''must be a valid date'') unless date_is_valid end end end I feel like I''m fighting Rails to pull this off. I''ve got to run the model validations manually. I''ve got to push errors from the controller back into the model so that they can be passed to the view, and I''ve got to be careful to do it after I do the save. I can''t really have model validations for the date field too, because then the user might see multiple, conflicting errors for the one field. Editing a record requires more code, because I have to grab the date and convert it to text before displaying the form. So, as much as I believe that code like this should live in the view/ controller, it''s not worth fighting the Rails way of doing things to make my ideological point. :) Pete Yandell http://9cays.com On 05/05/2006, at 11:05 AM, Tobias L?tke wrote:> > Business logic belongs into the model unless its http related. > > In the case of sending an email after a signup i think the controller > is the correct please to put this code. In a sense writing a email as > part of a signup procedure is directly tied to http, you wouldn''t send > the user a email when you create him on the console for instance. > > However i would put the call to send the email in the model. My user > models usually have a method like user.deliver_welcome_email which > just delegates to the UserMailer. This keeps the logic in the model > but makes it explicit. > > > > -- > Tobi > http://shopify.com - modern e-commerce software > http://typo.leetsoft.com - Open source weblog engine > http://blog.leetsoft.com - Technical weblog > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails
Since I accept I am wrong about my (previous) MVC definition, I am wondering how you do specific business logic things in the Rails model like: If you have a register method, do you return the model AND true/false so it can be inserted back into the view if validation fails and the controller knows what view to show next? Do you pass a hash to register and call self.save inside the method? What if you are updating multiple tables and want to perform it in a transaction (common business logic). Does your register method find the other models and update/save them all in a transaction within the register method? Is it bad practice to call model.save in controllers, since they seem to be only to transfer user input/output data to/from views and models? Tobias - Is typo a good source to look at as an example of how to correctly use MVC in rails? Chris Pete Yandell wrote:> +1 to what Tobias said. > > The Rails approach to MVC is to push a lot of things down into the > model. > > Whether or not you think this is the right way to do things (which, > for the record, I don''t), you shouldn''t try to fight it when > developing Rails code. > > > Here''s an example from some code I''ve been working on lately to > illustrate the point: > > I hate dropdowns, so I don''t want to use the standard date picker for > a date field on my model. I''d rather have a text field and parse the > date, but this obviously requires validation. So, here''s the code > from my model: > > (Just take date_is_valid? and parse_date as givens for now.) > > attr_writer :date_as_text > > def date_as_text > @date_as_text ||= (date && date.strftime(''%d %b %Y'') > end > > validate :validate_date_as_text > def validate_date_as_text > if @date_as_text > if date_is_valid?(@date_as_text) > self.date = parse_date(@date_as_text) > else > errors.add(''date'', must be a valid date'') > end > end > end > > "But wait!", I hear you cry, "Why are you doing this in your model? > It''s clearly a user interface issue, and belongs elsewhere!" > > In theory, you''re absolutely right. In practice, Rails puts all > validations in the model and you''re best not to fight it. > > Here''s what happens if I try to handle the date_as_text field in the > controller: > > def new > @my_model = MyModel.new > if request.post? > date_is_valid = date_is_valid?(params[:date_as_text]) > @my_model.date = parse_date(params[:date_as_text]) if > date_is_valid > if @my_model.valid? and date_is_valid > @my_model.save > else > @my_model.errors.add(''date'', ''must be a valid date'') unless > date_is_valid > end > end > end > > I feel like I''m fighting Rails to pull this off. I''ve got to run the > model validations manually. I''ve got to push errors from the > controller back into the model so that they can be passed to the > view, and I''ve got to be careful to do it after I do the save. I > can''t really have model validations for the date field too, because > then the user might see multiple, conflicting errors for the one > field. Editing a record requires more code, because I have to grab > the date and convert it to text before displaying the form. > > > So, as much as I believe that code like this should live in the view/ > controller, it''s not worth fighting the Rails way of doing things to > make my ideological point. :) > > Pete Yandell > http://9cays.com > > > On 05/05/2006, at 11:05 AM, Tobias L?tke wrote:-- Posted via http://www.ruby-forum.com/.
> Tobias - Is typo a good source to look at as an example of how to > correctly use MVC in rails?I''d be interested in hearing the "correct" way to do things too. I''ve read the Agile... book but it still left me with some architectural "greyness" about RoR, which I why I balked and did my last project in straight-up, procedural PHP. *ducks*
So, I was looking through the typo code and have a question. It looks (and I might be way off) that the models (I looked mostly at blog.rb) seem pretty tightly coupled to the overall web appication. Is this correct? I was under the impression that your models should be as independent of a specific application as possible or am I way off base here? I thought your models should enforce business rules, like can''t take out more money than you have in your account, etc. I was thinking a good test would be if you can take your existing models and use it to build say a stand-alone application with little or no modification--that means your models are well designed. Is this the completely wrong assumption of what the M is in MVC?? Thanks, Chris gravy face wrote:>> Tobias - Is typo a good source to look at as an example of how to >> correctly use MVC in rails? > > I''d be interested in hearing the "correct" way to do things too. I''ve > read the Agile... book but it still left me with some architectural > "greyness" about RoR, which I why I balked and did my last project in > straight-up, procedural PHP. > > *ducks*-- Posted via http://www.ruby-forum.com/.
On 5/5/06, Chris Bruce <cbruce@sleeter.com> wrote:> > So, I was looking through the typo code and have a question. It looks > (and I might be way off) that the models (I looked mostly at blog.rb) > seem pretty tightly coupled to the overall web appication. Is this > correct? I was under the impression that your models should be as > independent of a specific application as possible or am I way off base > here? I thought your models should enforce business rules, like can''t > take out more money than you have in your account, etc. I was thinking a > good test would be if you can take your existing models and use it to > build say a stand-alone application with little or no modification--that > means your models are well designed. Is this the completely wrong > assumption of what the M is in MVC??You could have a mix of models that are application specific and some that are not. But your application logic belongs in the model 1) because it''s easier to write it that way 2) because then you can reuse that logic in different controller/view combinations. In theory you should be able to build a new user interface that reuses your models to implement the same application logic. The controller handles the conversation between the views and the models and handles the "control flow" logic i.e. what screen to show next after we''ve done with this one. That''s how I make sense of it all. cheers, Ben -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060505/e7a265fe/attachment.html
I''d keep them separate User.register(...) is not called User.register_and_deliver_welcome_email(...) I try and factor each method so it has one simple task (laziness tends to get in the way). If your find that your repeating yourself then I''d create a higher level helper method such as User.register_and_deliver_welcome_email(...) Decoupling the email action from the registration action would provide greater flexibility in the model as Koz mentions it does all depend on individual requirements and/or tastes. Ross> -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org]On Behalf Of Michael > Koziarski > Sent: Friday, 5 May 2006 11:29 AM > To: rails@lists.rubyonrails.org > Subject: Re: [Rails] Should controllers be "smart"? > > > > Keeping with the welcome email example, would you then just > make your > > model a bit more fine-grained? > > > > # controller code > > u = User.register(...) > > u.deliver_welcome_email > > > > > > I don''t know, I''d still stick the email delivery call inside > > User.register. All it does is create the user and deliver > the email. > > If you don''t want to send the email, just call User.create instead. > > It depends on your requirements, if you have some situations where > you may want to create them without delivering, I''d do it like tobi > has there. > > However, I can say that we currently send our welcome emails from our > equivalent of ''User.register'' > > > > > -- > Cheers > > Koz > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
I think that type of DATA validation should go in your model as you have it. Validating a date format has nothing to do with your interface (view) and nothing to do with the application logic (controller). I think there is a difference between what people call "business logic" and "application logic". Business logic is the stuff you need regardless of the framework you are using. This includes your data model and data validation RULES. It''s all the rules you would follow even if your business ran on paper and filing cabinets. Application logic is the stuff that may change depending on the framework you are using. This is your controller and it glues the backend to the front-end, deciding which views to show and which models to send messages too. On 5/4/06 10:22 PM, "Pete Yandell" <pete@notahat.com> wrote:> I hate dropdowns, so I don''t want to use the standard date picker for > a date field on my model. I''d rather have a text field and parse the > date, but this obviously requires validation. So, here''s the code > from my model: > > (Just take date_is_valid? and parse_date as givens for now.) > > attr_writer :date_as_text > > def date_as_text > @date_as_text ||= (date && date.strftime(''%d %b %Y'') > end > > validate :validate_date_as_text > def validate_date_as_text > if @date_as_text > if date_is_valid?(@date_as_text) > self.date = parse_date(@date_as_text) > else > errors.add(''date'', must be a valid date'') > end > end > end > > "But wait!", I hear you cry, "Why are you doing this in your model? > It''s clearly a user interface issue, and belongs elsewhere!" > > In theory, you''re absolutely right. In practice, Rails puts all > validations in the model and you''re best not to fight it.
Ok so how would the register method look in the following: User has_many :addresses validates_presence_of_one_address # <- Say some custom validation to require one address Address belongs_to :user validates_presence_of :address, :city, :state, :zip validate_zip_code # <- Say some custom validation to lookup zipcode Business RULE: User must have at least one address. Address must have valid zip code plus address, city, state, zip. My web form: Fields for User Information, including TWO addresses (one for shipping, and mailing). So according to the idea the model should have all business rules and logic... User.register should save the user info AND adresses, right? So what if an address validation fails. How does controller know which address failed, and what the errors. Can you show me how the User.register method would look in this case? Chris Ross Dawson wrote:> I''d keep them separate > > User.register(...) is not called > User.register_and_deliver_welcome_email(...) > > I try and factor each method so it has one simple task (laziness tends > to get in the way). If your find that your repeating yourself then I''d > create a higher level helper method such as > User.register_and_deliver_welcome_email(...) > > Decoupling the email action from the registration action would provide > greater flexibility in the model > > as Koz mentions it does all depend on individual requirements and/or > tastes. > > Ross-- Posted via http://www.ruby-forum.com/.
On 5/5/06, Chris Bruce <cbruce@sleeter.com> wrote:> Ok so how would the register method look in the following: > validate_zip_code # <- Say some custom validation to lookup zipcodeTo me, things like zip code validation, email validation, etc. would be a Helper.
Your register could save everything if you want it to. Just depends on how course-grained you want it to be. The real point is that even if you don''t write a register method to handle everything, the business logic is still available entirely from the model. u = logged_in_user u.shipping_address = Address.new(params[:shipping]) u.billing_address = Address.new(params[:billing]) u.save Now obviously this snippet requires some code from the controller (it uses our helper method logged_in_user and params), but it''s not coupled to the controller. You could open the console and set a billing address. You could write a standalone app that uses the model to do this. The controller is handling application logic - figuring out what objects to use, methods to call, order in which to call them - but the business logic belongs to the model. Finally, to answer your question about how to handle errors, it seems pretty simple to me. u = User.register(User.new(params[:user]), Address.new(params[:shipping]), Address.new(params[:billing]) if u.save redirect_to success_url else @shipping = u.shipping_address @billing = u.billing_address end class User belongs_to :shipping_address, :foreign_key => ''shipping_address'', :class => :address belongs_to :billing_address, :foreign_key => ''billing_address'', :class => :address validates_associated :shipping_address validates_associated :billing_address def self.register(u, shipping, billing) u.shipping = shipping u.billing = billing u end end Throw a validates_associated in your User model, which will validate the two addresses and add errors if validation fails. Then assign those to the instance variables, which will populate your forms and show any errors. My example SUCKS of course, to be passing in a user and then returning it, but I''m just trying to show you that you can write a coarse-grained register method and still use the nice rails error handling. Pat On 5/5/06, Chris Bruce <cbruce@sleeter.com> wrote:> Ok so how would the register method look in the following: > > User > has_many :addresses > validates_presence_of_one_address # <- Say some custom validation to > require one address > > Address > belongs_to :user > validates_presence_of :address, :city, :state, :zip > validate_zip_code # <- Say some custom validation to lookup zipcode > > Business RULE: > User must have at least one address. > Address must have valid zip code plus address, city, state, zip. > > My web form: > Fields for User Information, including TWO addresses (one for shipping, > and mailing). > > So according to the idea the model should have all business rules and > logic... > > User.register should save the user info AND adresses, right? > > So what if an address validation fails. How does controller know which > address failed, and what the errors. Can you show me how the > User.register method would look in this case? > > > > Chris > > > Ross Dawson wrote: > > I''d keep them separate > > > > User.register(...) is not called > > User.register_and_deliver_welcome_email(...) > > > > I try and factor each method so it has one simple task (laziness tends > > to get in the way). If your find that your repeating yourself then I''d > > create a higher level helper method such as > > User.register_and_deliver_welcome_email(...) > > > > Decoupling the email action from the registration action would provide > > greater flexibility in the model > > > > as Koz mentions it does all depend on individual requirements and/or > > tastes. > > > > Ross > > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >