switching adapters in rails and generated sql - ruby-on-rails

I'm writing a multi-tenancy gem for rails
My tests right now establish connections for a particular adapter, run some tests, then repeat for subsequent db adapters.
My problem however is that when I call:
ActiveRecord::Base.establish_connection
with a different adapter, the sql generated from it is still in the form of the old adapter. For instance, I run the mysql tests, then try to run postgresql tests. I get an error:
Failure/Error: subject.create(database1)
ActiveRecord::StatementInvalid:
PGError: ERROR: syntax error at or near "."
LINE 1: SELECT `users`.* FROM `users` WHERE `users`.`name` = 'Some ...
^
: SELECT `users`.* FROM `users` WHERE `users`.`name` = 'Some User 0' LIMIT 1
And it's obvious here that it's using the mysql backslash syntax, which isn't valid in postgresql.
So... does anyone know how to establish a connection with a different adapter properly? I've tried:
ActiveRecord::Base.connection.reconnect!
ActiveRecord::Base.clear_all_connections!
Neither of these fixed my tests. Any help is greatly appreciated.

See if this helps
ActiveRecord::Base.send(:subclasses).each do |model|
model.connection.clear_query_cache
end

Related

Active Record getting PG::InsufficientPrivilege: ERROR: when permission exits for the user

We are using the Gem PaperTrail, so in postgres we have a table called xxx.versions.
Through rails consoles locally we try to query the db through the PaperTrail Object:
PaperTrail::Version.first
PG::InsufficientPrivilege: ERROR: permission denied for relation versions
: SELECT "versions".* FROM "versions" ORDER BY "versions"."id" ASC LIMIT 1
but if I access the table like this:
ActiveRecord::Base.connection.execute("SELECT * FROM xxx.versions limit 1")
a record set is returned.
This only happens when we try and connect to the db from our local machines.
If I run PaperTrail::Version.first from the rails console on one of the qa servers it connects just fine.
Other troubleshooting details:
I have used the same credentials as the qa server and received the
same results.
On my local machine, I can query the DB from
DataGrip/pgadmin just fine outside the rails project.
There are several possibilities:
You use a different PostgreSQL user or database in both attempts.
There is a different relation versions in another schema that is before xxx on the search_path.

Rails: find_by fails in test, works in production

I'm still a bit of a newbie, and I'm stumped: I have a 'find_by' statement that works fine when it's executed in a production environment, but it fails during a test, with what is, as far as I can determine, identical input.
I have a very simple table, populated by seeds.rb as follows:
Nonprofit.create!(id: 1, name: "Nonprofit number 1")
Nonprofit.create!(id: 2, name: "Nonprofit number 2")
In my sessions controller, I have the following two statements:
puts "=======>" + params[:nonprofit_id] + "<=============="
nonprofit = Nonprofit.find_by(id: params[nonprofit_id])
puts "=======>" + nonprofit.name + "<=============="
In the production environment, the log shows this:
Processing by SessionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Mm7qVchebMORY5QBOlvl1ac69m1ACwttXcE71LbfHnHH2RqpB6mSP+wFxodop/9Mgv/NlLO9V9NVEcTU1a54tw==", "session"=>{"email"=>"jane#rich.com", "password"=>"[FILTERED]", "remember_me"=>"0"}, "nonprofit_id"=>"1", "commit"=>"Log in"}
==================>>>1<=========
Nonprofit Load (0.3ms) SELECT `nonprofits`.* FROM `nonprofits` WHERE `nonprofits`.`id` = 1 LIMIT 1
==================>>> Nonprofit number 1
In other words, ActiveRecord finds the correct table entry using the id value of 1.
The log from the test run shows exactly the same output from the 'puts', but then it errors out on the second 'puts' because (presumably) the find_by didn't find the record. Here's the log from the test run:
Running:
==================>>>1<=========
E
Finished in 0.467105s, 2.1408 runs/s, 0.0000 assertions/s.
1) Error:
UsersIndexTest#test_index_as_non-admin:
NoMethodError: undefined method name' for nil:NilClass
app/controllers/sessions_controller.rb:14:increate'
test/test_helper.rb:19:in log_in_as'
test/integration/users_index_test.rb:29:inblock in '
Any ideas/suggestions? Alternatively (or in addition) how can I cause the test run log to show the active record query, like the log shows for the production run?
Thanks!
Your test can't find the record you're looking for because Rails does not load seed.rb into the test database.
You should use something like FactoryGirl, Fixtures or just create the records in the before(:each) block. Any Rails testing tutorial will have something to say about Fixtures, FactoryGirl or some other way to get data into your tests. This may be a good way to start.
Alternatively, if you really need to load what you have in seeds.rb into your testing database, you could try doing this.
Rails works with different environments. While testing your're (duh) on test environment. When running your application locally (with rails server) you are on development environment. When running on a server, it's supposed to be on production environment.
Each environment has its own database. I suppose you ran 'rake db:seed' and thought it'd populate your test database, but it's not true. That's why it isn't finding the record - on test database it doesn't exist.
As pointed out by #pggaspar you should be working with factories or fixtures to populate your test database.

How to execute PostgreSQL slash methods on ActiveRecord?

I am using Rails 4. I am trying to list all PostgreSQL databases with '\l' using 'execute' method from ActiveRecord. Connection is correctly established.
p = ActiveRecord::Tasks::PostgreSQLDatabaseTasks.new(configuration)
p.send 'establish_master_connection'
p.connection.execute('\l')
Here is the error:
ActiveRecord::StatementInvalid (PG::SyntaxError: ERROR: syntax error at or near "l"
When I use 'no slash' method it works fine
connection.execute("DROP DATABASE IF EXISTS NOTHING")
=> #<PG::Result:0xc5e6094 status=PGRES_COMMAND_OK ntuples=0 nfields=0 cmd_tuples=0>
Any idea?
You can't. Commands beginning with \ are meta commands implemented by the psql shell itself - the database server itself doesn't know what they mean.
In the particular case of the commands listing various things, this normally boils down to querying tables in pg_catalog e.g.
SELECT * FROM pg_catalog.pg_database
for databases
SELECT * FROM pg_catalog.pg_table
for tables. These are documented here

rails difference between Model.count and Model.count(:all)

Is there any difference between
User.count
and
User.count(:all)
I upgraded rails to 4.0 then when I use ModelName.count(:all) it's working well but if I use ModelName.count the following error occurs.By the way bot of them is working well in rails 3.2
SELECT COUNT() FROM "users"
PG::WrongObjectType: ERROR: count(*) must be used to call a parameterless aggregate function
LINE 1: SELECT COUNT() FROM "users"
I ran into this issue as well. The change was introduced in this commit. A line like
User.count
will now throw an ActiveRecord::StatementInvalid error since it will generate SELECT COUNT() FROM users on Postgres. As of this commit, the fix is to update your code to
User.count(:all)
This commit restores the functionality that existed previously, using :all as the "column" to pass on to ARel, causing a valid SQL query SELECT COUNT(*) FROM users.
My Gemfile originally had the following (as mentioned in the comments)
gem "rails", github: "rails/rails", branch: "4-0-stable"
but I needed to run bundle update rails to pull down the newer commit referenced above.
I guess there is no difference between them
http://apidock.com/rails/ActiveRecord/Calculations/count
http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-count
By not passing any parameters to count, it will return a count of all the rows for the model.

Force $ rake db:reset Despite Other Users with Postgres [duplicate]

This question already has answers here:
Rails + Postgres drop error: database is being accessed by other users
(20 answers)
Closed 9 years ago.
Is there a way to force a database reset even if Postgres has other users using it. I almost always get this error when I try a $ rake db:reset:
Couldn't drop example_database_name :
#<ActiveRecord::StatementInvalid: PG::Error: ERROR: database "example_database_name" is being accessed by other users DETAIL:
There are 2 other session(s) using the database.
Put this in a file lib/database.rake if you find yourself using db:reset a lot in development.
require 'active_record/connection_adapters/postgresql_adapter'
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter < AbstractAdapter
def drop_database(name)
raise "Nah, I won't drop the production database" if Rails.env.production?
execute <<-SQL
UPDATE pg_catalog.pg_database
SET datallowconn=false WHERE datname='#{name}'
SQL
execute <<-SQL
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = '#{name}';
SQL
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
end
end
end
end
Obviously only designed for use on non-production databases. It will cause all existing db connections to be severed, so the next page load might be an error if unicorn/passenger/pow is pooling db connections. If this happens, a simple page refresh will cause the server to open a new connection and all will be well.
if the connected sessions are from your rails process - you definitely want to stop rails, strange things could occur if you drop and rebuild the db from underneath the running process
anyhow the following can be run from the command line to drop postgres connections
psql -c "SELECT pid, pg_terminate_backend(pid) as terminated FROM pg_stat_activity WHERE pid <> pg_backend_pid();" -d 'example_database_name'

Resources