Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Catalyst / DBIx::Class - accessing a different table from the model

by mkchris (Sexton)
on Feb 16, 2015 at 17:31 UTC ( [id://1116906]=perlquestion: print w/replies, xml ) Need Help??

mkchris has asked for the wisdom of the Perl Monks concerning the following question:

Hi there I'm developing a Catalyst website and have kind of been learning as I'm going along, but now know enough (almost) to go and rewrite chunks of it. Up until now I've been doing my create / update error checking in my controller (which I know is not recommended) - I'm now moving it to the model, but have hit a snag. Consider a table ('clubs'), one of whose columns ('venue') has a 'belongs_to' relationship with another table ('venues'). Previously, to do my error checking, I've been able to do something like this:
my $venue_check = $c->model("DB::Venue")->find($venue); $error .= "The venue is not valid.\n" if !defined($venue_check);
Now from my model Resultset class, I can check anything in the current table with $self->find(), etc., but am unsure how to query a different table without passing in $c as one of the arguments from the controller (which is obviously regarded as a cardinal sin and kind of defeats the object of doing it in the model). Many thanks in advance for any assistance. Chris

Replies are listed 'Best First'.
Re: Catalyst / DBIx::Class - accessing a different table from the model
by Your Mother (Archbishop) on Feb 16, 2015 at 19:50 UTC

    Right off you can be sure that you will never need $c. The Catalyst context is, well, SHOULD be, entirely irrelevant to all DB operations. If not, you may have a “broken design.”

    The DB has its own proper routes to information and self-reference. It’s only being consumed by Catalyst, it is not intrinsically a part of it at all. Generally, no DBIC question is ever a Catalyst question and vice versa.

    So, there are probably a few ways to do what you want, if I’m correctly guessing what you want; which is to create a club record, presumably from MyApp::Controller::Club->something with valid venue.

    my $club = $c->model("DB::Clubs") ->create({ some_data => "asdfasdf", venue => $id });

    If your data is InnoDB or equivalent with proper foreign keys this will throw an exception on a bad venue because your DB will not allow bad integrity to be stored. Then you just eval and recover in the controller, or do a general purpose version of same in you /end controller where $c->errors (all fatals) are available to be handled (and cleared) or passed along as a server error.

    I take it you are trying to avoid things like the following. But there is nothing wrong with this approach so don’t avoid it out of some sense of purity. Maybe you don’t know about it. This one will also throw an error if the venue is bad whether or not your DB cares.

    my $venue = $c->model("DB::Venue")->find($id); $venue->add_to_clubs({ some_club_data => "Without venue" });

    Now, the last possibility (well, the last obvious one) is that you have no DB integrity (your foreign keys are advisory, not enforced) and you don’t want to do any handling in Catalyst. In this case you might have to do something like this–

    # Inside MySchema::Result::Club. sub insert { my $self = shift; return $self if $self->in_storage; croak "No venue provided..." unless $self->venue; my $schema = $self->result_source->schema; croak "Venue is invalid..." unless $schema->resultset("Venue")->find($self->venue); $self->next::method(); } sub update { my $self = shift; my %to_update = $self->get_dirty_columns || return $self->next::method(@_); $to_update{venue} || return $self->next::method(@_); croak "Venue is invalid..." unless $schema->resultset("Venue")->find($to_update{venue}); $self->next::method(@_); }

    That’s rough but probably functional (none of this code was tested but I have used all of the approaches at some point). You can see why letting the DB handle integrity is saner policy. When you have to code around it, many edge cases pop up and get messy and can trash performance.

      The only nitpick I have is with "eval and recover". Try::Tiny cleans this up quite nicely, or use Throwable to create actual exceptions and keep things less crappy.

      Three thousand years of beautiful tradition, from Moses to Sandy Koufax, you're god damn right I'm living in the fucking past

        Well, that was back-of-the-napkining. :P I use Try::Tiny sometimes and I rely on /end handling myself; also newer Perls (5.16+ IIRC) do eval+$@ better so it’s not as important a caveat now and frankly I was never bitten by it in the past. I agree that exception objects can be a good idea, I posted a sample on that not long ago, but it’s not something that lends itself to inclusion in snippets.

        (Update: 5.14 is where better eval and $@ came in. Not 5.16 as previously suggested.)

      Thank you for that - I think I prefer the second option actually (all tables are InnoDB with enforced foreign keys) - I think I will try that or a variation on it, I never thought of that. Thanks again.
Re: Catalyst / DBIx::Class - accessing a different table from the model
by Anonymous Monk on Feb 16, 2015 at 19:41 UTC

    Does this info help?

    my $db_model = $c->model('FilmDB'); # a Catalyst::Model my $dbic = $c->model('FilmDB')->schema; # the actual DBIC object

    Catalyst, it even makes the questions confusing :) and the answers impossible :)... yeah I don't Catalyst

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1116906]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having an uproarious good time at the Monastery: (1)
As of 2024-04-24 13:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found