Re: [Catalyst] Reuse of controllers
On Mon, Sep 20, 2010 at 1:46 AM, David Schmidt wrote: > On Mon, Sep 20, 2010 at 4:33 AM, John Romkey > wrote: > > On Sep 19, 2010, at 10:02 PM, Pavel A. Karoukin wrote: > >> I started to play more often with Catalyst framework and found that I > often need to re-use some controllers logic. What the best DRY way to deal, > for example, with Login/Register/Forgotpassword controllers? > >> > >> I mean I created one controller for one app. For another app I am doing > I need to recreate everything, which ends up in plain copy/pasting and > changing class names. I do not like this, this doesn't feel DRY. Is there > some better way? Something plugable and unplugable with their own > models/controller/view may be? > > > > One approach is to simply inherit from the controller you want to reuse. > So, package up the controllers you want to reuse together, then use Moose to > extend them in the controller modules in each app that uses them. That > allows you quite a bit of flexibility; use a common convention for the start > of the dispatch chain (for instance, 'base') for each controller and then > your subclass can map its parent controller to whatever path is best for > each app. > >- john romkey > >http://www.romkey.com/ > > > > > > ___ > > List: Catalyst@lists.scsys.co.uk > > Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst > > Searchable archive: > http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ > > Dev site: http://dev.catalyst.perl.org/ > > > > Another nice approach to reuse Controller Logic is to use Moose Roles. > > I got the basics from t0ms blog > (http://bobtfish.livejournal.com/#post-bobtfish-264317) > An example how i use it can be found here > > http://wiki.catalystframework.org/wiki/wikicookbook/controllerwithfileupload > (the interesting part is in the file Resource.pm in the attachment > > http://wiki.catalystframework.org/wiki/wikicookbook/ControllerWithFileUpload.attachment/100 > ) > > > * > package CatalystX::TraitFor::Controller::Resource; > use MooseX::MethodAttributes::Role; > use namespace::autoclean; > > sub base : Chained('') PathPart('') CaptureArgs(0) { >my ($self, $c ) = @_; >... > }; > > sub index :Chained('base') :PathPart('') :Args(0) { >my ($self, $c ) = @_; >... > } > 1; > * > > > > Thank you David. This looks very close to what I had in head. I will look more in to it! Regards, Pavel ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] best practices for handling forms?
Hi, I am curious what everyone thinks as being the best practices for handling forms in Catalyst. Are there any Catalyst applications you have run across which are good examples of how to use Catalyst's features to handle forms? To illustrate what I am getting at, below is typical Rails (v2) controller code which implements updating the attributes of an object: def edit @book = Book.find(params[:id]) @subjects = Subject.find(:all) end def update @book = Book.find(params[:id]) if @book.update_attributes(params[:book]) flash[:notice] = 'Book successfully updated.' redirect_to :action => 'show', :id => @book else @subjects = Subject.find(:all) render :action => 'edit' end end In Catalyst, this would be appear something like (and please correct me if I have made any errors here): sub edit :Args(1) { my ($self, $c, $id) = @_; ... set up $c->stash for template 'edit' ... # no need to set $c->stash->{template} - will be set from the current action } sub update :Args(1) { my ($self, $c, $id) = @_; ...process form... if (form is valid) { ...perform updates... $c->flash->{notice} = 'Book successfully updated.'; $c->res->redirect('show', $id); } else { ... set up $c->stash for 'edit' template ... $c->stash->{template} = 'edit'; } } Any comments on this architecture? Is there a better way? My main problems are: 1. The code ... set up $c->stash for 'edit' template ... is duplicated in both edit and update (which is also true for the Rails code). 2. Having the template name defaulted from the current action is nice, but that means we have to explicitly set it in the update method. Is it better to always explicitly set the template name in a controller method? Then update could perform a $c->detach('edit', $id) or would you use $c->go('edit', $id)? Thanks, ER ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] best practices for handling forms?
perl Catalyst Forms with Formhandler and Thickbox: You know you dont always need a template.tt2 file... this is useful with ajax (especially with thickbox) so you can pass a scalar as template, so you end up with: $c->stash( template => $form->render, current_view => 'Ajax', ); 1. You could create an Ajax view. 2. Or you can set body content directly. This way you skip creating TT files for forms and render them directly into the $c->res->body or $c->stash( template => \'foo baz') If you use something like thickbox, you can render any $form directly into a modal. Its very handy! For example: __PACKAGE__->config( action => { edit => { Chained => 'base', Args => 1, }, }, ); sub base : Chained('/') PathPart('foobar') CaptureArgs(0) {} sub edit :Action { my ( $self, $c, $foobar_id ) = @_; my $form = HTML::FormHandler->new( schema => 'DBSchema::Foo', params => $c->req->params, field_list => $self->form_fields($c), ); if( $c->req->method eq 'POST' && $form->process() ) { ... } else { #OPTION 1 (create an Ajax View and create a wrapper for it. Then render the form into stash template var): $c->stash( template => \$form->render, current_view => 'Ajax', ); #OPTION 2 (set your content type and charset and render the form into the body, needs no view/TT files): $c->res->content_type('text/html charset=utf-8'); $c->res->body($form->render); } } sub form_fields { return [ field_one => { type => 'Text', label => '...', css_class => '...', maxlength => 160, required => 1, required_message => 'Required Text', }, submit => { type => 'Submit', value => 'Save', css_class => '...', }, ]; } and DRY on edit & update unless necessary... 1. If there is an argument its "update?" 2. Else, when it has no args then its "edit/new" ? use your foregin_key_id and $form('foregin_key_id')->value = '...' to set it , then formhandler will know whether to update or create a new entry. Take care, hernan On Mon, Sep 20, 2010 at 6:48 PM, E R wrote: > Hi, > > I am curious what everyone thinks as being the best practices for > handling forms in Catalyst. Are there any Catalyst applications you > have run across which are good examples of how to use Catalyst's > features to handle forms? > > To illustrate what I am getting at, below is typical Rails (v2) > controller code which implements updating the attributes of an object: > > def edit > @book = Book.find(params[:id]) > @subjects = Subject.find(:all) > end > def update > @book = Book.find(params[:id]) > if @book.update_attributes(params[:book]) > flash[:notice] = 'Book successfully updated.' > redirect_to :action => 'show', :id => @book > else > @subjects = Subject.find(:all) > render :action => 'edit' > end > end > > In Catalyst, this would be appear something like (and please correct > me if I have made any errors here): > > sub edit :Args(1) { > my ($self, $c, $id) = @_; > ... set up $c->stash for template 'edit' ... > # no need to set $c->stash->{template} - will be set from the current > action > } > > sub update :Args(1) { > my ($self, $c, $id) = @_; > ...process form... > if (form is valid) { >...perform updates... >$c->flash->{notice} = 'Book successfully updated.'; >$c->res->redirect('show', $id); > } else { >... set up $c->stash for 'edit' template ... >$c->stash->{template} = 'edit'; > } > } > > Any comments on this architecture? Is there a better way? My main problems > are: > > 1. The code ... set up $c->stash for 'edit' template ... is duplicated > in both edit and update (which is also true for the Rails code). > > 2. Having the template name defaulted from the current action is nice, > but that means we have to explicitly set it in the update method. Is > it better to always explicitly set the template name in a controller > method? Then update could perform a $c->detach('edit', $id) or would > you use $c->go('edit', $id)? > > Thanks, > ER > > ___ > List: Catalyst@lists.scsys.co.uk > Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst > Searchable archive: > http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ > Dev site: http://dev.catalyst.perl.org/ > ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] best practices for handling forms?
correction: you can pass a reference to $c->stash(template => \'foobas'), so you end up with: $c->stash( template => \$form->render, current_view => 'Ajax', ); On Mon, Sep 20, 2010 at 8:09 PM, Hernan Lopes wrote: > perl Catalyst Forms with Formhandler and Thickbox: > > You know you dont always need a template.tt2 file... this is useful with > ajax (especially with thickbox) so you can pass a scalar as template, so you > end up with: > $c->stash( template => $form->render, current_view => 'Ajax', ); > 1. You could create an Ajax view. > 2. Or you can set body content directly. > This way you skip creating TT files for forms and render them directly into > the $c->res->body or $c->stash( template => \'foo baz') > If you use something like thickbox, you can render any $form directly into > a modal. > Its very handy! > > For example: > > > __PACKAGE__->config( > action => { > edit => { Chained => 'base', Args => 1, }, > }, > ); > > sub base : Chained('/') PathPart('foobar') CaptureArgs(0) {} > > sub edit :Action { > my ( $self, $c, $foobar_id ) = @_; > my $form = HTML::FormHandler->new( > schema => 'DBSchema::Foo', > params => $c->req->params, > field_list => $self->form_fields($c), > ); > if( $c->req->method eq 'POST' && $form->process() ) { > ... > } else { > #OPTION 1 (create an Ajax View and create a wrapper for it. Then render > the form into stash template var): > $c->stash( > template => \$form->render, > current_view => 'Ajax', > ); > #OPTION 2 (set your content type and charset and render the form into the > body, needs no view/TT files): > $c->res->content_type('text/html charset=utf-8'); > $c->res->body($form->render); > } > } > > > > > sub form_fields { > return [ > field_one => { > type => 'Text', > label => '...', > css_class => '...', > maxlength => 160, > required => 1, > required_message => 'Required Text', > }, > submit => { > type => 'Submit', > value => 'Save', > css_class => '...', > }, > ]; > } > > > > and DRY on edit & update unless necessary... > 1. If there is an argument its "update?" > 2. Else, when it has no args then its "edit/new" ? > > use your foregin_key_id and $form('foregin_key_id')->value = '...' to set > it , then formhandler will know whether to update or create a new entry. > > Take care, > hernan > > > > > > > On Mon, Sep 20, 2010 at 6:48 PM, E R wrote: > >> Hi, >> >> I am curious what everyone thinks as being the best practices for >> handling forms in Catalyst. Are there any Catalyst applications you >> have run across which are good examples of how to use Catalyst's >> features to handle forms? >> >> To illustrate what I am getting at, below is typical Rails (v2) >> controller code which implements updating the attributes of an object: >> >> def edit >> @book = Book.find(params[:id]) >> @subjects = Subject.find(:all) >> end >> def update >> @book = Book.find(params[:id]) >> if @book.update_attributes(params[:book]) >> flash[:notice] = 'Book successfully updated.' >> redirect_to :action => 'show', :id => @book >> else >> @subjects = Subject.find(:all) >> render :action => 'edit' >> end >> end >> >> In Catalyst, this would be appear something like (and please correct >> me if I have made any errors here): >> >> sub edit :Args(1) { >> my ($self, $c, $id) = @_; >> ... set up $c->stash for template 'edit' ... >> # no need to set $c->stash->{template} - will be set from the current >> action >> } >> >> sub update :Args(1) { >> my ($self, $c, $id) = @_; >> ...process form... >> if (form is valid) { >>...perform updates... >>$c->flash->{notice} = 'Book successfully updated.'; >>$c->res->redirect('show', $id); >> } else { >>... set up $c->stash for 'edit' template ... >>$c->stash->{template} = 'edit'; >> } >> } >> >> Any comments on this architecture? Is there a better way? My main problems >> are: >> >> 1. The code ... set up $c->stash for 'edit' template ... is duplicated >> in both edit and update (which is also true for the Rails code). >> >> 2. Having the template name defaulted from the current action is nice, >> but that means we have to explicitly set it in the update method. Is >> it better to always explicitly set the template name in a controller >> method? Then update could perform a $c->detach('edit', $id) or would >> you use $c->go('edit', $id)? >> >> Thanks, >> ER >> >> ___ >> List: Catalyst@lists.scsys.co.uk >> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst >> Searchable archive: >> http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ >> Dev site: http://dev.catalyst.perl.org/ >> > > ___ List: Catalyst@lists.sc
Re: [Catalyst] best practices for handling forms?
Ohh, by the way, if you need to write html into the form, you can also do it without any TT view file. With Formhandler it is very simple, just use the field of type 'Display', for example: has_field 'display0' => ( type => 'Display', html => ' Your Personal Data foo bar baz ' ); On Mon, Sep 20, 2010 at 8:09 PM, Hernan Lopes wrote: > perl Catalyst Forms with Formhandler and Thickbox: > > You know you dont always need a template.tt2 file... this is useful with > ajax (especially with thickbox) so you can pass a scalar as template, so you > end up with: > $c->stash( template => $form->render, current_view => 'Ajax', ); > 1. You could create an Ajax view. > 2. Or you can set body content directly. > This way you skip creating TT files for forms and render them directly into > the $c->res->body or $c->stash( template => \'foo baz') > If you use something like thickbox, you can render any $form directly into > a modal. > Its very handy! > > For example: > > > __PACKAGE__->config( > action => { > edit => { Chained => 'base', Args => 1, }, > }, > ); > > sub base : Chained('/') PathPart('foobar') CaptureArgs(0) {} > > sub edit :Action { > my ( $self, $c, $foobar_id ) = @_; > my $form = HTML::FormHandler->new( > schema => 'DBSchema::Foo', > params => $c->req->params, > field_list => $self->form_fields($c), > ); > if( $c->req->method eq 'POST' && $form->process() ) { > ... > } else { > #OPTION 1 (create an Ajax View and create a wrapper for it. Then render > the form into stash template var): > $c->stash( > template => \$form->render, > current_view => 'Ajax', > ); > #OPTION 2 (set your content type and charset and render the form into the > body, needs no view/TT files): > $c->res->content_type('text/html charset=utf-8'); > $c->res->body($form->render); > } > } > > > > > sub form_fields { > return [ > field_one => { > type => 'Text', > label => '...', > css_class => '...', > maxlength => 160, > required => 1, > required_message => 'Required Text', > }, > submit => { > type => 'Submit', > value => 'Save', > css_class => '...', > }, > ]; > } > > > > and DRY on edit & update unless necessary... > 1. If there is an argument its "update?" > 2. Else, when it has no args then its "edit/new" ? > > use your foregin_key_id and $form('foregin_key_id')->value = '...' to set > it , then formhandler will know whether to update or create a new entry. > > Take care, > hernan > > > > > > > On Mon, Sep 20, 2010 at 6:48 PM, E R wrote: > >> Hi, >> >> I am curious what everyone thinks as being the best practices for >> handling forms in Catalyst. Are there any Catalyst applications you >> have run across which are good examples of how to use Catalyst's >> features to handle forms? >> >> To illustrate what I am getting at, below is typical Rails (v2) >> controller code which implements updating the attributes of an object: >> >> def edit >> @book = Book.find(params[:id]) >> @subjects = Subject.find(:all) >> end >> def update >> @book = Book.find(params[:id]) >> if @book.update_attributes(params[:book]) >> flash[:notice] = 'Book successfully updated.' >> redirect_to :action => 'show', :id => @book >> else >> @subjects = Subject.find(:all) >> render :action => 'edit' >> end >> end >> >> In Catalyst, this would be appear something like (and please correct >> me if I have made any errors here): >> >> sub edit :Args(1) { >> my ($self, $c, $id) = @_; >> ... set up $c->stash for template 'edit' ... >> # no need to set $c->stash->{template} - will be set from the current >> action >> } >> >> sub update :Args(1) { >> my ($self, $c, $id) = @_; >> ...process form... >> if (form is valid) { >>...perform updates... >>$c->flash->{notice} = 'Book successfully updated.'; >>$c->res->redirect('show', $id); >> } else { >>... set up $c->stash for 'edit' template ... >>$c->stash->{template} = 'edit'; >> } >> } >> >> Any comments on this architecture? Is there a better way? My main problems >> are: >> >> 1. The code ... set up $c->stash for 'edit' template ... is duplicated >> in both edit and update (which is also true for the Rails code). >> >> 2. Having the template name defaulted from the current action is nice, >> but that means we have to explicitly set it in the update method. Is >> it better to always explicitly set the template name in a controller >> method? Then update could perform a $c->detach('edit', $id) or would >> you use $c->go('edit', $id)? >> >> Thanks, >> ER >> >> ___ >> List: Catalyst@lists.scsys.co.uk >> Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst >> Searchable archive: >> http://www.mail-archiv
Re: [Catalyst] Reuse of controllers
> "Pavel" == Pavel A Karoukin writes: Pavel> I got the basics from t0ms blog Pavel> (http://bobtfish.livejournal.com/#post-bobtfish-264317) An Pavel> example how i use it can be found here Pavel> http://wiki.catalystframework.org/wiki/wikicookbook/controllerwithfileupload Pavel> (the interesting part is in the file Resource.pm in the Pavel> attachment Pavel> http://wiki.catalystframework.org/wiki/wikicookbook/ControllerWithFileUpload.attachment/100) An overlooked feature of Catalyst is the ability to modify actions via the configuration: package MyRole::Login; use Moose::Role; sub login { etc... } package MyApp::Controller::Login; use Moose; with 'MyRole::Login'; __PACKAGE__->config(action => { login => { PathPart => 'sign-in' } } ); package MyOtherApp::Controller::Login; use Moose; with 'MyRole::Login'; __PACKAGE__->config(action => { login => { PathPart => 'log-in } } ); note that you can use any key that you would use as an action attribute, including chainining, and catalyst automatically promotes the method to an action due to the existence of the config. -- Eden Cardim Need help with your Catalyst or DBIx::Class project? Code Monkeyhttp://www.shadowcat.co.uk/catalyst/ Shadowcat Systems Ltd. Want a managed development or deployment platform? http://blog.edencardim.com/http://www.shadowcat.co.uk/servers/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] Defining ARRAY in Config::General config
Hello, I am using Catalyst::Plugin::Mail and want to define email config in myapp.conf. But C::P::Mail expects email config variable to be array ref. How I can assign array value to config variable in myapp.conf? Regards, Pavel ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Defining ARRAY in Config::General config
On Tue, Sep 21, 2010 at 07:29, Pavel A. Karoukin wrote: > Hello, > I am using Catalyst::Plugin::Mail and want to define email config in > myapp.conf. But C::P::Mail expects email config variable to be array ref. > How I can assign array value to config variable in myapp.conf? Multiple rows with same name and different values form array in myapp.conf For example: room 7 room 9 room 13 Example is in Config::General syntax best regards Kamen ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] best practices for handling forms?
Hi, A clean example that uses HTML::FormFu is: package MyApp::Controller::Foo; use Moose; extends 'Catalyst::Controller::HTML::FormFu'; # or just use parent 'Catalyst::Controller::HTML::FormFu' if you don't use Moose sub edit : Local FormConfig { my ($self, $c, $id) = @_; my $form = $c->stash->{form}; my $foo = $c->model("DB::Foo")->find($id); if ($form->submitted_and_valid) { $form->model->update($foo); $c->flash(notice => "Foo was updated successfully."); $c->res->redirect($c->uri_for_action('/foo/index')); } else { $form->model->default_values($foo); } } sub edit : Local FormConfig { You can use Path or the chaining dispatch type or something else, not only "Local". If you use the attribute FormConfig, it will search for the form placed by default in root/forms/foo/edit.conf If you want to use another specified form, you can use something like: sub edit : Local FormConfig('path/to/another/form') { my $form = $c->stash->{form}; If you use the FormConfig attribute, it will place the form in the stash automaticly so you just need to get it from there. my $foo = $c->model("DB::Foo")->find($id); This uses DBIx::Class result class DB::Foo for getting the $foo record. if ($form->submitted_and_valid) { This will be true only if the form past all the validation and constraints. $form->model->update($foo); This will update the $foo record in the database. In order to work this way, you need to have defined the database schema in myapp.conf like: 'Controller::HTML::FormFu' => { model_stash => { schema => 'DB', }, }, And in the edit.conf form configuration file (defined below using Config::General) you will need to have defined the resultset like: resultset Foo $c->res->redirect($c->uri_for_action('/foo/index')); $c->uri_for_action is prefered because /foo/index is not a URI but an internal path to the index action from the Foo controller and this code doesn't need to be changed even if the public URI to that action changes. $form->model->default_values($foo); This fills the form with the values from $foo record when the form is displayed. HTH. --Octavian - Original Message - From: "E R" To: "The elegant MVC web framework" Sent: Tuesday, September 21, 2010 12:48 AM Subject: [Catalyst] best practices for handling forms? Hi, I am curious what everyone thinks as being the best practices for handling forms in Catalyst. Are there any Catalyst applications you have run across which are good examples of how to use Catalyst's features to handle forms? To illustrate what I am getting at, below is typical Rails (v2) controller code which implements updating the attributes of an object: def edit @book = Book.find(params[:id]) @subjects = Subject.find(:all) end def update @book = Book.find(params[:id]) if @book.update_attributes(params[:book]) flash[:notice] = 'Book successfully updated.' redirect_to :action => 'show', :id => @book else @subjects = Subject.find(:all) render :action => 'edit' end end In Catalyst, this would be appear something like (and please correct me if I have made any errors here): sub edit :Args(1) { my ($self, $c, $id) = @_; ... set up $c->stash for template 'edit' ... # no need to set $c->stash->{template} - will be set from the current action } sub update :Args(1) { my ($self, $c, $id) = @_; ...process form... if (form is valid) { ...perform updates... $c->flash->{notice} = 'Book successfully updated.'; $c->res->redirect('show', $id); } else { ... set up $c->stash for 'edit' template ... $c->stash->{template} = 'edit'; } } Any comments on this architecture? Is there a better way? My main problems are: 1. The code ... set up $c->stash for 'edit' template ... is duplicated in both edit and update (which is also true for the Rails code). 2. Having the template name defaulted from the current action is nice, but that means we have to explicitly set it in the update method. Is it better to always explicitly set the template name in a controller method? Then update could perform a $c->detach('edit', $id) or would you use $c->go('edit', $id)? Thanks, ER ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/