Re: [Catalyst] One App, multiple databases
On 20 Nov 2008, at 14:51, Jose Luis Martinez wrote: Jonathan Rockway escribió: * On Wed, Nov 19 2008, Jose Luis Martinez wrote: sub ACCEPT_CONTEXT { my ($self, $c) = @_; my $user_db = $c->lookup_the_users_db(); $self->{'dsn'} =~ s/#DATABASE#/$user_db/; return $self; } I am really surprised that this works at all. When do you actually ever connect to the database with the DSN in $self->{dsn}? (I am also surprised that the DBIC version works.) It looks like the models don't connect to the database until it is first needed, so changing the properties with which they connect lets me get away with it. I think the fact that I'm working with app_server.pl -f helps me start each request without preestablished db connection. Anyway, mutating objects is wrong. You should do things like this: package MyApp::Model::UsersDatabase; ... sub ACCEPT_CONTEXT { my ($self, $c) = @_; return $c->user->get_database($c->config->database_info); } The idea is that each user has his own database connection, stored in the user object, and Catalyst just returns the right thing when you say $c->model('UsersDatabase'). This is much easier to reason about. But I'll still have to change Model::DBI and/or Model::DBIC::Schema connection information on the fly... how should I do this in a clean way? No, you don't. In your application code, instead of saying $c->model('DB')->dbh, with the example above, you would say $c->model('UsersDatabase'), and that would return you the dbh which the user object had generated. You then work with it in exactly the same way as if you were using Catalyst::Model::DBI. This means that you have to re-implement the connection logic of Catalst::Model::DBI in your user class. The only tricky bit is the stay_connected function, which is 16 lines long. I don't think the code police will break down your door if you pinch this function verbatim. ;) Cheers t0m ___ 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] One App, multiple databases
Jonathan Rockway escribió: * On Wed, Nov 19 2008, Jose Luis Martinez wrote: sub ACCEPT_CONTEXT { my ($self, $c) = @_; my $user_db = $c->lookup_the_users_db(); $self->{'dsn'} =~ s/#DATABASE#/$user_db/; return $self; } I am really surprised that this works at all. When do you actually ever connect to the database with the DSN in $self->{dsn}? (I am also surprised that the DBIC version works.) It looks like the models don't connect to the database until it is first needed, so changing the properties with which they connect lets me get away with it. I think the fact that I'm working with app_server.pl -f helps me start each request without preestablished db connection. Anyway, mutating objects is wrong. You should do things like this: package MyApp::Model::UsersDatabase; ... sub ACCEPT_CONTEXT { my ($self, $c) = @_; return $c->user->get_database($c->config->database_info); } Then your user class should do something like: sub get_database { my ($self, $database_info) = @_; $self->database_connection($self->connect_to_database($database_info)) unless $self->has_database_connection; return $self->database_connection; } The idea is that each user has his own database connection, stored in the user object, and Catalyst just returns the right thing when you say $c->model('UsersDatabase'). This is much easier to reason about. But I'll still have to change Model::DBI and/or Model::DBIC::Schema connection information on the fly... how should I do this in a clean way? Regards, Jose Luis Martinez [EMAIL PROTECTED] ___ 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] One App, multiple databases
* On Wed, Nov 19 2008, Jose Luis Martinez wrote: > > sub ACCEPT_CONTEXT { > my ($self, $c) = @_; > > my $user_db = $c->lookup_the_users_db(); > $self->{'dsn'} =~ s/#DATABASE#/$user_db/; > > return $self; > } > I am really surprised that this works at all. When do you actually ever connect to the database with the DSN in $self->{dsn}? (I am also surprised that the DBIC version works.) Anyway, mutating objects is wrong. You should do things like this: package MyApp::Model::UsersDatabase; ... sub ACCEPT_CONTEXT { my ($self, $c) = @_; return $c->user->get_database($c->config->database_info); } Then your user class should do something like: sub get_database { my ($self, $database_info) = @_; $self->database_connection($self->connect_to_database($database_info)) unless $self->has_database_connection; return $self->database_connection; } (You can write cleaner code with a before method modifier, if you use Moose.) The idea is that each user has his own database connection, stored in the user object, and Catalyst just returns the right thing when you say $c->model('UsersDatabase'). This is much easier to reason about. Regards, Jonathan Rockway -- print just => another => perl => hacker => if $,=$" ___ 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] One App, multiple databases
On Wed, Nov 19, 2008 at 10:53 PM, Jose Luis Martinez <[EMAIL PROTECTED]> wrote: > Basically we giving multi-tentant capability to our app (which was ported > from some old CGIs). The CGIs where setup to load config files based on the > REMOTE_USER, so we gave each user a separate DB just by changing the connect > string. Now in Catayst we want the same effect ;), as sharing one database > between all users is a step we don't want to take (for the moment). I've achieved something similar to this by connecting to the user-specific database where appropriate via an effective model-like (non cat) module in the Root/auto portion of the application. This works well-enough for my purposes, but you might want to call out to a dedicated service if you want to achieve better persistence than this would otherwise afford. Chris ___ 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] One App, multiple databases
Mesdaq, Ali escribió: Are these db's exact copies as far as schema from each other? Or is it different tables and structure as well? Reason I am asking is because if its exactly the same and all your queries work the same and your logic works the same as well and the only difference is if user1 is connected then connect to one schema and if user2 is connected connect to another schema you might be able to more cleanly determine the db in your controller code. You would also then create a model for each user. This would give you granular control over if the user db's ever move or if you need to configure specific connection data per users db like different user accounts and passwords etc. So instead of something like: $c->model('DB::Blah')->all Yes, they are exactly the same. But I'm not really all that keen on creating one model per user (because the users would be created and deleted), and that would mean that will have to be added and deleted, and app servers restarted. But I think knowing a little more about your exact situation might help understand the issue more. Basically we giving multi-tentant capability to our app (which was ported from some old CGIs). The CGIs where setup to load config files based on the REMOTE_USER, so we gave each user a separate DB just by changing the connect string. Now in Catayst we want the same effect ;), as sharing one database between all users is a step we don't want to take (for the moment). Hope that explains a bit more. Thanks, Jose Luis Martinez [EMAIL PROTECTED] ___ 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] One App, multiple databases
Are these db's exact copies as far as schema from each other? Or is it different tables and structure as well? Reason I am asking is because if its exactly the same and all your queries work the same and your logic works the same as well and the only difference is if user1 is connected then connect to one schema and if user2 is connected connect to another schema you might be able to more cleanly determine the db in your controller code. You would also then create a model for each user. This would give you granular control over if the user db's ever move or if you need to configure specific connection data per users db like different user accounts and passwords etc. So instead of something like: $c->model('DB::Blah')->all You could do: $c->model("$user:Blah")->all But I think knowing a little more about your exact situation might help understand the issue more. Thanks, -- Ali Mesdaq (CISSP, GIAC-GREM) Sr. Security Researcher Websense Security Labs http://www.WebsenseSecurityLabs.com -- -Original Message- From: Jose Luis Martinez [mailto:[EMAIL PROTECTED] Sent: Wednesday, November 19, 2008 9:54 AM To: The elegant MVC web framework Subject: [Catalyst] One App, multiple databases Hello, This question has been asked a couple of times on the list, and I have found yet another solution to it, but I would like to hear if maybe I'm doing something wrong, or I will suffer serious pain by doing it my way :) We have an app that will connect to one database or another depending on the logged in user. My solution: package App::Model::DB; use strict; use base 'Catalyst::Model::DBIC::Schema'; ... sub ACCEPT_CONTEXT { my ($self, $c) = @_; my $user_db = $c->lookup_the_users_db(); $self->config->{'connect_info'}->[0] =~ s/#DATABASE#/$user_db/; $self->schema->connection(@{$self->config->{'connect_info'}}); return $self; } 1; I've done the same with Catalyst::Model::DBI: package App::Model::AnotherDB; use strict; use base 'Catalyst::Model::DBI'; sub ACCEPT_CONTEXT { my ($self, $c) = @_; my $user_db = $c->lookup_the_users_db(); $self->{'dsn'} =~ s/#DATABASE#/$user_db/; return $self; } 1; And the two seem to be working OK, but I'm worried about what will happen when we fire it up in a FastCGI environment (I suspect the connection to user1's database will be kept live, and the next user will get the connection to it). Am I right? Any pointers? Does this way of using the models trigger any warning lights to Catalyst gurus? Thanks in advance, Jose Luis Martinez [EMAIL PROTECTED] ___ 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/ Protected by Websense Hosted Email Security -- www.websense.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/
[Catalyst] One App, multiple databases
Hello, This question has been asked a couple of times on the list, and I have found yet another solution to it, but I would like to hear if maybe I'm doing something wrong, or I will suffer serious pain by doing it my way :) We have an app that will connect to one database or another depending on the logged in user. My solution: package App::Model::DB; use strict; use base 'Catalyst::Model::DBIC::Schema'; ... sub ACCEPT_CONTEXT { my ($self, $c) = @_; my $user_db = $c->lookup_the_users_db(); $self->config->{'connect_info'}->[0] =~ s/#DATABASE#/$user_db/; $self->schema->connection(@{$self->config->{'connect_info'}}); return $self; } 1; I've done the same with Catalyst::Model::DBI: package App::Model::AnotherDB; use strict; use base 'Catalyst::Model::DBI'; sub ACCEPT_CONTEXT { my ($self, $c) = @_; my $user_db = $c->lookup_the_users_db(); $self->{'dsn'} =~ s/#DATABASE#/$user_db/; return $self; } 1; And the two seem to be working OK, but I'm worried about what will happen when we fire it up in a FastCGI environment (I suspect the connection to user1's database will be kept live, and the next user will get the connection to it). Am I right? Any pointers? Does this way of using the models trigger any warning lights to Catalyst gurus? Thanks in advance, Jose Luis Martinez [EMAIL PROTECTED] ___ 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/