Git Product home page Git Product logo

Comments (5)

alassek avatar alassek commented on August 29, 2024 1

@TylerRick Thanks for the followup! This is not a use-case that matters to me so I appreciate the detail. I'll look through your PR when I have some free time.

from activerecord-pg_enum.

alassek avatar alassek commented on August 29, 2024

It's because you've defined it outside of the public schema, which I didn't account for.

from activerecord-pg_enum.

TylerRick avatar TylerRick commented on August 29, 2024

Ah, good catch. I didn't even notice that I was using a schema other than public. My config/database.yml specifies a user but doesn't specify a schema anywhere, so I guess maybe it uses a schema matching the user name by default?

Anyway, thanks for the quick fix! 👍 It's working now.

from activerecord-pg_enum.

TylerRick avatar TylerRick commented on August 29, 2024

Actually, the new behavior doesn't seem quite right to me. Now it's hard-coding the schema into the schema.rb.

The behavior that I expected was that it would leave the name unqualified since it is in the default schema and doesn't need to be qualified. Just like Rails doesn't qualify the table name for any of the create_table statements. The enum type that it created is in the same, default schema (app_name_development) as all the tables are in.

I probably wouldn't have even noticed that it was including the schema name except that it caused an error when I tried to run rails db:test:prepare:

rails aborted!
ActiveRecord::StatementInvalid: PG::InvalidSchemaName: ERROR:  schema "app_name_development" does not exist
: CREATE TYPE app_name_development.mailing_list_type AS ENUM ('include', 'if_address_valid', 'exclude')

I think the reason it doesn't work is because the schemas that are in the search_path vary depending on which database I connect to (even though I actually connect with the same app_name_dev user for both dev and test):

app_name_test=# show search_path;
   search_path   
-----------------
 "$user", public
(1 row)

app_name_development=# show search_path;
   search_path   
-----------------
 "$user", public
(1 row)

And here's my config/database.yml:

__postgres: &postgres
  adapter: postgresql
  encoding: unicode
  pool: 5
  host: host
  port: 5432
  user: app_name_development
  prepared_statements: false
  password: dev

development: &development
  <<: *postgres
  database: app_name_development

test: &test
  <<: *development
  reconnect: false
  database: app_name_test

I wonder if we could just reuse the same code Rails uses for determining the name to dump in schema.rb for tables?

You might also look at how https://github.com/scenic-views/scenic does it, because I know they have similar logic for dumping views to schema.rb...

from activerecord-pg_enum.

TylerRick avatar TylerRick commented on August 29, 2024

I looked at the code for how Rails gets the table name to dump, and it looks like it doesn't even select the schema name (nspname) at all:

SELECT c.relname FROM pg_class c
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = ANY (current_schemas(false)) AND c.relkind IN ('r','p')

... which means (if I am not mistaken), that it never qualifies table names that it dumps to schema.rb. Shouldn't we make activerecord-pg_enum dump the same way for types?

The way it appears to work is that it treats all schemas in your search path as equal, and basically flattens everything when dumping. So even if your current actual database has multiple schemas, it flattens it when you rails db:schema:dump, and if you were to set up your database again from schema.rb, you would only end up with one schema instead. I'm not sure that's the best way to do it, but we should probably be consistent with that way anyway...

(To confirm this, I did an experiment. I created a table in each of the schemas in the search path, and one that wasn't:

app_name_development=# create schema custom;
app_name_development=# select current_schemas(false);
           current_schemas           
-------------------------------------
 {app_name_development,public}
app_name_development=# CREATE TABLE app_name_development.table_1();
app_name_development=# CREATE TABLE public.table_2();
app_name_development=# CREATE TABLE custom.table_on_custom_schema();

Then I ran rails db:schema:dump and observed that table_1 and table_2 were dumped in the same way (without schema); table_on_custom_schema was not dumped at all.
)

In fact, not only does lib/active_record/schema_dumper.rb appear to not add the schema name as prefix, it goes out of its way to remove any prefix or suffix that might be defined (via config.table_name_prefix):

tbl.print "  create_table #{remove_prefix_and_suffix(table).inspect}" 

What about schemas not in your search path, you ask? Well, they won't be selected due to the WHERE n.nspname = ANY (current_schemas(false)) condition.

https://www.postgresql.org/docs/9.3/functions-info.html has the documentation for current_schemas(false):

names of schemas in search path, optionally including implicit schemas

(Note that you can control that by specifying a :schema_search_path in config/database.yml, but I didn't...)


Having said all that, I will probably eventually just change my database to just use the public namespace instead of one named after the app. But I still think the current behavior is surprising, and causes things to break when preparing the test database using schema.rb (that is, rails db:test:prepare).

If you're wondering how I ended up with a non-public namespace for all my tables to begin with, it was because I imported another (production-like) database into development instead of creating it from db/schema.rb... which was working fine. But test database still needs to be created from db/schema.rb.

from activerecord-pg_enum.

Related Issues (14)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.