globalize/globalize

rails asset:precompile attempts to connect to DB because of globalize

spikeheap opened this issue ยท 17 comments

  • ruby '2.6.1'
  • gem 'rails', '~> 5.2.2'
  • gem 'globalize', '~> 5.2'

When precompiling assets in a Docker environment, Rails fails with the following error:

rails aborted!
PG::ConnectionBad: could not connect to server: Connection refused
  Is the server running on host "localhost" (::1) and accepting
  TCP/IP connections on port 5432?
could not connect to server: Connection refused
  Is the server running on host "localhost" (127.0.0.1) and accepting
  TCP/IP connections on port 5432?
/Volumes/...<omitted>.../app/models/category.rb:18:in `<class:Category>'
/Volumes/...<omitted>.../app/models/category.rb:13:in `<main>'
/Volumes/...<omitted>.../config/initializers/rails_admin.rb:59:in `block in <main>'
/Volumes/...<omitted>.../config/initializers/rails_admin.rb:3:in `<main>'
/Volumes/...<omitted>.../config/environment.rb:7:in `<main>'
/Volumes/...<omitted>.../bin/rails:11:in `<top (required)>'
/Volumes/...<omitted>.../bin/spring:16:in `<top (required)>'
./bin/rails:5:in `load'
./bin/rails:5:in `<main>'
Tasks: TOP => environment
(See full trace by running task with --trace)

Because we're doing this as part of a Docker build, we don't have access to any database. Rails is attempting to open a connection because a translation exists on my Category model, which is being interrogated by Rails Admin.

This issue originally arose in #601 and was resolved in #602 by guarding database checks with connected?. A subsequent PR to support Rails 5.1 (#619) reintroduced this bug in 42b173f, because connected? doesn't return true when running tests using a database because there's nothing to trigger the actual connection.

#619 altered the behaviour to rescue ActiveRecord::NoDatabaseError, however a failed Postgres connection raises PG::ConnectionBad, which leads to the error I'm experiencing.

#719 suggested rescuing from PG::ConnectionBad, but understandably this was rejected as it makes pg a dependency of globalize, and doesn't cater for Mysql2::Error::ConnectionError .

This comment has some insight into how this could be avoided in Globalize, but I'm not familiar enough with Globalize/ActiveRecord to put together a fix (happy to be pointed in the right direction though...).

I'm mostly opening this issue for visibility, as the conversations/comments are all on closed issues and merged PRs.

Would you be open to a PR reverting 42b173f in the interim?

deepj commented

The same problem here. It causes troubles while building docker image when there is no DB available.

The same problem here. It causes troubles while building docker image when there is no DB available.

The same

I have managed to work it around by commenting out resources in config/routes.rb:

RUN : disable resources in config/routes.rb so that it\'d not connect to db \
    && sed -Ei 's/^(\s*resources)\b/# TEMPORARY \1/' config/routes.rb \
    && RAILS_ENV=production bin/rake assets:precompile \
    && : enable resources back \
    && sed -Ei 's/^# TEMPORARY //' config/routes.rb

This particular solution might not work for you, since resources might be nested, and so on. You might try this:

RUN : comment out config/routes.rb so that it\'d not connect to db \
    && sed -Ei 's/^/# /' config/routes.rb \
    && RAILS_ENV=production bin/rake assets:precompile \
    && : uncomment config/routes.rb back \
    && sed -Ei 's/^# //' config/routes.rb

Never tried.

Another thing is that with puma one database connection per process is wasted (never used). Since puma's main thread boots a rails application (which connects to a database because of the globalize gem), and then it starts the worker threads. As such with globalize minimum number of connections (pool size) needed to serve requests is 2.

As it turned out I had eager loading turned off, and what triggered loading models was the methods I used in config/routes.rb to define resources. So, the solutions above are for the just mentioned case.

If eager_load = true you would run into the issue anyway. And then you can try the following patch:

module Globalize
  module ActiveRecord
    module ActMacro
      alias_method :old_check_columns!, :check_columns!
      def check_columns!(attr_names)
        return if ::ActiveRecord::VERSION::STRING >= "5.0" || ! connected?
        old_check_columns!(attr_names)
      end
    end
  end
end

I would also like to add that this applies outside of docker applications but in a similar situation. For instance, I have a VPC and when I deploy code to lambda or a server within the vpc it tries to connect to the database. Of course, I can't connect to the DB from my local machine-- and I definitely don't want to expose a DB instance.

Attempting to fix this in #737 when time allows, if you're able to help ๐Ÿ˜„

Thanks for the invite @parndt :D

Just a serious question, is it really necessary to check the column names with check_columns! and the intersection of the parent model? I had read it in the docs and that was enough for me... I mean by design its meant to have the attributes living on the translated model not the parent.

I can see this as a development utility but shouldn't be necessary in production anyway. So I would actually like to propose ditching the check altogether?

Interesting suggestion. Would you like to open a PR that does this so that we can review what the implications would be? A lot of people aren't going to read the docs, so we still need to make sure they won't be losing losing any data.

In a Rails app, the schema should be the same in development and production so I'm thinking your suggestion is a pretty good idea. ๐Ÿ˜„

stale commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

issue has open PR

stale commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

As it turned out I had eager loading turned off, and what triggered loading models was the methods I used in config/routes.rb to define resources. So, the solutions above are for the just mentioned case.

If eager_load = true you would run into the issue anyway. And then you can try the following patch:

module Globalize
  module ActiveRecord
    module ActMacro
      alias_method :old_check_columns!, :check_columns!
      def check_columns!(attr_names)
        return if ::ActiveRecord::VERSION::STRING >= "5.0" || ! connected?
        old_check_columns!(attr_names)
      end
    end
  end
end

@x-yuri I ran into this same problem, except that I also had to alias the allow_translation_of_attributes method.

module Globalize
  module ActiveRecord
    module ActMacro
      alias_method :old_check_columns!, :check_columns!
      def check_columns!(attr_names)
        return if ::ActiveRecord::VERSION::STRING >= "5.0" || ! connected?
        old_check_columns!(attr_names)
      end

      alias_method :old_allow_translation_of_attributes, :allow_translation_of_attributes
      def allow_translation_of_attributes(attr_names)
        return if ::ActiveRecord::VERSION::STRING >= "5.0" || ! connected?
        old_allow_translation_of_attributes!(attr_names)
      end
    end
  end
end

@rsmithlal hey, can you please check out #737 and let me know what you think?

Our team faced this same exact issue. As a workaround, we ended up using NullDB as the database adapter during asset precompilation.

First, install the gem by adding this to your Gemfile:

gem 'activerecord-nulldb-adapter'

Then move your default database adapter into an environment variable inside config/database.yml:

default: &default
  adapter: <%= ENV['DB_ADAPTER'] ||= 'postgresql' %>

Finally, set the DB_ADAPTER to nulldb when precompiling your assets:

bundle exec rake assets:precompile DB_ADAPTER=nulldb

We have a fix in #737 it's just awaiting time allocation to fix the tests

easy fix for this bug is need to if connected? validation before translate method on each model

Can you please try #737 @saiqulhaq-hh because this is what we've added but we're having issues with getting tests to pass with it ๐Ÿ˜‚ thanks