# Add Avo to existing app | SupeRails #218

- URL: https://superails.com/posts/add-avo-to-existing-app
- Published: 2024-12-16
- Duration: 22:45
- Access: free
- Topics: avo
- Playlists: AVO

Let's add Avo to an existing Rails app

0:00 generate Avo resources
4:48 add search
12:42 admin-only Avo access
17:10 styling

Change history:

- [generate Avo resources](https://github.com/yshmarov/moneygun/commit/8e206ee40eb9778820b6f3455178919f5c81ba82)
- [add search](https://github.com/yshmarov/moneygun/commit/21decdfbe257f55a615341f9efd420346839a042)
- [admin-only Avo access](https://github.com/yshmarov/moneygun/commit/8fae41451c9380f6002f6435dd018b424f564d7a)
- [styling](https://github.com/yshmarov/moneygun/commit/279403e174dff60a63bcdcf965da64626bbd40a8)

[All the changes together](https://github.com/yshmarov/moneygun/compare/main...add-avo-3)

## Chapters

- 0:00 generate Avo resources
- 4:48 add search
- 12:42 admin-only Avo access
- 17:10 styling

## Transcript

Hello friends. So in the previous episode, we added VO into a new ribbon rails application and used it with the Rails eight authentication generator. And now we are going to try adding VO to an existing, so not just to a new, but to an existing ribbon rails application. And we are going to use man gun, my ribbon rails, uh, multitenancy boiler plate as an example application. Don't forget to put a star. Okay? So here I have Mangan running and I have three main models in the application. I have the user model. The user can log in, the user can, uh, browse his organizations. He can create an organization, and he can be a member in multiple organizations. So three models, user, organization, and membership. We see that in this organization there are two users. One is an admin and one is a member. And I want to add AVO as an admin backend. So they're going to use AVO to be able to see all the users, all the organizations, all the memberships, and uh, do some moderation like, uh, uh, change, uh, a member in another organization from admin to member. Add the new organizations from the admin, uh, add, uh, users to, uh, organization. So anything as super admin would want to do. Okay, let's start with the going to the other homepage, um, VO HQ io. And here I have this, uh, app template. I'm going to run it, uh, in my repository. Uh, what is it doing? So it added VO to the GEM file. It, uh, added VO to the roots. So, uh, here I have this, uh, root AVA integration route path, and the avo initializer has a lot of, uh, defaults. And it says that the root path by default is ava. So if I navigate to slash Ava, I should be able to see the A dashboard. And it also tried creating a resource for users. So a resource is way to see a list of users with vo, it's like an VO scaffold where we have, uh, all the fields, uh, of the user defined, uh, based on the database, uh, schema. Uh, and, uh, these are based on the associations in the user model. So a user has many memberships, has many organizations through memberships. This is based on the user model. Okay, let's try, um, uh, run our application. Now, I need to restart because I added a new engine and I added a new initializer. And let's open our app and go to, uh, slash Okay, so here I have, uh, VO kind of runin. We have the, uh, default, uh, homepage, and let's try going to users. And, uh, it says polymorphic associations not support computing in the class. Okay? So, uh, if you go to our newly created, the user resource, this one, uh, he have, uh, uh, all these invitation fields, and we have this invited by type and invited by, uh, id, I will just comment them out for now. We don't need it. Okay. So here have, uh, users, we can see a list of users. We can try to create a new user. We can, uh, open a user. We can delete a user, edit a user. Okay? Now I open a user and I have this, uh, error membership field, uh, uh, not found because, uh, for our membership model, we also need a resource. So it prompts us to run rail, generate our resource membership. I can cope with this command and, uh, run it, uh, in my, uh, and so, or I can actually have a look how to generate all the resources for all our models for vo. So if I type rails, generate help here, I have all the prompts, and I also have the prompts for vo. So rails generate vo, uh, all resources. Let's try this. Command rails generate other all resources. Uh, no, I don't need to override user. Okay? And here I have, uh, the other resources generated for inbox membership, membership invitation, organization, transfer user. Okay? Now, a couple of them are empty because they're not backed by the database. I just don't need them. I can remove them. Uh, I also don't really need the resource for inbox. I will remove it for now. And, uh, here I have three resources, user, organization and membership, and three controllers. If you're not going to need these other controllers now, but in theory, you could override some behaviors here if you wanted. Okay, let's, uh, save our changes. Uh, add other generate resources. Okay? Uh, now let's, uh, refresh our page and, uh, yeah, it works. So we have, uh, our memberships, organizations and users. We can navigate to a user's page. We see all his attributes. We see all his memberships and organizations. We see that this user is a member of this organization. He is, uh, his role is a member and he doesn't own the organization. He's just a member. Let's go to the organization. We see we have two members, okay? Undefined inboxes, fields, uh, yeah, it was added by the scaffold. We don't need it. So, uh, let's go to our mul created folder. App, uh, yeah, app. Our resources organization. I'm going to remove this inboxes. Uh, I need to go back because it is looking for the inboxes in the URL. Okay? So the organization has memberships users. Let's go to the other user. We see that he is, uh, an admin organ organization, and he owns one organization. So the organization, uh, uh, table has his user ID as the owner. Okay? So we can navigate, uh, in avo, we can create, we can edit looks, uh, good. Now let's try adding some more functionality. For example, imagine you have a big list of users, big list of organizations, and you want to find a user by the email or organization by the name. So, uh, let's try adding search. Now, uh, if you have a look at your resource, it already has an example of adding search. So let's try adding search by the name of, uh, an organization. Let's uncommon this. And, uh, by default, we have the example with adding search by the id, uh, that equals this. DSL is from the gem ransack. I relies on the g ransack to make, uh, search for. So I will cope with this, and I will, uh, say coma, uh, name contains. And the, the D from RANSACK is CONT. Um, okay, so we can search organization by the idea or by the name. Let's, uh, refresh. And you see we have a search field that appeared. I will click on the search field, and we have this undefined method ran for class organization. So I think we need to manually add the gem ransack to our, uh, gem file, otherwise again on ransack, uh, for search, and then the gem bundle, restart in the server. Okay, let's try searching. Okay, we have this, uh, undefined sackable attributes. So it is, uh, uh, ransack, uh, security feature, uh, that, uh, they'll need to add in the organization model. He will have DAF solved sackable, uh, attributes, uh, decision by ID and by, uh, name. Yeah, actually we need to add this note in the resource, but in the modal. So organization, modal right here, and recyclable attributes by source, by ID, or name. Let's now refresh. Okay? We have the organization name here. Let's try searching for something that doesn't match. Nothing found, super, found it has been highlighted. Okay, looks good. Now, in the same manner we can add search to our users. Let me go with this. I'm going to the user model. I will add the search by ID or email, uh, and, uh, here in the organization, resource searched again by ID or name in user. We're going to search by ID or email. Okay, refresh. Let's see, our users, so have, have search. And, uh, I try to search. You see, it shows the id. So, uh, uh, if we don't want to just be able to see the list of user id, like I'm searching for hello. I see that this is used with ID number one, but, uh, I don't see the email, so the idea still doesn't tell me much. So we want to be able to see the ideas, uh, not only the ideas, but the email, uh, here. So the simplest way would be to set self title. Uh, of the resource is going to be email. Now I'm going to refresh. And KC have, uh, the email here, uh, looks good so we can search by our users. And, uh, also setting the title, uh, changes, uh, the way the user, uh, the resource looks in the breadcrumbs and the title. So let's, uh, comment out that title. You see now we have the ID here and ID here. So it's, uh, a good practice to always when, uh, there is something defining characteristic on a resource to have a title. Now, we didn't really need to do it on the organization model because it searches for a name attribute by default, but I think it makes sense to, uh, manually declare the attribute, uh, yourself to, uh, say that you want to the organization to be defined by the name attribute. Again, let's try defining the organization by the id. And you see it, uh, shows the ID here instead. So, okay, name is, uh, definitely better. Okay? We added search for organizations and for users, we don't really need to edit for memberships. Yeah. And token of, um, uh, titles. So here you see we have, uh, the name of the, uh, the email of the user. But imagine you have two organizations with the same name. If you're not validated, the uniqueness of the name, and, uh, uh, likely you would want to to be able to have organizations with the, the same name. Uh, uh, if it is not just in the URL, uh, it's just like, uh, like in Trello, you can have two boards with the same name. So, uh, you would want to have, uh, not only the name of the organization, but also maybe something defining like the ID in the, the search results. So we can have a programmatically defined, uh, title. And I think we have it in the other docs. Actually. I usually look a lot into the other docs. Uh, yeah, we have this computer title, and, uh, here we have an example, title Lambda and, uh, something. So let's have a computer title. Let's have not just name, but, uh, equals, uh, uh, and say, uh, record. We have a record defined here. So we have record id, coma, record, name, join, uh, slash So now we go back to vo. I go to search. And you see we have the ID and the name of the organization. So this way, uh, what version four is definitely going to be unique. And, uh, let's try open the organization again. We see the computer title here and computer title here. Okay, looks, uh, good, let's save our changes. So, um, uh, a search, uh, and titles. Okay? Now, uh, another very important thing is to make it so that only logged in users, only logged in, admin users have access to other. So first of all, we're going to add the admin attribute to the user model rails, generate the migration, um, add admin to users, admin bullying. Let's, uh, open our migration. And we are going to also say no false and default false. So by default, a QC is not admin relatively migrate. Okay? Now, uh, let's, uh, uh, make it so that only a logged end user has access to abo. So if go to the our docs, uh, let's open device. And here we have this current user method, current user. Let's go to docs. Here we have, uh, current user method, current user, and I can just un comment it or paste one that I took from the device docs. And, uh, we are also going to add a log out, uh, path. Uh, so config send out path, name, destroy user session path is the one that works for, uh, device. Uh, okay, now let's, uh, see if it works. I will, uh, start the server going to ava. Now we had our user, and now I refresh. And you see we have hello@cprs.com. So, uh, it, uh, sees the current user that is sent in Now from Ava. I can also try signing out. So let me sign out. I sent out here, uh, now I will sign out. Uh, I will just refresh this page. You see Ava send me out. So I managed to send out with, uh, there's an out link from ava. Uh, but if I go to slash Ava, now, uh, you see I'm not sent in and I still have access to vo. So, uh, what I need to do is, uh, going back to the other docs, uh, here I have this authenticated user access, ava. So now, uh, if I add this, uh, around our AVA route, only a logged in user will have access to, uh, a, uh, I refresh. You see, I'm, uh, redirect from vo, uh, I need to send into access, uh, vo, uh, let me send in. Okay, I have access to vo, but I'm not an admin. So let's make it so that only admins have access to vo. I will again, go to the VO docs. And, uh, here, uh, I'm going to say that user has to be an admin. So like this, now I'm going to refresh my, our page. And you see, again, I have no access to ava. So let's manually make our user an admin for the console rails console user first email, okay? This user dot update, uh, admin, true refreshing. Okay, wonderful. Now only an logged in admin user has access to ava. And finally, let's change our route to be no slash val slash admin. So I will go to Ava rb, and here the route part is going to be slash admin. I refresh slash ava, nothing. Refresh slash admin and have, have our AVA dashboard. Okay? Uh, now let's have a look at our users. Here we have two users. Let's also display which user is an admin and make it so that the, the super admin can, uh, change the admin status of other users. So going to resources user, I will add another field, field, uh, admin as a bullying refresh. Okay? We have, uh, uh, one user that is, uh, an admin and one user that is not, let's make this other user an admin. So, uh, just checking the check mark. And you see now both users are admins. Okay, wonderful. Let's save our changes. So, um, only admin has VO access. Okay? And now let's do some more styling. Uh, so here, for example, we have our users and we see all these invitation fields, and they don't, uh, serve a lot of value on the index. So let's make the invitation fields visible only, uh, if they open the user. Um, so how can we do it? Let's go back to users and, uh, uh, we can add hide on the index to a field. Let's refresh now. And you see we don't have this, uh, uh, uh, invitation token visible on index anymore. Uh, another thing that, uh, we can do is, uh, uh, style our show page. So here we are going to have like, uh, main, uh, content error, and we're going to have a sidebar, and let's move all this invitation fields to the sidebar. Let's, uh, go again to the other docs and search for sidebar. And here we have an option to have a main panel and a sidebar. So let's add the main panel to our fields. In the main panel, we will have ID, email and admin, and within it, we will have the sidebar with all the invitation fields. Okay? And, uh, again, I'm not adding all this has many fields, uh, neither to the main panel, not to the sidebar. Let's, uh, now go back here and, uh, have a look. Okay? So here we have the main fields, and here we have the invitation fields. Let's go to the user's index. And you see all the fields that have been moved to the sidebar are not visible on the index. So we don't need this hide on index, uh, anymore. Even, uh, better. Now we can, uh, open again a user. And here we have our memberships, organizations owned organizations. Let's add all these into, uh, tabs. So instead of like having them as an endless list, we are going to have three tabs for seeing all the memberships, all the organizations, all the owned organizations. So again, our has, uh, tabs on show view. Uh, we're going to have tabs. We don't really need to set an id, uh, tabs, uh, do. And our most importantly, we have organizations and memberships, then owned organizations. Let's, uh, have a look. Now I will refresh and have, have organizations, memberships and owned organizations. So now the hierarchy of things in our, uh, show page of, uh, user looks better. Now, at the moment, we don't see when the user was like created or updated. So the default timestamps, let's also try adding them. I will, um, add them as another sidebar. So sidebar dual here will have a field, uh, created add field, updated app. Let's refresh and let's not show the seconds. Let's, uh, show the date in another format. So do something like SDRF time. Now, um, AVO has its, uh, way of format in date, uh, time format. And, uh, here's the example. So field, uh, as time or as daytime. And they're going to add the format attribute. And, uh, the format is not f time, it is this luxon format in tokens. And, uh, here are examples. So, uh, uh, let's just show the date as August 6th and, uh, uh, yeah, and let's all show the day of the week. So let's just make it, uh, format DDDD, refreshing. And you see now the credit at is more readable. Let's also show the, uh, time, uh, as just like t. So after D, DD, D, we'll have t refresh and have the time. Okay, let's try putting a comb. I wonder if this will work. Yes, it worked. Okay, we can add this, uh, kind of, uh, uh, date format to all our, uh, datetime fields. Let's refresh. And all of them are a bit more readable, so wonderful. Uh, we improved the style of the show page of our users and removed all the, uh, informational overload from user's index. So let's save our changes, uh, as, uh, style users, uh, AVO users show. Okay? And, uh, yeah, this is the like basics, uh, what I would do when add VO to an existing application. So you ensure that only admins have access to vo. You make sure that all the resources, uh, can link, uh, among each other, and you add some, uh, your search and you add some basic, uh, styling. So that's it. Thanks for watching and see you in the next one.
