From the GoRails video:
https://gorails.com/episodes/subdomains-and-multi-tenancy-from-scratch
Their Rails 4.2.1 example code:
https://github.com/gorails-screencasts/gorails-episode-48
I first created the project in Rubymine as Rails app using:
- rails 7.0.4.3
- ruby 3.2.2
- database: postgresql
- javascript: esbuild
- additional option:
- --css bootstrap
After project setup in Rubymine, add .idea to .gitignore file.
Then ran:
bundle exec rake db:drop db:create db:migrate db:seed
Commit: 'Initial project setup', d4722c4
Added devise gem in the gemfile then ran bundle:
bundle
Then ran devise install:
bundle exec rails generate devise:install
Then created the devise user:
bundle exec rails generate devise User name
And created an "account" model as the subdomain holder:
bundle exec rails generate model Account subdomain user_id:integer
Lastly, I scaffolded the posts with an account_id because the Account will be loaded on each request based on the subdomain:
bundle exec rails generate scaffold Post title body:text account_id:integer
Then ran the migrations:
bundle exec rake db:migrate
Commit: 'Added devise, used generators to create objects needed for the rest of the application', 2b6ce3d
I then added the simple account/subdomain before action in application controller and setup the routes.
Commit: 'Setup subdomain before_action', 414f75f
Part of why I created such a small previous commit was to isolate the handler code for easy reference. A secondary benefit was at this point in the video, the local domain 'lvh.me' was used. In Rails 7 (6.1?), you have to specify the hosts. So the following commit calls out a modern Rails way to handle the (sub)domain.
Commit: 'Rails 7 host config', 6eb6794
Next I generated the devise views to add account to sign up:
bundle exec rails generate devise:views
Then I added account to the sign up form.
Then added the before action in application controller to allow devise to accept the nested account attribute 'subdomain'.
The models were modified to setup active record relations, as well as create an account when saving a new user.
Devise has changed since the video was made, so I had to modify the before action in the application controller
From the video:
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) { |u|
u.permit(:email, :password, :password_confirmation, account_attributes: [:subdomain])
}
end
...and the new way of doing it:
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:account_attributes => [:subdomain]])
end
From this point I was able to create an account and user, and login using 'example.lvh.me:3000'.
Commit: 'Devise sign up accepting account', 45efe17
I then added active record relations to the post and account models linking them together.
Then edits the posts controller to pull from @account.posts instead of Post now that @account ought to be set by the application controller.
I also removed the account_id from the posts _form partial. This illustrates that the account is being set automatically.
Following the video, I opened a private browser window and created a new user and new account called "test".
This is shown in the video using "example.lvh.me:3000" and "test.lvh.me:3000".
Just "lvh.me:3000" will not work because the subdomain is required in the posts controller now.
The host Chris Oliver makes the statement that this subdomain project can go many different directions at this point.
Sounds like a good time to commit.
Commit: 'Isolating posts by account/subdomain', f88579c
The last change in the video is to add a require_account! before action in the posts controller.
This prevents someone from getting to the posts controller without an account.
If you try to navigate to 'lvh.me:3000' after that, you will not get a page because the root goes to posts#index in the routes file.
I'm adding this from the comments in the video:
Chris Collinsworth on Jan 30, 2016
Is there anything special that needs to be done to continue to use devise helpers like current_user or user_signed_in? inside of a multitenant app?
Reply: Chris Oliver on Jan 30, 2016
Nope, that should still work out of the box. Server side will just continue to set cookies, but will only match users available for the current tenant.
Reply