Re: dynamic tablenames

John-Scott Atlakson
Mon, 29 Jan 2007 04:02:43 -0000

On 1/27/07, Russell Norris
<sconds-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
wrote:
>
> What''s the criteria for which models need a new table name/prefix?
If it
> centers around another model then you can put a table_prefix attribute on
> that model and call it thusly:
>
> def self.set_tables
>   OtherModel.set_table_name "#{table_prefix}_othermodels"
> end
>
> Don''t use table_name_prefix as it sets ActionRecord::Base itself
and not
> the specific model as you might think. Lots of fun confusion on that for
me.
> Also, you can''t [or I couldn''t figure out how to] set the
table_name on the
> model itself. For me, the models that needed new table names [databases
> actually] were all related to what site was being used so my Site model has
> the set_tables method. Call that method from a filter on the appropriate
> controller methods and voila! On-the-fly table name changes. If you have a
> relationship between the models, you might also need to tweak your
> associations code like this:
>
> class Whatever
>   has_many :othermodels, :finder_sql => ''SELECT
> #{table_name}_othermodels.* FROM #{table_name}_othermodels WHERE
> #{table_name}_othermodels.whatever_id = #{id}''
>
> I hope that''s not too obtuse. It''s just that my code uses
this
> functionality to change databases and I don''t want to paste it and
have you
> thinking that it''s merely for changing table names. However, if
anyone is
> wondering... If you do need to change the database, you don''t have
to
> establish a new connection but can use
Model.set_table_name"#{db_name}.table_name".  You can use the same
trick in the association to
> select across two databases.
>
> God, I hope that wasn''t too obscure. Apologies in advance.
>
> RSL
>


Hmm, I posted a reply using the Google Groups interface and it''s not
appearing (even though my first reply to this post came through just fine).
Lots of posts elsewhere about this annoying Google Groups issue. So at the
risk of repeating myself, I''ll try sending an email reply to the group
to
see if it goes through or disappears into the ether.

Anyway, first off, thanks for your reply. My particular situation is that I
have separate tables for individual US states with the two letter state
abbreviation as table prefixes ( e.g. ''ny_things'',
''ca_things''). For a
variety of reasons these tables can''t be merged into a single table.
Rather
than define (essentially the same) models for every state, I''d rather
just
have the user select a state, which will the set the state abbreviation in
the users session data. From then on, all tables needing a prefix will be
dynamically set according to the session data. Some tables do not need a
prefix at all, so yes, I ran into the same problem trying to set
''table_name_prefix'' on an individual model and found it was
being prefixed
to all table names.

So for my first stab at a solution, I''m using a before_filter in my
controllers which call a private method in application.rb (so it can be
shared between several controllers) which calls the
''table_name'' methods for
those models needing this:

class ApplicationController < ActionController::Base
  def set_table_names
    Thing.table_name = "#{session[:state_abbreviation]}_things"
  end
end

Before this method is called, I call another before_filter method that makes
sure the the session variable is set and valid. If not, it redirects the
user to select an appropriate value. This is working perfectly for now.
I''m
using a regular expression to ensure that the state abbreviation is in fact
two and only two lower case letters before it is set in the session, so I
think I''m fairly safe with this approach.

As far as setting the table name within a model, I''ve always been able
to
just do:

class ExampleModel < ActiveRecord::Base
  self.table_name =
"some_crazy_table_name_not_conforming_to_conventions"
end

Cheers,
John-Scott
--