Hi, My name is Andy Leverenz and I work as a Product Designer at Dribbble. For fun I design, code, and write. Check out my blog called Web-Crunch where I publish design and development tutorials with the occasional vlog.
PART 3 of 7
Welcome to my 13th Let’s Build: With Ruby on Rails. This build will feature a multitenancy workout app which uses a popular gem called Apartment, nested attributes, and Vue.js integration.
We’ll be building a workout tracker type of app to demonstrate the multitenancy approach to a. web app with Ruby on Rails. Working locally we will utilize a `lvh.me` domain (a domain registered to point to `127.0.0.1`) to allow our app to function as it should during development. Follow along using both the written guide and videos below to learn how to take advantage of what Ruby on Rails and the multitude of gems available offer us.
What’s in this video?
Having setup the app we dive deeper into integrating the subdomain portion of the rails application.
⚙️ Source Code:
💻 Previously published at:
💻 Check out the blog:
🔭 Check out my app:
💡 👫 Check out my agency:
🦄 Check out my personal site:
📘Check out my book on UX Design:
“LUXD: Learn User Experience Design”
📙 Check out my FREE book on Tumblr Theming:
“Pro Tumblr Theming”
💯 Need awesome web hosting? Check out cloudways. They allow me to use a variety of hosting providers and build apps with ease:
🌊 Need more advanced hosting for Rails, PHP, Node, or other projects? Digital Ocean has you covered.
💎 Ruby on Rails devs, Try HatchBox.io. You’ll save upwards of 50% compared to Heroku. I use it and love it!
☕️ 🙏🏻 Patreon
☕️ Or buy me a coffee
all right so the user model is going to be more or less our source of truth for a tenant and the subdomain they're affiliated with so when my user creates their new account they need to be associated with that subdomain field we've hadded the way to scope it with devise is to actually use a few tweaks in bells and whistles to make that happen so we need to actually backtrack a few things that have already been installed so the validator bowl is going to be one of those we actually want to remove this completely and then we want to actually use request keys here and then we're gonna source our sub domain through that so this is gonna like basically the concept here is to allow the user to scope their credentials to other domains as well as make it more approachable for people who want to sign up given their own domain and then also persist their login across the domain so it's kind of a confusing and crazy crazy concept but it does end up working pretty well so we need to do a few things when a new user is created though so if you've created a user already probably just hold off if I were you but if you have already it's not gonna have any of this associated with it so it's just kind of one of those dark areas that's gonna be persistent until we get the model in order so we can do at some fancy stuff with rails where you can do things after a model is created or deleted here we're gonna do one called create tenant and then we'll have one that says after destroy say delete tenant so we shouldn't have a tenant after they deleted their account right that makes sense to me okay so one thing I want to do is validate the email this is just a small enhancement here it's just saying it's unique when a user signs up and you'll see that Y that we have to run a migration here to change a few things in our devise schema so let's first create these methods and then we'll go back and do that create tenant and this will hook it now apartment and then the tenant class and then go to the create method and then we'll pass in the subdomain created like it's ball domain okay so that's that one delete is very similar permit to drop subdomain and then there's this fancy one from devise where we need to kind of make sure there's conditions on the login once its scoped to the sub domain so it's a little fancy and I actually pulled this from the devise read me but we're basically doing this find or authentication warden conditions this is a little over my head to be honest but it's something that needs to happen so say we're email warden conditions then won't pass in email and then sub domain warden conditions sub-domain and then we'll call the first one cool so hopefully that works in that documents or just read me should say you might see it written like this and that's just an older way to write the same thing so I prefer the non hash rocket approach personally so looks cleaner okay so with that we still need to run that migration I mentioned so let's get devised to work with us here okay so the migrations gonna look like this and then we're still gonna have to tweak a lot of other stuff too so I'm gonna go in a new tab zoom in on this for ya web crunch will go to workout tracker there we go and we'll run our migration so I want to call this rails generate migration reindex users by oops by email and subdomain so by default it is just the email I believe so we'll run this and we'll do our our own oh I didn't mean to delete that let's say rails Jen should be G naught D there we go I don't think there was anything that delete there by default so I think we're safe so we'll go into the database go and hit that migration it's gonna look like this we want to actually go old-school and do it def up and add F down and with that we'll remove index users from the users table and email and we'll add index email sub-domain and we want those to be unique from the data side so we've got that validation already in that place but this is making sure it's super validated and then we'll just kind of undo that in the down statement so you're just basically swapping things here so we'll say users and an email and then add an X users email unique groups unique true so this is because if you were to scaffold your own user authentication system it would be different here but devise comes by default scoping it to the email on adding index on that by default but we want to add a additional scope of subdomain and make them unique per user all right so that's kind of complicated but it ends up making this work so I'm all cool with that it's then we'll just do where ails DB migrate so you keep getting this message but we did get our actual migration invoked so that's good it's gonna have any tenants yet so that's one thing we need to actually create an account but before we do that I want to modify a few things to make this still work so our routes need to be updated too and basically when the user signs up I want them to be redirected to their subdomain that that shows and to do that we need a few constraints in the routes directly so let's go to config routes and by default we have devised and our route to home index which is good delete this comment but we want to do a bit different with the routes by default and you can actually append a class to this and I'll probably reference to my other app just so I don't mess this up royally but our general concept is to generate this class and then do a resources on the eventual workouts model that we'll have so we might need to generate that to be honest in this video so let's maybe rollin with our regular app so we want to have this class here and you can make this live elsewhere if you want to there is a folder called Lib and if you added a folder here called constraints which is what this is gonna be rails will not be smart enough to know that that's there but you do have to import it or require it just like this it's just an extra thing not necessarily important that you do that but it is something to keep in keep in mind so that's going to end up looking like constraints subdomain so we're just hooking into that class setup domain do block and then eventually this will be our resources workouts great so yeah we want to make sure the workouts and exercises are scoped to the subdomain because that wouldn't make sense otherwise within this class you can call which requests you don't want to permit so by default we want to make sure WW isn't and admins you could save whatever subdomains you don't want the user to actually visit and be able to visit so here's how you exclude those but we still do need to exclude it locally so the issue that were running into is you for localhost users you need to still scoped to have a root path to the app if you want it so say on our app let me pull up the browser are now it's localhost well we need to actually make use of the LVH me dot me root path now and so we can access that but i want to reserve this i don't want anyone to take this up or use WW and that's already configured and our initializer so what you can do is have a subdomain exclusion and the way i did it in our demo project is I created a folder that's called apartment and then within that is a this file plus the subdomain exclusion so initializers apartment our apartment file and then subdomain exclusions so I might do that in this one just to keep it consistent so I'm going to create a new folder apartment and we'll move this file into apartment so I'll move and we'll just say apartment so that's in there now and this other file will need to actually create it's going to be subdomain exclusions I can spell it I really can't spell it you xcl you si ons are be in that file we will have I'm gonna make sure there's not any more than what I'm thinking yeah it's just that one line it will be apartment the class of elevators sub domain not excluded subdomains rules so that's the one the route one we want to actually keep for ourselves that's so that's what that's saying so no one can sign up with that so now we can go and essentially scaffold that workouts model but one more thing for devise that's a kind of a gotcha that screwed me royally is one more file that doesn't exist here we'll create in the initializers and call it session store so this acts as a way to restore or keep your session through switching the subdomain so it's something to keep in mind so it generates a cookie in essence in your browser so your session is configured to use the LVH new instance of the sub domain it permits that so rails application dot config dot session store and then we'll do cookie store key and this will be basically pertaining to the name of your app so I'll just do workout tracker session and then domain will scope it to our LVH stop me for now great okay so I know this is confusing but that's just these steps to make devise play nice with a subdomain based environment just a little confusing to make work so to get this constraint to not air out let's generate our workouts controller and models and views and stuff next so I will do that now and we're gonna have just a few columns on it so I'm gonna use a scaffold just for example purposes so rails generate scaffold workout will have a title of string and again you could just pass title and it'll default to string I like to just be explicit and then a date for the workout and then we'll do date time for the type so we'll run that it will generate tons of files tests and stuff like that I want to definitely delete the scaffold CSS it generated get rid of that cool cool cool and now I can have our resources here it's already threw it in the file up here and I'll just move it so I'll save that and we should have access to those now through the sub domain that we persist there's more to do for the user model we've already done the migration we needed we need we did the model configuration and then we also need to do some application control or specific stuff so on our app we need a few more methods to do a few things so when it make private space and I'm going to go to our final application controller for reference here real quick all right so I'm gonna have a method called redirect to the subdomain so I'm gonna put this after this and it's going to be a before action and we're gonna do a redirect with this method so we're gonna say to have redirect I call it what we just called it end it and then inside that will return if self is a device controller it's basically anything to do with devise here it's a nice little hack to get in and you gotta spell it right though and then we'll do another if current user present just the current user is there and the request subdomain that's how you can hook into the actual request or essentially the URL is not equal to the you'd current user subdomain and we'll need another end and then inside that will redirect finally to workouts URL which will be their main space for creating workouts and will pass in the parameter of subdomain from the user itself like so so that's confusing as hell I know but basically it hooks into the controller make sure it's a devise one checks if the user is there and then the request they basically have a subdomain and it's not equal to their some domain if it is then we'll redirect them to their subdomain with their workouts path so it'll be basically like workouts like that on the URL but with their sub domain as the prefix to the main domain on top of that I want the user to after sign in this is part of device then we could do resource I'm gonna call it this resource or scope in that and then within that will just put root URL and then sub domain resource or scope sub domain so if they've already registered and they just sign in on their cell domain they'll be redirected to their cell domain as simple as that I think that's it for that I'm controller 1 1 gotcha though I want to make C footwork it's different on this machine but we'll see I'm going to do a rail server and try to create an account finally looks like we're already running I might reboot and go let's create an account I need to migrate though okay and this will go why once we finally create a user so I'll do that first I need a run server again refresh your friend redirect to sub domain ah I can't spell sub-domain all right cool all right let's sign up hopefully this works guys I didn't test it yet so okay we got something up create tenant did you meet create and it looks like our user model might be a little messed up let's go check that out create ten tenth tenant can't spell can't spell boy what I could do if I could spell all right let's reboot just because and try that again I don't think the user would save at that point so let's try with the same stuff it works cool so use all that all that junk we just did made us redirect to our actual scope of the app we have to use L eh me because we're local a production app you can you know establish those subdomains on your own you defi have to hook into some DNS fanciness to do so but it is possible it's beyond the scope of this tutorial but it's just kind of just showing you where he at least get started with this stuff so with that I think it's a good stopping point for this video because we have officially created a user we've got the user and we're updating it with all this stuff that we have on them now that the apartment gym is installed we shouldn't have now a database for web crunch yeah there we go very cool so that's all looking good and I think in the next few videos we'll work out the controllers for the workouts then we'll generate the exercises and then get into some of the views stuff so we'll see you in the very next video you