Transcript
Hello, friends, I have an exciting news to share with you after around four years of doing, uh, YouTube videos. I'm launch@superrails.com, a place where you can watch all the videos from YouTube plus exclusive member only, uh, content. And I'm trying to make it as good as possible. Now, previously I tried making actually a code, a long series about how I am building ship rails, but after 19 episodes, I understood that I can't really make it because it, it was consuming too much of my time, and I would need, uh, I think like 200 or more episodes to really make it good. You can't really, uh, think of, uh, concepts and, uh, spend a lot of time, uh, just, yeah, just thinking value are life coding. You should be delivering something, right? So, uh, yes, I have, uh, built super ales and here's the source code for super ales. And if you are a subscriber to Super Rails, then you will have, um, access to the code base that you can explore on your own. So basically, how does cprs work there through core elements, the most important element is the videos. So there are three videos and pro videos on the videos, uh, page. You can filter by raw or free, and by many different other parameters. Free videos are accessible to anybody. So let me open a free video and, uh, you see I can watch it and if I open a row, video Unity to be subscribed to be able to watch it. Now you see this user, he is, uh, subscribed. So if you can see this, uh, pro video, but if I log out or if I log in as an unsubscribed user, I will not be able to view this video. So I see this pay and I am prompted to subscribe. Then I've got playlists. It is series of videos that are best to watch in the specific order, and there are also tags, just videos that, uh, share something in common. Now let's have a look at the source code for RAs. So I've actually got, uh, the application cloned locally. Let's have a look at it. So, um, whenever I start looking at a new application, I usually start from the readme and, uh, after the readme, I go to the jump file. So what do you have in the jump file? Now? Everything is more standard. So Rails latest, uh, stable version, prop shaft, postgre, QL. Um, I've got request js that is not present in the default rails installation that I am, uh, using to make, uh, post and, uh, get requests with, uh, JavaScript. So actually this, uh, search is done with request js. So I am, uh, type in here and, uh, I make a request from JavaScript and return at Turbo Stream as a response. And you see I have playlists, Tags and videos in the response. Then, uh, I'm obviously using Tailwind. I'm using good job for processing jobs. I'm not using Sidekick because I don't want to have read this as a dependency and I'm not using solid queue because, uh, salt queue just didn't exist when I created this application. Nowadays, maybe I would use solid queue by default, but good job is doing the job and uh, it's good. Yeah, I'm just repeating myself. Then I'm using your B link and robocop to clean up my H tm L and RUBIC code. These are, I think, very important gems for you to have. And I'm using Faker. Now, in theory, I could, uh, just get rid of faker because I'm using, uh, uh, fixtures for my test. But, uh, I do need faker to mock my, uh, only out responses. Uh, I could in theory try abstracting, uh, also and get rid of faker. Then, uh, I'm using the GI in tasks for translations. You see in the application I have, uh, two languages, English and, uh, Spanish. So all the text are available in English and Spanish. Then, uh, this is just for system tests. Uh, then in the application have authentication only via auth. So you see you can log in with GitHub, with Google on Apple. Now, initially I was thinking of doing device and just log in with the email and password, but then I didn't want to connect an email service and thinking about email deliverability, email confirmations or send password. So I thought to go just with the, uh, social login flows. And also in theory, if you are building a content, uh, a, a private content sharing system like Netflix, you would want to fight, uh, against, uh, password sharing maybe. So with uh, social logins, it is hard do use to share passwords, and I'm using Stripe to process payments and subscriptions. Okta kit, because whenever a user subscribes and his subscription is active, he automatically gets access to the super rail code base you see as a private repository. But ascribed user, you have access. Then honeyed for error monitoring. Uh, Google, API client. Uh, I'm using this one for, uh, the YouTube, API. So I get the video data from YouTube. We'll see more about it later. And raw versus valve for performance monitoring. Let's have a look at the, the raw versus valve dashboard. So here is the dashboard where I see the first performing, uh, pages and, uh, maybe queries in my application and, uh, I can improve them. I can also see errors. Let's take last 24 hours. So there were a few errors, but by now I have already fixed them. Then, uh, I'm using AWS, uh, uh, S3 for storage. And the only thing I'm storing in the application is the video thumbnails like this. So the videos themselves are not stored in the application. They are actually embedded as, uh, an external either YouTube player or Vimeo player. Then, uh, active storage validations to ensure that, uh, the images that, uh, are uploaded are actually images and that they don't have too big of a file size acts as list to be able to order videos in, uh, a playlist. You see this one is first, second, and third, but I can change the order if I like, um, acts as voidable because users can add a video to a bookmark or mark the video as completed. Lemme try doing this. So, uh, I will mark like these videos, uh, as bookmarked, this one as completed. And if I go to the list of lessons, I can filter by bookmarked or completed lessons, uh, friendly ID because, uh, if I am trying to share, uh, records, uh, URLs in the socials, it looks better if, uh, the URL is more descriptive than just given an ID to a record, uh, page for infinite pagination. Here, you see I've got a list of posts, and whenever I scroll down, there's this infinite pagination going on. Uh, punit I needed, uh, in this application, I think only for, uh, VO uh, policy. Yeah, so I'm using pundit only for vo uh, ranac because it provides a wonderful, uh, uh, API for searching inside active record, and I'm using ranac for this, uh, search sidebar, uh, noticed for the notifications, actually, I tried going without noticed and building my own, uh, notification, uh, system. But in the end, I ended up with an API that was, uh, similar to noticed, and, uh, it didn't make sense to build my own thin virus. I could use this gem. So it is a good gem and recommend to use it. Then view components. I actually have quite a lot of components, uh, in the application and, uh, I scope the logic within the components. So there's, for example, this, uh, uh, where is it? Cloud component, oh yeah, base item component that, uh, a few other components inherit from and reuse, uh, different elements from this component. Then, uh, uh, meta tags so that, uh, the images I share on socials have nice previews. For example, uh, I'm sharing, uh, a link to this video. And you see this is a, a meta image. This is a meta description, so it looks quite good. Then shared on socials. Then, uh, inline, SVG. So all the S VGs in the application are rendered, uh, using the gem inline SVG. If you search for SVG in the code base, you see all the SVGs are just s VG files themselves. I don't trend the SVGs in line in the H TM L at all, and I think it's very good because, uh, if you just see something like this in your H TM L, you cannot process it with your head. Uh, but uh, I use in line SVG tag and uh, I will usually know, uh, I will see the name and I will know what SVG I'm actually using. Then red carpet and rules for markdown and synex highlighting inside markdown. Uh, I use these, uh, if I go to lessons, let's have a look at the comments. So here, for example, uh, I have a code block and some inline code elements, and, uh, they get, uh, uh, highlighted and they get displayed as markdown. Then side map generator, because if you go to slash uh, side map xml, you see it'll prompt you to download the site map. And I submit the site map to search engines, rails, I and n for translations, active link to actually, previously I made a video highlight link to current page where we implemented our own solution for highlight and link to current page. But, uh, the time I, uh, grew to learn that, uh, it is just better to use this gem that already has all the possible cases covered. And finally, I'm using VO and VO Pro for the backend. So, uh, let's actually try logging into the backend of the application. I can go to any of the lessons and as an admin, I can open here. I have, uh, I'm looking at the specific post from which I opened it. You see, I have, uh, the, uh, check mark two mug, the Episode Pro or free. I have a title, the body of the episode. I can, uh, edit it, like add a new cover image. I, uh, can add tags or add this, uh, episode to a playlist. And here I have a list of all my episodes in avo. I can also view them as a grid, and this looks actually much better, but displays less information. That's, uh, the trade off between a table view and a grid view. Also, I have some filters to see only the published videos or only the unpublished videos, and I have some actions, we'll come back to them later. Then I've got the playlists, I've got tags. So I do kind of all the content management from, uh, and again, a list of all the dimensions and a list of all the comments in the application. I also have users and plans. I'm not going to show them for the video and for privacy. And I also have the jobs from good job. So, uh, yeah, it's the good job dashboard. And I also have ome, let's see where I use ome. So I use it to generate, uh, open graph images. So, uh, basically I use firm to navigate to these URLs, take screenshots and store the screenshots in the application. And whenever I share a link on socials to, for example, the, uh, pricing page or to the text page, then this is going to be taken as the open graph preview image. Okay, so we had a look at the gem file. Uh, let's actually try running the application. Uh, I will say bundle then, uh, rails, the bid drop, the B created, the BI migrate, and, uh, let's run bin dev. So we are starting the server and going to run super rails on local host. So by running Bin Dev, let's have a look at the profile. We run the rail server, we run the, the changes in vin. We start the, uh, good job, uh, worker. And we also listen to the stripe web hooks on local host. So here I have the application. You see, I don't have any lessons. Let's try logging in. I already have my, uh, uh, secret credentials set up so I can look in and, uh, I'm automatically redirected to the pricing page. I don't have any lessons, nothing. Now let's make this user and admin. So I will, uh, say Rails console user dot account, one user first, do update admin. True. Let's click and start the real server once again. Now I refresh the page. And here you see, the user now has admin access. Let's actually change the language back to English. So let's go to admin. Okay, I'm in the admin console. I have just one user and, uh, none of anything else. And in the post I have this action to input videos from YouTube. Now, how does it work? Let's have a look at vo. So VO posts. So we have this post resource, and here we have actions. Inside actions. We have this YouTube list videos job. Let's open this job and see it runs. Uh, so this job from, uh, avo, this, uh, action runs the YouTube list videos job, and the YouTube list videos. Job Makes a request to my, uh, API key for YouTube. And, uh, it, uh, tries to get all the videos from a channel. Actually, I started to get just five, uh, videos on the development. So it's going to make an API call to YouTube, get my videos, and, uh, store them in my application using this create video job. So here I am, uh, creating posts based on, uh, the API response from YouTube. Let's try running this, uh, job. Going back to the console. Console. See, a lot of good jobs are running. Let's refresh. And here I have imported a few videos. Okay, here they are. Looks, uh, quite good. I can, uh, open one of the videos and let's mark it, uh, as a pro video. So let's navigate back to the application. And here you see, uh, you need to be subscribed to view this video, but you can view all the other videos without a subscription. So let's click on this button and actually subscribe. I'm going to, uh, initiate the subscription. So you see it is opening the Stripe checkout. In this case, it is an embedded Stripe checkout. Let's input our card information name. You see, I also have enabled, uh, this check mark tool and purchase as a business so that the companies can, uh, uh, return VAT and integrate terms of service and privacy. Uh, in theory, you can, uh, also upgrade to have two months free with an annual subscription. Let's click to subscribe and, uh, let's see what's happening in the background. So here's the subscription going on a lot of web hooks and so on. Uh, let's have a look at the, the Stripe F Hooks controller. Oh, you see, I was, yeah, I have subscribed. So you see I have the subscription. You should, you see subscription active Next billing date, uh, current plan features, and I have the button to manage billing. Okay, let's have a look at the, uh, F Hooks controller. So here is the great action. I'm doing the authentication. Then, uh, I handle the subscriptions. So when the subscription has been created, I, um, update the, uh, plan of the user. And if the user subscription is active, then I, uh, invite him to access the GitHub private repositories like superl.com and, uh, also, and user within an active subscription has access to the pro videos. So let's now try having a look at one of the pro videos. Going back, let's open the Pro video. And you see I can view this video. Now, going back to my profile, I can go to manage billing and it opens the Stripe billing portal where you can, uh, either cancel a subscription or upgrade the subscription and see the billing history. So you see, I'm trying to outsource as much payment logic, uh, from my application to Stripe as possible. But there are a few things that I still keep in my application. For example, uh, that logic of being subscribed is the user subscribed or not. So a user has one plan, and when a user is, uh, created, we create the plan for the user. So let's have a look at the plan. Basically, the plan is the place where the store all the information about the current subscription. You see, we have user a plan update, and we update the user's plan whenever he has, uh, changed his subscription status in Stripe. And, uh, here the main thing is to check that the subscription is active. It is active if the end date of the subscription is in the future, and if the subscription status of column in Stripe is also active. So going back to the application here, the user is active and he can manage his billing looks good. Now, I was thinking of maybe using a gem like pay to, uh, manage subscriptions, but, uh, actually doing subscriptions, uh, with Stripe without any additional gems except just the Stripe. API Gem was, uh, enough. Okay, so we had a look at subscriptions. Now, usually after having look at the GEM file, I have a look at the schema. So let's have a look at what models there are in the application. So we've got a lot for active storage attachments. It's all for attention images to post. Then we've got comments. Uh, a post can have multiple comments. Initially I was thinking of doing comments polymorphic because a comment can belong to a post and to a comment within a comment. Uh, let's have a look at some comments. So let's go to lessons. Most commented, you see there's this three of, uh, comments and, uh, each of these comments belongs to the post. So we can know how many comments the post has in total, but each of them can in theory also belong to another comment. And you see this quite easy to build this kind of comment, trees, and you can reply to any and create new trees. I will open one of them and you see, I can, uh, each comment has its own page and I can go one level up, one level up and, uh, or just view the post all the comments. So I'm quite happy with the way the comment structure is built. Then we've got the good job tables, quite a few of them then mentions. So you can mention other users, like at the, um, somebody and the user should get a notification that he has been mentioned. Uh, noticed advanced notifications. So it is again for, uh, this feature to have an inbox with, uh, mentions or information about new videos being published. Uh, then we've got, uh, plans. We already talked about plans. A user has one plan, and then the main logic of the application. So, uh, a lesson can be in a playlist, so in multiple playlists and a lesson can have multiple texts. So, uh, post has many playlists through playlist posts. Post has many tags through post tags. This is the core of the application itself, what the application is delivering. Then we've got the user's table. And again, I, uh, even don't need to have an email, uh, for the user because all the users send in with, uh, uh, their social accounts. So email can be null in my case. And, uh, votes for X as voidable that I'm using for bookmarks and marking lessons as complete. Okay. So we had to look at the schema and usually have to look in the gem file and the schema. I also have a look at the roots of the application to have a good understanding of what is generally going on. So this is all generated by a new rails, uh, eight, uh, applications, uh, generation. Then site map to submit to the, uh, search engines feed to submit to RSS readers. Uh, if few static pages about application, then the authentication, you see, it is all built from ground up without device and any other external libraries, just the omni au uh, libraries. Then only a user that has an admin role can access AVO to manage the content. And a good job to see the job processing. Uh, I've got, uh, testimonials. Again, only a signed user can access the checkout s billing portal. Obviously notifications read all. So, um, here I have this, uh, kind of clear button or read all to hide all notifications. I click it and you see the notifications are empty. Now, uh, the pricing page, uh, the Stripe webhook, that has to be, uh, accessible without setting current user. Uh, search for this global search that is accessible on any page. Uh, post, have many comments. A post can be marked complete or voice listed. Uh, the landing page. So static index, uh, playlists only index and show, uh, on the front end. They cannot be managed. It, it's all managed like creation, uh, edit and delete is managed through. And the, the tree of comments. So you see the roots are also quite simplistic. Now, I've actually written quite a lot of tests in the application. I'm using the mini test, and, uh, I'm trying to leverage, uh, uh, fixtures as much as possible. Initially, I was more used to using APEC and uh, factories, but, uh, I, uh, came to like fixtures and, uh, they said that re using fixtures is faster than re using factories. Okay. So yes, this is basic overview of, uh, the application. So we managed to, uh, have a look at the basics of the code base. We managed to launch the application locally, set ourselves as an admin and access the AVO content management, uh, part of the application where we can, uh, create new posts. Uh, we can input them from YouTube if you have the API keys, uh, and, um, add the post to a playlist or add text to post. And, uh, yeah, I think, uh, that's about it. So, uh, I invite you to subscribe to SIP Rails. It'll really help me, uh, keep, uh, creating, uh, good videos, uh, uh, for you to watch and learn from. And, uh, yes, uh, if you subscribe, you also get access to the Superl code base. So thanks for watching and see you in the next one.
1