Skip to content

Commit ce8b43e

Browse files
committed
General cleanup
1 parent 86339c8 commit ce8b43e

18 files changed

+253
-151
lines changed

Gemfile.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ PATH
22
remote: .
33
specs:
44
brick (1.0.41)
5-
activerecord (>= 4.2, < 7.2)
5+
activerecord (>= 4.2)
66
fancy_gets
77

88
GEM

README.md

+99-33
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ so very easily brought into play by editing that file. Myriad settings are avai
8787
- [3.d. Tweaking For Performance](#3d-tweaking-for-performance)
8888
- [3.e. Using Callbacks](#3e-using-callbacks)
8989
- [4. Similar Gems](#10-similar-gems)
90-
- [Problems](#problems)
90+
- [Issues](#issues)
9191
- [Contributing](#contributing)
9292
- [Intellectual Property](#intellectual-property)
9393

@@ -103,30 +103,61 @@ so very easily brought into play by editing that file. Myriad settings are avai
103103
| 1.0 | 1-stable | v1.x | >= 2.3.5 | >= 4.2, < 7.2 |
104104

105105
Brick supports all Rails versions which have been current during the past 7 years, which at
106-
the time of writing (July 2022) includes Rails 4.2.0 and above. If you are using any version
107-
older than Rails 5.0, then you MUST have this to be the last line in boot.rb:
106+
the time of writing (July 2022) includes Rails 4.2.0 and above. Rails 7.x and 5.x apps work
107+
staightaway with no additional changes.
108+
109+
Rails 6.x uses an interim version of Zeitwerk that is not yet compatible with The Brick, so for
110+
those versions you must use classic mode. (This is generally the default for Rails 6.0.) If
111+
you see the error "uninitialized constant _____" then you need to add this line in
112+
application.rb:
113+
114+
config.autoloader = :classic
115+
116+
In Rails 7 and later the Zeitwerk loader is fully functional, so no autoloader compatibility
117+
issues. As well Rails 7.0 and 7.1 are the versions which have been tested most extensively.
118+
119+
When used with really old versions of Rails, 4.x and older, Brick automatically applies various
120+
compatibility patches so it will run under newer versions of Ruby. This makes it easier to
121+
test the broad range of supported versions of ActiveRecord without having to also use older
122+
versions of Ruby. If you're using Ruby 2.7.5 then any Rails from 4.2 up to 7.1 will work, all
123+
due to the various patches put in place as the gem starts up. Rails 4.x has not been tested
124+
very extensively, and as well when using those older versions then you MUST have this to be the
125+
last line in boot.rb:
108126

109127
require 'brick/compatibility'
110128

111-
(Definitely try this if you end up seeing the error "undefined method `new' for
129+
(Definitely try this patch any time you see the error "undefined method `new' for
112130
BigDecimal:Class (NoMethodError)".)
113131

114-
Rails 5.x apps work staightaway with no additional changes.
132+
The Brick notices when some other gems are present and makes use of them -- most notably
133+
composite_primary_keys which allows very tricky databases to function. As it stands, when
134+
database table and column names are not named according to Rails' conventions, The Brick does
135+
quite a bit to accommodate. But to get multiple-column primary and foreign keys to work,
136+
then composite_primary_keys is required. Just bundle it in and The Brick will leverage this
137+
gem in order to make everything work.
115138

116-
Rails 6.x uses an interim version of Zeitwerk that is not yet compatible with The Brick, so at
117-
this point you must use classic mode. It's the default for Rails 6.0, and for 6.1 you need to
118-
add this line in application.rb:
139+
Another notable set of compatibility is provided with the multitenancy gem Apartment. This is
140+
the most popular gem for setting up multiple tenants where each one uses a different database
141+
schema in Postgres. The Brick is able to recognise this configuration when you place a line
142+
like this in config/initializers/brick.rb:
119143

120-
config.autoloader = :classic
144+
Brick.schema_behavior = { multitenant: {} }
121145

122-
In Rails >= 7.x the Zeitwerk loader is fully functional, so no compatibility issues. As well
123-
this is the version of Rails which has been tested most extensively.
146+
If you provide a sample representative tenant schema that is bound to exist then it gets even
147+
a little smarter about things, being able to auto-recognise models being used on the has_many
148+
side of polymorphic associations. For example, if globex_corp is a schema that has a good
149+
representation of data, then you might want to use this line in the brick initialiser:
124150

125-
When used with various older versions of Rails, Brick automatically applies various
126-
compatibility patches. This makes it easier to test the broad range of supported versions of
127-
ActiveRecord without having to mess with older versions of Ruby. If you're using Ruby 2.7.5
128-
then any Rails from 4.2 up to 7.1 will work, all due to the various patches put in place as
129-
the gem starts up.
151+
Brick.schema_behavior = { multitenant: { schema_to_analyse: 'globex_corp' } }
152+
153+
The way this auto-polymorphic discovery functions is by analysing all existing types in the
154+
_type columns of these associations. For instance, let's say you have an images table with the
155+
columns `imageable_type` and `imageable_id`, and a goal to have the `Image` model get built out
156+
with `belongs_to :imageable, polymorphic: true`. In that case to properly establish all the
157+
inverse associations of `has_many :images, as: :imageable` in each appropriate model, then
158+
whatever schema you choose here needs to have data present in those polymorphic columns that
159+
represents the full variety of models that should end up getting the `has_many` side of this
160+
polymorphic association.
130161

131162
### 1.b. Installation
132163

@@ -142,7 +173,22 @@ To configure additional options, such as defining related columns that you want
142173

143174
Inside the generated file many options exist, and one of which is `Brick.additional_references` which defines additional foreign key associations, and even shows some suggested ones where possible. By default these are commented out, and by un-commenting the ones you would like (or perhaps even all of them), then it is as if these foreign keys were present to provide referential integrity. If you then start up a `rails c` you'll find that appropriate belongs_to and has_many associations are automatically fleshed out. Even has_many :through associations are provided when possible associative tables are identified -- that is, tables having only foreign keys that refer to other tables.
144175

145-
## Problems
176+
## Issues
177+
178+
If you are using Rails 6.0 or Rails 6.1 and see:
179+
180+
uninitialized constant _______
181+
182+
(Where _______ is the name of some model or controller class you're hoping to reference) then
183+
in your application.rb file, make sure this configuration setting is in place:
184+
185+
config.autoloader = :classic
186+
187+
Every effort is given to maintain compatibility with the current version of the Rails ecosystem,
188+
so if you hit a snag then we'd at least like to understand the situation. Often we'll also offer
189+
suggestions. Some feature requests will be enteratined, and for things deemed to be outside of
190+
the scope of The Brick, an attempt to provide useful extensibility will be made such that add-ons
191+
can be integrated in order to work in tandem with The Brick.
146192

147193
Please use GitHub's [issue tracker](https://github.com/lorint/brick/issues).
148194

@@ -159,37 +205,57 @@ DB=sqlite bundle exec appraisal
159205

160206
See our [contribution guidelines][5]
161207

162-
## Setting up my MySQL
208+
## Setting up for PostgreSQL
209+
210+
You should be able to set up the test database for Postgres with:
163211

164-
If you're on Ruby 2.7 or later:
165-
sudo apt-get install default-libmysqlclient-dev
212+
DB=postgres bundle exec rake prepare
166213

167-
On OSX / MacOS with Homebrew:
168-
brew install mysql
169-
brew services start mysql
214+
And run the tests with:
215+
216+
bundle exec appraisal ar-7.0 rspec spec
217+
218+
## Setting up for MySQL
219+
220+
If you're on Linux:
221+
```
222+
sudo apt-get install default-libmysqlclient-dev
223+
```
224+
225+
Or on OSX / MacOS with Homebrew:
226+
```
227+
brew install mysql
228+
brew services start mysql
229+
```
170230

171231
On an Apple Silicon machine (M1 / M2 / M3 processor) then also set this:
172-
bundle config --local build.mysql2 "--with-ldflags=-L$(brew --prefix zstd)/lib"
232+
```
233+
bundle config --local build.mysql2 "--with-ldflags=-L$(brew --prefix zstd)/lib"
234+
```
173235

174236
(and maybe even this if the above doesn't work out)
175-
bundle config --local build.mysql2 "--with-opt-dir=$(brew --prefix openssl)" "--with-ldflags=-L$(brew --prefix zstd)/lib"
237+
```
238+
bundle config --local build.mysql2 "--with-opt-dir=$(brew --prefix openssl)" "--with-ldflags=-L$(brew --prefix zstd)/lib"
239+
```
176240

177241

178-
And once the service is up and running you can connect through socket /tmp/mysql.sock like this:
179-
mysql -uroot
242+
Once the MySQL service is up and running you can connect through socket /tmp/mysql.sock like this:
243+
```
244+
mysql -uroot
245+
```
180246

181247
And inside this console now create two users with various permissions (these databases do not need to yet exist). Trade out "my_username" with your real username, such as "sally@localhost".
182248

183249
CREATE USER my_username@localhost IDENTIFIED BY '';
184-
GRANT ALL PRIVILEGES ON duty_free_test.* TO my_username@localhost;
185-
GRANT ALL PRIVILEGES ON duty_free_foo.* TO my_username@localhost;
186-
GRANT ALL PRIVILEGES ON duty_free_bar.* TO my_username@localhost;
250+
GRANT ALL PRIVILEGES ON brick_test.* TO my_username@localhost;
251+
GRANT ALL PRIVILEGES ON brick_foo.* TO my_username@localhost;
252+
GRANT ALL PRIVILEGES ON brick_bar.* TO my_username@localhost;
187253

188254
And then create the user "duty_free" who can only connect locally:
189255
CREATE USER duty_free@localhost IDENTIFIED BY '';
190-
GRANT ALL PRIVILEGES ON duty_free_test.* TO duty_free@localhost;
191-
GRANT ALL PRIVILEGES ON duty_free_foo.* TO duty_free@localhost;
192-
GRANT ALL PRIVILEGES ON duty_free_bar.* TO duty_free@localhost;
256+
GRANT ALL PRIVILEGES ON brick_test.* TO duty_free@localhost;
257+
GRANT ALL PRIVILEGES ON brick_foo.* TO duty_free@localhost;
258+
GRANT ALL PRIVILEGES ON brick_bar.* TO duty_free@localhost;
193259
EXIT
194260

195261
Now you should be able to set up the test database for MySQL with:

Rakefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ task prepare: [:clean] do
5555
end
5656

5757
require 'rspec/core/rake_task'
58-
desc 'Run tests on PaperTrail with RSpec'
58+
desc 'Run tests on Brick with RSpec'
5959
task(:spec).clear
6060
RSpec::Core::RakeTask.new(:spec) do |t|
6161
# Hide list of specs

brick.gemspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ gem_spec = Gem::Specification.new do |s|
2929

3030
require 'brick/util'
3131

32-
s.add_dependency 'activerecord', ['>= 4.2', '< 7.2']
32+
s.add_dependency 'activerecord', ['>= 4.2']
3333
s.add_dependency 'fancy_gets'
3434

3535
s.add_development_dependency 'appraisal', '~> 2.2'

lib/brick.rb

+12-3
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ def relations
140140
(@relations ||= {})[ActiveRecord::Base.connection_pool.object_id] ||= Hash.new { |h, k| h[k] = Hash.new { |h, k| h[k] = {} } }
141141
end
142142

143+
def apartment_multitenant
144+
if @apartment_multitenant.nil?
145+
@apartment_multitenant = ::Brick.config.schema_behavior[:multitenant] && Object.const_defined?('Apartment')
146+
end
147+
@apartment_multitenant
148+
end
149+
143150
# If multitenancy is enabled, a list of non-tenanted "global" models
144151
def non_tenanted_models
145152
@pending_models ||= {}
@@ -447,7 +454,7 @@ def finalize!
447454
::Brick.relations.each do |rel_name, v|
448455
rel_name = rel_name.split('.').map(&:underscore)
449456
schema_names = rel_name[0..-2]
450-
schema_names.shift if ::Brick.config.schema_behavior[:multitenant] && Object.const_defined?('Apartment') && schema_names.first == Apartment.default_schema
457+
schema_names.shift if ::Brick.apartment_multitenant && schema_names.first == Apartment.default_schema
451458
k = rel_name.last
452459
unless existing_controllers.key?(controller_name = k.pluralize)
453460
options = {}
@@ -477,7 +484,8 @@ def finalize!
477484
# Older versions of ActiveRecord would only show more serious error information from "panic" level, which is
478485
# a level only available in Postgres 12 and older. This patch will allow older and newer versions of Postgres
479486
# to work along with fairly old versions of Rails.
480-
if Object.const_defined?('PG::VERSION') && ActiveRecord.version < ::Gem::Version.new('4.2.6')
487+
if (is_postgres = (Object.const_defined?('PG::VERSION') || Gem::Specification.find_all_by_name('pg').present?)) &&
488+
ActiveRecord.version < ::Gem::Version.new('4.2.6')
481489
::Brick::Util._patch_require(
482490
'active_record/connection_adapters/postgresql_adapter.rb', '/activerecord', ["'panic'", "'error'"]
483491
)
@@ -784,7 +792,8 @@ def build_left_outer_joins(manager, outer_joins)
784792
end
785793

786794
# Do this earlier because stuff here gets mixed into JoinDependency::JoinAssociation and AssociationScope
787-
if ActiveRecord.version < ::Gem::Version.new('5.0') && Object.const_defined?('PG::Connection')
795+
if is_postgres && ActiveRecord.version < ::Gem::Version.new('5.0') # Was: && Object.const_defined?('PG::Connection')
796+
require 'pg' # For ActiveRecord < 4.2
788797
# Avoid pg gem deprecation warning: "You should use PG::Connection, PG::Result, and PG::Error instead"
789798
PGconn = PG::Connection
790799
PGresult = PG::Result

0 commit comments

Comments
 (0)