Bug #18662
closedEnsure Taxonomix empty default scope isn't overridden by association scopes
Description
Since #16982, the following test fails on Rails 5:
HostsControllerTest#test_0009_should create new host with hostgroup inherited fields [/home/travis/build/domcleal/foreman/test/controllers/hosts_controller_test.rb:114]:
--- expected
++ actual
@ -1 +1
@
-nil
#<Environment id: 334344675, name: "production", created_at: "2017-02-23 13:29:27", updated_at: "2017-02-23 13:29:27">
(Note that actual/expected are the wrong way around.)
When a Taxonomix resource (e.g. Environment) has a default scope that is empty, i.e. the user has access to no resources, returning the scope where(:id => [])
under Rails 5 causes an issue with associations.
An association accessor merges rather than appending a scope to the default scope, so host#environment essentially merges a where(:id => environment_id)
scope to the default. On Rails 4.2, this doesn't merge correctly and so effectively ANDs the two where(:id..) clauses, so no record is found.
irb(main):001:0> Hostgroup.unscoped.first.environment
2017-02-24T10:13:41 [sql] [D] Hostgroup Load (0.6ms) SELECT "hostgroups".* FROM "hostgroups" ORDER BY "hostgroups"."id" ASC LIMIT 1
2017-02-24T10:13:41 [sql] [D] (0.1ms) SELECT "environments"."id" FROM "environments"
2017-02-24T10:13:41 [sql] [D] (0.4ms) SELECT "environments"."id" FROM "environments"
2017-02-24T10:13:41 [sql] [D] Environment Load (0.5ms) SELECT "environments".* FROM "environments" WHERE 1=0 AND "environments"."id" = ? ORDER BY environments.name LIMIT 1 [["id", 1]]
=> nil
irb(main):002:0> Hostgroup.unscoped.first.environment_id
2017-02-24T10:13:45 [sql] [D] Hostgroup Load (0.5ms) SELECT "hostgroups".* FROM "hostgroups" ORDER BY "hostgroups"."id" ASC LIMIT 1
=> 1
On Rails 5.0, this merges fully and so returns a simple where(:id => environment_id)
scope. This overrides the default scope, so host#environment now returns the environment even if the default scope doesn't permit access to it.
irb(main):001:0> Hostgroup.unscoped.first.environment
2017-02-24T10:13:05 [sql] [D] Hostgroup Load (0.2ms) SELECT "hostgroups".* FROM "hostgroups" ORDER BY "hostgroups"."id" ASC LIMIT ? [["LIMIT", 1]]
2017-02-24T10:13:05 [sql] [D] (0.1ms) SELECT "environments"."id" FROM "environments"
2017-02-24T10:13:05 [sql] [D] (0.1ms) SELECT "environments"."id" FROM "environments"
2017-02-24T10:13:05 [sql] [D] Environment Load (0.3ms) SELECT "environments".* FROM "environments" WHERE "environments"."id" = ? ORDER BY environments.name LIMIT ? [["id", 1], ["LIMIT", 1]]
[..]
1 row in set
Changing the default scope to generate a SQL string ('1=0'
) ensures the two clauses are combined rather than the default being overridden.
Also worth noting is that on develop, the test is checking that host.environment
is nil, because hostgroup.environment
now returns nil due to the default scope. It used to test, and should test, that the environment is present.