We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
Analysis Summary
Worth Noting
Positive elements
- This video provides a rare, unscripted look at how a framework creator approaches problem-solving and project initialization using their own tools.
Influence Dimensions
How are these scored?About this analysis
Knowing about these techniques makes them visible, not powerless. The ones that work best on you are the ones that match beliefs you already hold.
This analysis is a tool for your own thinking — what you do with it is up to you.
Related content covering similar topics.
Announcing RunElixir.com
Peter Ullrich
Shared secrets management in Livebook Teams
Dashbit
Build a Twitch Clone in Elixir
Peter Ullrich
IEx's Hidden Superpowers - Brett Beatty | ElixirConf US 2025
ElixirConf
Build a Chatbot with LangChain
Peter Ullrich
Transcript
okay now YouTube is running okay see you you're live there we are look at our beautiful faces cool all right yeah I'm gonna okay then I go over here wait streaming Everywhere YouTube twitch okay good and I'm going to share my screen with you I hope that works yeah screen one no the other screen screen two screen two yeah all right now you should be seeing my screen um yes I am seeing your screen perfect oh man does it mess with your yeah no obious like I need to resize your the input again of course wait can't I because I want to have you as here pin I'm going to pin you for everyone let's see how that goes okay yeah that's slightly better but now I need to do the whole resizing thing again hey may uh for the user in chat um who can't access the stream you could try twitch uh is another alternative like there's other places where the stream is happening um let me see if I can find a twitch link real quick for you all right is the link to the to the twitch Channel everything's breaking for me I don't even get the CH chat messages fun so you got to be you got to be the person who takes care of the chat now SEC okay I can do that I'm seeing myself stretched on your screen right now which is pretty funny but yeah wait but okay so well I was just on the no we're good we're good you're good okay so you uh yeah I'm like I was watching the lag delayed thing on on your stream not your screen so all right we're good okay so I can see you well in OBS that should be working fine uh cool I can't see the chat but uh that's all right doc chat G to re reload it yeah oh cool now I can see it Zack Mike's is louder than Peters um here let me turn down my game yeah I can also do that here how's this is that any any better hey Rebecca how's it going oh hang on okay it's early or late for you Rebecca I don't know it's not a normal time for you I think can you say something again Zach please testing testing one two three that's cool okay I had you I had you double like the audio was double here all right sounds better okay all right everyone excuse me for uh all this like back and forth it's the first time I have another person in the live stream so Zack Daniel is joining us today uh thank you very much Zack for being here oh yeah uh I'm happy to be here thanks for inviting me um yeah this I actually haven't done this sort of thing either like a live intro yeah to Ash um I watched your recent I watched some of your recent videos like the um the live you native one and I was like oh that's cool it's a nice like just have somebody experienced experience the thing for the first time pretty yeah it's it's it's that thing right where like I like to play around with these kind of things but yeah sometimes you run into an issue that the creator of the library never anticipated because for them everything is clear because they build the whole thing right but if you come new into something then sometimes you're just missing like what we had with life you native you know was just like okay so what is the next installation step now like how do I actually run my my life you native uh apps for example so yeah anyway but I appreciate that you uh made time to to join us today so the idea basically for the live stream um will be that we will dive into Ash framework right and idea we build a little project with it um like before we started the stream we we discuss ideas and I think we can just build something like a Twitter clone um you know I would like to to test out also something that Ash adds that um Phoenix framework that that doesn't come uh with the Phoenix framework for example like the Google login I think I think you support that right with like one line of code or something I think we'll have an easier time if we do magic link for example um because Google you have to like you have to like there's a whole like aligning of settings with your Google provider setup and you know making sure they're all right and like it can be kind of fiddly not because of Ash but just because setting up ooth requires okay you know yeah no problem that so so magic link would be cool as well yeah um yep magic link yeah and then we just you know have some basic like a form where we need to create a tweet like you can just write a tweet uh you have a form um yeah and then you also have some pops up you know for messaging stuff like that all right cool so um yeah how okay we can you can also be the guide and natal so if you tell me what I need to do I will do it happily but otherwise I also just like look at the documentation and try to figure it out myself but I think it would be better if you you you well it's an interesting question that's the choice we have to make fear from the outset right is like do you wanna do you want to do what a beginner would do and use me as a resource right so like you know do you want to go to this getting started guide and do what it says or because I think that might actually be a little bit better of an experience because that that's what other people will do all right okay um so I search for the ash framework in all caps and we have the beautiful website here I will allow cookies talk to an expert will I be connected to you if I do that yeah that that goes to to OIC which is uh they employ me and they're uh the by far and above the biggest sponsor of of Ash okay cool good to know um all right so we got the get started but we can also run the live book so maybe I do the live book thing okay yes people really like this the live book experience I you know I didn't make it even some it was contributed by another user and I just I've maintained it in various ways but people really like this all right okay cool yeah I like it too so okay you have different resources here okay but I'm just going to stall this and it's going to install Ash uh yeah Ash basically right okay all righty cool so we we create Ash resources quy them and use ETS as your data storage we won't be building an over arching application okay well in that situation maybe I I rather I would rather go with the uh intro yeah because we want to build a phoenix application right right right right exactly like that does show some Concepts but right um yeah okay no problem all right so I'm gonna skip right to what is Ash uh what get started all right this is a get started got yeah we already got everything installed um oh yeah cool yeah I I want to use igniter I'm I'm a big fan of igniter like I I looked at the Beacon CMS we also talked about that earlier but I I had a look at the Beacon CMS from docyard the CMS and they use igniter for installing the CMS in your application so and and actually what I saw there which I really liked hello what I really liked in in the igniter is that you have these helper functions that give you for example the application name or and these kind of things so if you want to generate code um yeah you can just you know if you want to have your module having the same name space as the previous application then you know it's kind of hard sometimes to actually get that name so it's cool that that uh the igniter actually does it forol me really yeah yeah there's tons of useful stuff in there too like the I mean you know like anything you can think of like you can say like ensure that this configuration uh is set in the config file and it like does this whole Magic thing but yeah cool awesome we will see that all right um see let me see so we got the copy yeah and what I will say is it's kind of I think there might be oh yeah check out that section on if you already know that you want to use Phoenix and Ash together well yeah you can do this first the that first step this one right IGN or Y install all right by the way also this one doesn't copy but maybe it's my issue it's a hex it's an xock issue I think there was a bug about it in xock I either need to update xock in in Ash and republish or maybe it's I'm not sure if it's been fixed but okay no problem um yeah cool so uh do you want to install igniter yes and it's installed cool all right and uh you said we should have like we should look at the something else with Phoenix um it's right it's right up there but um don't do the um all right yeah yeah if you already know that you want to use Phoenix um so in this situation it tells me I'll you do the with flag to generate a project with Phoenix new okay so it's using Phoenix new the generator for generating an ash project and a phoenix project at the same time exactly yeah so the basic problem is like you know igniter generators are all composable in a really cool way but okay phoenix. new is just using it's you know you have to run that first to create your project right all right let's do this so I want to do yeah not help this let's call this uh [ __ ] okay so I got yeah ignite a new [ __ ] install Ash with Phoenix and then we CD into that new folder but yeah if I do this um I got to change my my working uh my working directory so development and I'm going to do it in here yeah sorry all right yeah Nas is telling me not to help so much just like watch what Watch What Happens all right yeah it's hard right I mean if you see somebody using your own thing and it's just hard to not immediately dive in oh you have an issue let me immediately help you with that but this cool yeah I'll try to cut like a balance because the point is you do have me here so it's like that is you know true it there should be good commentary Etc but but yeah it's like I should give you a second to yeah yeah let's see to Gro um yeah also I don't need my Wi-Fi all righty so we got the project set up um yeah my computer's a little slow with running OBS and Google me at the same time so oh I lost my network connection whoopsy Daisy all right sorry I'm back I just watched you turn your Wi-Fi off no well the thing is I have a I have a connection like internet connection as well but so my little I have a little Kell digit was it an adapter and it just didn't work I don't know some something it's one of these days where you know nothing works as expected all right let me pin you again let's see okay we're back we're back everybody maybe the chat can let me know whether we are still uh whether they can still see us I hope so um all right I think right yeah yeah we're good I'm I'm looking at us on the stream okay so although my my is my face like big okay no that's that's right let me actually zoom out slightly just so I don't have such a big all right okay okay all righty okay cool um so I generated the project here and all good cool thank you yeah so it's it's giving you like a interactive version you could pass like dash dash yes or Dash y or something to just say like just do you know answer yes to all the prompts but you you know this way you can kind of see what it's changing it brand Phoenix new and then now it's showing you what changes right and that changes because we ran the install Ash uh command here right okay it's also cool that it finds the latest version I always have that issue when I add when I want to add a dependency that I I always need to go to Hax PM you know find the latest version and then I add it here in the in the yeah so okay totally maybe I just I just use igniter all the time now that's well that's actually legit a thing so I'll show you what I mean um when we're done here but igniter has used even if even if the project in question doesn't um use igniter yeah um and it's just that mix igniter do install works with any dependency right so like it it just won't have an installer but that's fine right like maybe there's no need for an installer on that for that tool yeah but I mean I can install any dependency with that from hex right yep and from GitHub and from GitHub as well right cool yep but it it will always add it to the top of my dependencies it does I think added to the top of your depend for now we actually talked about adding some categorizing stuff to like all sorts of cool things but that's you know yeah that's all right I mean I you know that's the easiest to just like move it down into the right position all right so it uh asked me a bunch of stuff here so following a Sol with found executed so it will add the import deps it will add the format for spark uh and the configuration here and that goes into the config EXs okay yeah sure sounds good proceed and we're in the project right MH so if I open that here also got to add my everything bigger all right cool all right so let me have a look here so we got our mix EXs and in here we already saw that Ash is uh installed and igniter as well aside from that it is the normal Phoenix project right on um also I don't have the latest RC of life you that's maybe an issue seven yeah you should yeah yeah bump that up I think the the squiggly Arrow will get you the latest um yeah like it it should have been yeah okay yeah it might be right I I don't know fun fun fact the the current generator for the release candidates if you run mixed compile you'll have a warning yeah um from G text yeah I already saw that earlier believe yeah um if you do uh oh the Migra thing can I do the Migra thing yeah you can say mix igniter do update get text and it will oh cool let me do that after I I compiled here the the files yeah okay but aside from that's this one one annoying thing about igniter right now is sometimes it recompiles depths like multiple times you know and for ash that's like actually like takes a minute you yeah it's like 500 so yeah all right but yeah so now you can do the yeah so I do mix igniter and then what do I do to fix this uh update unor get text like this uh no it's just like all one word oh it's a it's a task here it's a yeah it's its own task because like it doesn't live inside of G Tech so oh I see okay so it tries to update the dependency and some other stuff here yeah it adds backend yeah and you can scroll up to the warning and see like that's what they're telling you to do in yeah I saw that here so you need to yeah add change the gex to gex back end and then add the back end in your gex file all right cool yes but just hit enter b b in the chat is saying that that's really useful um you can use that right now like just add igniter to your project and do it yeah so you know definitely and yeah it requires because it's making changes to your code I just we made it we made prompts require an explicit Mak sense yes all right okay so if we look at the G text now it actually updated it here and in rep as well yeah yeah oh and you should you should do um do like get in it and like all that sort of stuff because uh it'll just help like if you're doing generators we actually warn if there's unstaged get changes in your project right um but if you do like a commit that'll help keep it clean if you as you're making changes all right let's push this to GitHub then cool and push uh you need to add and commit right okay cool all righty so yeah so now people can have that code too exactly so Ash sh on my [Laughter] giab okay cool uh so let's uh yeah I want to have a little little walk around here first so is is anything else that you changed in the I mean I only saw the I saw some changes when I created the project um the Phoenix project right but like aside from that that's it actually that's it there's nothing else yeah okay um Ash doesn't like well okay not not like ash doesn't have the same kind of like file sprawl of like required stuff that you need to run an ash app and you'll kind of see like a lot of that is because Fenix has those things but you know like right Phoenix does things that we needed to do but um you'll kind of see how it goes over time so all right okay well then I continue with the with the get started thing so we started we created our project Yeah we actually added the GI the git uh connection um I don't want to skip to the end I could get some example code but we going to do it together so that's fine but I do see that they install Ash postgress so maybe I need to install that one you you'll probably want it yeah yeah because what does Ash po postest does uh what does it do it's the postgress data layer so it's like how you could have like a a uh how you could have a your resources back by postgress oh so it doesn't do that by default the correct yeah it's not included in the in the core thing okay interesting all right um I want to do that but I don't want to use the examples so I'm only going to do so this is actually I'm gonna make a note about this but you want to use mix mix igniter do install since you already have a project makes igniter do install and then Ash postgress right mhm and do I need the extend postrest thing or is that only for the example no yeah that's only for if you're generating resources it'll make them use postgress oh I see okay so I'm going to just going to do yeah Mi install Ash postgress this will change a lot more things also yeah all right let's see uh yeah we had the dependency that's fine now we do mix get uh mix steps get right what's this uh what is the minimum post version you will be using uh Ash poers uses information when generating queries or migrations to choose the best available features all right um got default 16 uh which one do I have running I think I have I think I have 13 running right now but I do have a 15 do I have a 15 yeah I have a 16 G running so let's do the 16 whoopsy Daisy um okay and start the 16 right so I yeah default 16 um can I just press enter yeah I can good because it didn't give me that yes no thing but makes sense all right so a lot of stuff is going to change here let's see it is adding import TS what what what do you do this for import TS so that's what you that is the formatter rules for that dependency so it's the the functions that that don't have that don't require parentheses right see it's pretty much the only thing sorry okay yeah I'm sure makes sense the format section order post for the resource interesting so what's actually kind of cool and is what you're not seeing here is um because you generated a phoenix project it already configures the repo so if you didn't have all that repo config stuff we would have added it oh this so like yeah and like all the stuff in config files and stuff we just reuse it because it's already there so it's like a really smart generator so you could actually even try it if you go and you delete delete the repo config somewhere like in your config Dev for example yeah this one for example like yeah just if you just delete that and then rerun the the installer it'll add it back all right my at it slightly differently you know but it'll mhm all right yeah 16 enter warning uncommitted G changes all right okay uh but I can already continue and hang on okay so it's still adding the form and the config and then yeah it's adding back the repo that's pretty cool actually yeah yeah if you had never had Ecto at all installed it would install all of that stuff that's required to run activ that's pretty cool yeah and also adds the correct database that's awesome uh config Ash just able in async am I test why does it yeah so you have so you can have async tests like the if if you're starting processes in your tests and they might run a run database queries and stuff yeah it's like so the SQL sandbox will work with you work for you and test why is it disabling asnc though well it's it's disabling ash from starting any processes internally right so Ash won't do anything async it does everything synchronous oh okay I see so yeah that's for ash okay interesting um yeah and it's going to replace my active repo with Ash post repo yep which they're compatible the ash repo just has more stuff okay so I can still use the ash repo same way I use my Reaper before like added actor queries and stuff okay mhm and the n PG version all right it's going to add a new yeah it's going to me add me to the it's going to add a it's what is that H that's the the test script in mix yeah so it's adding s setup instead of Crea a myig grade [Music] cool and it's running do you want to run the seats and test usually I don't that's a good question I don't know oh hang on well yeah so I was confused because it it's called Ash setup but then it has another Ash setup here which also called yeah I was confused I thought this would actually call this but it doesn't it will it will it will yeah mixed Alias is are recursive like that or like they they go to the other aliases I'm like pretty sure that's the case may yeah but yeah I can see what you're saying maybe you don't want to run seeds and tests yeah I never fix that never run seeds and tests no I mean seeding is just for I don't know my environment really yeah all right we got to change that later but uh it's fine for now I mean it's empty anyway but good now all right perceivers changes yes exciting okay so it also scheduled a task I don't know if you saw that but it's it's it scheduled uh um scroll up a little bit more uh right there following tasks will be run after the above changes following test will be S coach and initial okay and that so then you can see that that's that so you it generated some files for you okay so the snapshot and the migration here oh I see yeah that's something also like it's similar to what is it active record right where you can say um kind of add a field to a resource or a schema and then when you actually add the field it also generates the migration at the same time yep cool yeah that's cool so in this case it do you know there's no resources but it's it's doing some setup stuff for you yeah makes sense so if we look at this initialize extension one uh Ash Elixir or interesting Ash and yeah what are those these are um asking the big questions now these so it it kind of goes deep into some of the expression stuff that we do M um we have this portable expression syntax where like you can evaluate it Elixir or evaluate it in postgress and it'll get the same result um and part of that is we wanted you to be able to use like and and and you know or or like to get and get similar so that's the operator that makes a Elixir is and in postgress where it's like null or false oh it's a falsey truthy thing yeah exactly yeah okay interesting but because it's it is a little confusing because if you do if you use and it an expression Elixir it it it requires you to send a Boolean right if you do nil and one it actually gives you a Boolean error yeah but so but if you do and and with like the Amper Sands yeah so that's the same for us yeah yeah yeah we so that's so that because postgress doesn't have that operator it doesn't have like falsy or whatever you know it has nil it has Coles right so nil or or null or whatever and it has and but not the one we needed so you has to do when one is is not null than two lse one okay interesting and yeah trim wi Space Race error so you you brought a lot of uh oh even uuid version s that's pretty cool MH yeah you brought the Elixir the goodies from Elixir into post yeah exactly oh yeah uh uid version 7 includes the the time stamp right for ordering mhm Ah that's cool exactly yep all right maybe we use that because you know if we build a Twitter clone we will have so many tweets that we need to kind of find a way to order them efficiently yeah cool all right all right okay yeah so we got our project set up can can I just run uh mix Phoenix server and will it show me something um yes it will yeah good let's do that oh yeah I need to uh set up my database but um yeah I mean I will just mix Ecto setup but that would not run s setup it was supposed to oh that Ecto setup should have been oh just run Ash Ash setup that's what you should do that's why yeah yeah it actually is fine if you just run Ecto setup but Ash setup should be like what your kind of default thing is because that does like more stuff too oh I see so I would not use Ecto setup anymore I would just use S setup right okay got it yeah all right yeah it installed the uh things it run the migration okay cool yeah so let's start the server and go to Local Host right okay same same yep yeah it's I mean really like not much has changed about your app at this point um but cool okay so so let's get started then so um what's the next step that you that you give here create your first resource that's what we want all right so y this will create a okay I can already see a problem with this all right we should add we should add our new mix ash. gen. resource command to like to create your first like to show you at least that you can because I think that's probably what you want to use so was that Ash dot ash. gen. resource resource to getting started gu and let and if yeah if you do Mixel you'll see kind of like all the different stuff you can do right yeah because here what it gives me actually is I need to do it manually that's what it tells me to do yeah it's like walking you through how to physically do it oh yourself yeah okay now I like this better okay I'm going to do Mixel and then ash. gen. resource and that's G to okay that's going to give me the dox here all right so we generate and configure an ash resource and the example here has the ticket it had default actions read primary key ID attribute subject string required public Al would I need to create an attribute for every single field that I have yes okay yeah oh yeah that's the relationship to the representative time stamps extend postgress and graph Q okay I only want postgress right because we only want to store it in post yep and you based on what we were talking about you also want the other you want to probably use d-u id- V7 D primary key ID because you want yeah I say DS V7 paramet key right okay but I I think the first thing we need is accounts right I mean I want to log in and then I want to connect the the tweets to the account that's actually sending them right okay so then yeah we're g to we're not even going to start with Gen resource we're going to start with installing another package at that point okay um and that is uh somewhere here is that already mentioned it's not in there either Link Link Link to Ash authentication and getting started guide okay coolar a lot of good stuff here no it's not here right um yeah it's not it's in but it's very small okay and it doesn't even mention your authentication stuff it just means Phoenix gen o is that what we need oh because it that's that's a header in the alternatives to Ash guide is why oh mentioning it yeah I see no it's not your fault there should clearly be in the ash core docs at least a guide that says for authentication go use ash authentication yeah right because I mean you have a lot of different ways to authenticate here so yeah it would be cool to have that somewhere all right so for you yes um you can mix igniter do install uh help something is wrong okay uh mix Ash igniter uh just igniter do install igniter install and then and then you're going to do Ash authentication undor Phoenix Phoenix yeah that'll do like the whole shebang all right so that does it okay so what do we have here output of porel format continue will be prompted again to accept the above change so it does it makes changes to all of these no that's actually just oh that's the uncom CH sometimes where we check yeah sometimes we check ahead of time when we're about to make changes to your mix. X's I should unify those experiences but yeah you could just right yeah that's uh what's it post all right all right so we're going to do this again IGN install all right now it's going to install the authentication Phoenix Library and that's probably going to change a bunch of stuff I'm I'm I'm wondering like how do you keep these things in sync like how do you make sure that they still still working even because you have a lot of different libraries right that's what I saw like how do you make sure that they all kind of work together in in well yeah so the primary way is we have um we have a sub project test whenever anything is pushed to Ash core yeah it's it's run against all of the tests of all of the other projects are run against Ash main oh so we know whenever we've broken a sub project and generally speaking they only go in like downwards like ash authentication depends on Ash and you know so it's like there's some I mean sometimes we make a mistake even but right uh so this is your the whole Ash project and that's some ash core I guess yeah yeah yeah when I say Ash core that's what I'm talking about yeah and you can see like yeah there's a test sub projects right oh yeah you got all these CSV postgress authentication to Phoenix that's the one we have man oh okay a lot of lot of test you're running then okay then I understand that that's pretty cool then yeah in in these test do you also run the installer like if I what I did now the ignite install like do you run these commands to do that um it's a good idea but the problem is like there's no it's hard to verify we could run the installer and verify that it compiles but to verify that it's like correct yeah or like did what we intended it to do is just pretty hard right um so we just rely on individual test for the installers like igniter has a bunch of testing tools to test that your installers do what they say they do it's yeah yeah all right yeah I was just wondering because you get you know usually if everything is in the same library then you can always you know test everything at once but in your situation with all these different combinations and variations that is the challenge for sure all right so addication we already got some some Warners warnings some compiler warnings here yeah that's just a deprecation I need to fix in right Ash authentication core uh all right now we have Ash policy authorizer requires a SAT solver which would you like to use picad Elixir and N rapper around the P set what is an SAT solver all right that's another thing to add into that little message right there um because it's a it's a it's a so we use it for our authorization layer it's a constraint solver so like if you say like this has to be true and this has to be false and this has to be true and here's the combination of things you can run it through a solver to tell you like yeah that if these things are the case then then that will work and that sort of thing so it's how we do like large scale complex authorization rules efficiently okay and we use it for a couple other things like that right so so these would be like permissions and and like my role stuff like that stuff like that yeah okay because sat is usually the American high high school thing oh it's it's um it actually sat should not be capitalized it's not an acronym that's a it's it's a shortening of the word satisfiability okay um interesting so well I'm curious what does this Pico set it's Real Time Track uh real time tracking satellite no that's not it okay um look up Picos at Boolean solver yeah that's an Elixir Library here satisfiability oh that's a rust Library yeah you said that yeah it's a solver for Boolean variables and Boolean Expressions the SAT solver can determine if it is possible to find assignments to Boolean variables that would make a given set of expressions true if it's satisfiable it can also show a set of assignments that make the expression true okay interesting yeah I mean this is like probably some of the most complex Deep dive work that I've done on ash it took me like six months to get this right day yeah but but the way the authorization is set up it's like we turn all of these procedural rules into a big Boolean statement and then we pass them to a solver and it says okay if all these things are true then they would be allowed and we say well are those true and if they are true then we're like you're good to go and if they're not true then we say okay they're not true you add that to the expression and it's like okay well if all these things are true then they'd be good to go and we're like well that's not true either you know so we have this whole like system it's it's really complicated it's like the the heest work that I've done it it sounds very complicated yeah do you have it's internally complicated to end users you don't have to you don't have to worry makes sense yeah you don't have to care about that sort of thing yeah tools for working with set solver that dries field with sub so checking authorization yeah yeah you don't nobody uses these it should probably be a private module honestly oh well yeah do we have private modules now uh well yeah if you don't add the module doc here probably or if you exactly yeah yeah I think that's the definition currently that's what they mean private modules but it would be cool to have actually private modules yeah actually I I heard that what was it y I think yeah on Monday he made a live stream I think he mentioned that you know he was like yeah maybe this a good idea to have priate modules cuz yeah I mean I also had another discussion today on on Blue Sky uh with somebody who set up kind of like a an a facade module for all like for a certain subdomain you know so you have like my app Fu and then you have my app Fu query finder whatever but but you don't want people to actually call into these sub modules you only want to have like a one context and and he used def Delegate for that and uh I used that before also in another project and we use boundary eventually to prohibit to block any cost into sub modules but you know if that was just buil into Elixir it would be so much nicer yeah right it's kind of interesting like I I that stuff is cool and all but I also think that in a lot of ways it can be sort of productivity theater yeah in a way maybe like um it well okay I believe in boundary for example I think boundar is a great tool but I think you'll see like with in Ash in a lot of ways it's like we actually try to we squish a lot more things together like on purpose and and we don't take there's not this like you know separate your app into seven layers that all have a bunch of conventions and those seven layers like you because it all things get so duplicative things get so difficult to like I think that's like the seed of spaghetti in a lot of ways is this idea that I'm gonna like explode my app out into like you know these things that all have to like sort of line up and work together and you know I don't know I I I'm like how do I avoid that problem how do I make the interface not so confusing that I have like four that I need like a query Builder dedicated to every single thing and uh you know all that sort of stuff and you'll see that yeah I mean we're we're moving kind of slow but which is good which is fine but you might not all I'm trying to say yeah all right okay well okay now I got your point you have a good point we should we should continue with this one uh you know we just kind of fill down the rabbit hole into the solver here yeah we can do an episode two that's fine yeah maybe yeah all right so I'm going to use the Picos set Elixir silver one all right so that's going to add the dependency yes and yeah Ash is recompiling more I got to fix that on the in uh in igniter it's a really complicated thing I didn't know that was going to be the hardest part of igniter but the fact that we have to compile recompile certain depths and do stuff M it that was that took weeks and weeks to get right like well two weeks I guess but we but why do you need to why do you need to recompile everything we don't need to recompile everything we need to recompile some things and re and we need to recompile them based on depths changing and elixir just isn't set up for you to do that like to change depths and then reevaluate your new depths and then recompile oh you always stop and restart okay yeah so everything goes through your app or like you can only recompile your app or why why can't you recompile expecting they're expecting when you like you it's hard to recompile a dependency live on the machine like you can recompile modules and stuff like that right but mix is not set up for is not set up to be expecting you to be like recompiled this dependency live right now without restarting anything because it has all these like caches of what the dependencies are and the modules and the stuff and it just gets really complicated right it's it's it's not a impossible thing it's just the tooling there's nothing right now that Elixir needed to do that you would always stop and restart so yeah anyway so so so you mean you can only recompile the entire dependency or nothing you it's expected you would stop and rerun mix compile to do it because there's inmemory caches and there's there's no button called recompile dependencies that that looks to see if their version changed and then recompile it doesn't do that oh and that's what we that's because the script we're currently running that like this is a script right or something like that so that's because a mixed task but we downloaded new dependencies and then you have to recompile those new comp new dependencies that weren't there when it started right but we're still in the same task like we're still running this task so we can't just stop the task and then continue exactly oh I see well okay interesting today I learn all right a lot of stuff is being added here uh I will just accept it I guess I'll just trust trust the magic yeah you're getting users and tokens that's that's where you're getting yeah well it's the same as in Phoenix uh or Fenix J North so all right I'm just going to do yes of course do it there you go now I'm curious what it all added let's let's see okay we need to also change the Tailwind yeah modify your Tailwind config to add the new files so I guess this one yep yeah we can't igniter doesn't have like fancy JavaScript editing but we're working on it actually we have a user who's working on getting a a rust Library set up to parse JavaScript files so that we can like modify the code of JavaScript files in the same way that we do Elixir files okay should be pretty cool that that's cool yeah indeed definitely all right cool so we yeah we got this thing uh that's what it told us to do don't forget to add at least one authentication strategy that's what I want to do you can use a task mix as authentication add strategy or view the docks let me view the docks all right get started using igniter yeah we already did this choose a strategy so we want um yeah password and Magic link that's what we can do can we do GitHub is that easy with GitHub you can't there is no oneclick installer for those you have to do it but it is those are actually like easier than there's a lot less ceremony required to do those it's just get the config right right you do a new or uh so you need to create a new app here MH uh yeah all right okay now let's let's do magic link and actually let's do only magic link because know password is something you get with Phoenix as well but magic link not so uh okay so I do mix add strategy and then Magic link is this underscore I guess all right Buns of changes yeah these are the uncommitted ones this one's going to change this is my resource right yeah that's your user resource yeah okay bunch of stuff yeah's we can have a look at this after everything's done proce changes all right uh let me add the add magic link or boom actually I never yeah I was GNA say there's one thing we could probably include in that in those generators is a task to run Coden again um because you you'll actually just see if you run your run your app maybe I'll just let you see it to show you what I mean run the app now um yeah all right the migration so yeah yeah yeah that's all right but Fenix is the same yeah well no that's not what I'm talking about go to go to slash SL sign Dash in because like we don't modify the the basic thing so sign [Music] sign yeah right okay so yeah and just I mean try it see what happens if you use exist in the database you will be contacted all right that sounds good no um yeah a little bit different actually but go to the nothing there it's not doing that yeah yeah the the it's it look in your console we we talked about this we actually want to set this up like better but you're also getting an error right so this one is like nothing added the email column to the users which is required um we can do that we just need to I just need to add that task right to execute so you'll have to do it manually um so which one would that be mi. Cen after mix as. Cen after strategy add yeah so mix as. Cen um and then you give it a it's just a that's it and then you'll give it a name okay so call it like add password or add magic link add magic link to users okay and and this is creating a migration or what does it do I creating migration yeah yeah okay is that the way where you look at the current state of your resources and you look at the migration and if there's something missing you you generate a migration yeah we look at the snapshot files that we've made right um so that's how we sort of figure it out we don't look at the current state of the database because that would be fraught with problems yeah okay so all of these are Json files here for for example users and you got some attributes the repo table users and then more attributes yeah so every copy is every snapshot is a full snapshot of that of the table for that resource and stuff like that because I got my what's the name here Source ID and then I got Source ID again and now I have an email as well key generate fults all right cool all right okay so now now uh if I do this thing again if I do the login again will it work uh yeah it should request magic link there's no mail so it's not it's not into your mailbox it's in your console on the left that's the thing we want to do we don't actually set up a proper mailer we just we show you a stub of how you can do it like if you find the code where it's putting that out there's like a commented out thing that says like um to do the thing anyway yeah you're Lo in now okay there's nothing that shows you so you might want to like go to your home thing and get like a current user or you know edit your the other that template the template yeah um yeah but before we do that I would like to just have a quick look at the resources that we've been been generating yeah because uh yeah we get the accounts and then the user okay so this one and then we also get a folder here with senders send a magic link okay sender is an email sender I guess so it's a whatever you want really its job is to communicate in some way with user so you could use magic link with phone phone number for example instead of email um and so maybe that's job is to send a text message right this what you mentioned with it's commented out because yeah this is the email sending logic but it's commented out yeah we don't add the thing in in zitter Jitter doac accounts. emails uh because we just didn't do that work to patch that in it's just a little bit harder it's doable but we haven't how would you how would you add the email sending then with Phoenix or oh swoosh yeah I mean it's the standard like swoosh email pattern that we're kind of expecting to exist um okay but like I forget what that what that looks like it's like you know whatever because they generate yeah we we have the mail here for example this is a what you usually use but then you have a when you generate the uh when you generate uh mix Phoenix gen oath you also get an user Notifier module which has a bunch of just text based emails right and uh yeah we don't have that part yet but I mean you would just do uh this one [ __ ] yeah like um I think deliver something and but you you would you would need to to build your your email first so yeah mhm okay but yeah yeah we don't do that yet which is a little bit less convenient than Fenix Geno I guess but well yeah they don't have magic link so it's like give and take yeah but uh yeah that's actually we just we have an open ticket about that because Rebecca who may still be on the call it's late for her but she's working on the authentic oh yeah she said it in chat just now created an issue about improving this um because she's working on that chapter in the book as we speak oh you have a book about this uh pragprog yeah we got a pragprog book coming soon oh cool is it already announced on prag prog it's yeah it's announced well I don't I don't know when they announce it so maybe not but but you know we're we're well into it you just you just announced it so that's good enough well every everybody knows about it people ask us constantly we announced it like early early like okay okay beginning of the year interesting cool so yeah okay so we got a resource and this resource has a data layer so it's actually saving it to postgress interesting uh could I could I have multiple data layer here you can only have one data layer for a resource yeah so what was the other data layer graphql or so now I mean that's more the interaction that's the yeah that's that's those are just lists of extensions so there's other there's sqlite MySQL at CSV those are data layers oh I see um yeah because we use ash postgress here we could also have Ash MySQL instead right okay and we got the authentication extension some authorizers got some policies here okay uh and the domain interesting is that something that you only use internally or does it actually have some like gu there something around domains that people should follow yeah I mean generally domains are like broad segments of your application um and you can Define interfaces at the Domain level to have like a sort of Phoenix context like experience um so uh yeah domains are a pretty important concept I could say say hey generate a context that has [ __ ] uh [ __ ] accounts as a name and then it would have a bunch of like cruts functions no so that's that's kind of one of our fundamental differences right so if you look at the you can go to that module that accounts domain yeah um its job is to like the logic lives in resources right but it can act as a as an interface so we always know what domain we're act acting in the context of okay and I can show you an example actually if you um in in your resource it says resource you know Jitter doac accounts. user add like a do Block in there yeah um so like after you know it's like resource du um or resource no on the Oh you mean I'll use it like this yeah exact yeah there yeah yeah okay um so you can say if we look back at your user resource like you have some actions available um's find a good get get by email get by email get by email okay so uh go back to your domain your accounts domain and now say Define and the atom is uh call it like get user by email and then add an option called args so it's like a keyword list yep uh no just like a first argument is an Adam second argument is a keyword list um y so then you can say uh args uh yeah and then say it's a list yeah and you'll say email and then you'll say uh separate from args now you're going to say that the action is get by email action get by email yep okay so now if you do if you open up like I EX for example yeah um you can say accounts get use a bay email yep and then you can pass in your uh not found well I guess the wasn't created so this is actually interesting um see that where Falls so that's the policies that's the policies kicking in um okay so above right so that's the rules of of in the user uh resource if you go look at the the policies and user policy um strategies token yeah policies right yep so it there's a a a bypass that allows Ash authentication to do what it's going to do um and then otherwise a policy that says forbid if always so that applies even by default to like your your attempt to use it in IEX right so we're like secure by default okay um so if you go back to IEX and you do it again but pass an option to the function so after the email you then say authorize question mark because it's a bull authorized false you can bypass it like as a developer you know nobody external users can't do it but by default authorization is always applied a that's smart interesting oh but you also even have your own postest types here like a CI text string yeah that's used because like I mean yeah there's just there's design reasons for a lot of those things yeah but I mean is that a does it work the same as a as a bit string as a binary no it doesn't interesting we we preserve we preserve all of our value types yeah yeah I kind these so you would have to but there's you would say dot dot string to get the string out of it like this yeah okay right but the reason for that is you're actually throwing away information like let's say you fetch a user email from the database and then you pass it into an equals equals in a SQL query later yeah like postgress knows in the context of a post post query um well you would do do um do uh I don't know how deep we want to get in here but you don't use equals equals in there I'm saying but postgress can tell the difference between a a CI string yeah the CI text and a regular string inside of a query but once you load it up into Elixir and it's just a string and then you run a different query with that value it's not it's not a case in sensitive string anymore you have to remember it right and so Ash remembers it for you so if you say the email out and then you say give me the report that is for the user with this email and Report the email and report is not case sensitive right or it's not case insensitive right we but because it's a CI string you pass in we know to use case insensitive string checking oh okay so how would I how would I comp compare this CI string with another string um there's a couple different ways um I'll show you the cool one do import import ash. exert expert uh exp exp it's a expression yeah it's short for expression yeah okay so then you can say you have a function called a macro called expert exp yeah and then you can just you can say uh like pin use the uh user. email equals equals test test.com so that gives you that's an expression that you have now so you can assign it yeah exactly right okay um all right and then you can say ash. expert or actually you already have it just say eval eval comp yeah yeah okay true interesting so you don't almost ever have to do this sort of thing manually but yeah you know the point is that like it's all sort of like a unified system yeah makes sense yeah but I mean you know in your application code you might want to like compare some some values but okay um probably rather in queries like you explained and then yeah there's there's different ways you would do it that solve all that for you like yeah like using expressions and calculations and all sorts of stuff like you've seen like you know you're got a toe in the pond but yeah there's a lot more to it all right interesting all right yeah I think we uh we spent enough time on like diving very deeply into this so but okay I just wanted to see all right we have a we have attributes here on the resource which is a primary ID yeah we didn't it didn't do we didn't do do U ID V7 you can just change it you can say U ID V7 primary key it's compatible with any existing IDs like this yes yeah all right uh so if I load my user again was it you have to recompile too but yeah yeah true had it somewhere it will make some changes when you run code gen again as well to change the default value for that field right okay yeah because I mean this is not a version seven on new uid right I think so uh I actually I don't know what the I think it does does it appear differently it's a every V7 uid is a valid V4 uuid as far as I know okay I'm just say I don't know anyway but uh that's for another day but that's interesting I mean now when we create our tweets you know then we we want to use uh V7 U so all right uh maybe just a a little Qui question like how do you how do you query uh stuff like how would I how would I find all the users that I don't know have haven't we don't really have a query yet but how would I list all the users for example right um so if you look at your actions let's just try it just say ash. read ash. read yeah use like exclamation point version of it all of our functions have exclamation point versions that we'll raise errors instead and then just pass in pass in in Jitter doac accounts. user I get a so you're going to get we okay it says no no primary action and no action specified so what that's telling you is like resources can have a concept of a primary um of a primary action and that primary action is like what's used and that's typically what you would do for like a general querying tool if you want to be able to just query users in some way so what you can do is go if you go to the top of your um yeah we'll do it here and you just say defaults and pass in a list and put in the atom read so it's a the default is a macro like no no coal in there um okay so like this exactly yeah and now if you recompile all right yeah we're full still so I need to authorize y does this work yeah okay yeah this is actually a great example this is a good time to show you this right so yeah well first first let's let me just show you the querying right so now to like we have our own querying interface it's data layer agnostic and all this sort of stuff so say uh you know do Jitter doac accounts. user and you'll pipe that into like ash. query. filter and then you know email equals equals that's this is an expression as well so it's like how Ecto it's like a macro so you'd say uh sorry put it in per ends yeah um yeah and then you can say email equals equals and then you know put in a value yeah exactly yeah I'm going to make this uh like capitalized like this yep yeah and then uh pipe that into ash. read and you'll get you have to require ash. query because ash. query. filter is a macro all right yeah and authorize again MH false all right okay yep so L here's a good example of this you're eventually going to want to allow users to read their own user record right yeah right so so let's actually go in and and write that policy um in here somewhere that policy all right yep so add a policy called um policy you'll use a function called action type action type like this yep and then the one argument will be read cuz like so if they're doing a read um like the yep um and then you can say authoriz if authorized if yep and you I think if you give it a second you might actually be getting autocomplete from our we have a special language server extension are you using Elixir LS or are you using I use Elixir LS but it barely works actually I think I use Lex I use all of them okay like yeah Elixir LS has got a lot better but we have Elixir LS specific plugin that actually right gives you special autocomplete in resources anyway so authorize if um and then do an expression e expr like we did before okay MH and then say email equals equals and then you're going to use the pin operator and call a function a one AR function called actor actor yep and then that like uh the atom email like this right okay yep so so the policy is saying if you know you're allowed to read a user if the email of the user equals your email okay probably what you would actually use is ID sorry not email you should use ID true because yeah you know all right so now what you need to do is change that policy always at the bottom because the way that policies work and we can't we don't have time to go all the way into it but policies all policies that apply have to pass so that will all that right there prevents anything from happening so change that to action type the always yep change the always to action type and then pass in a list which is and the and the list will be uh create update destroy for example update destroy yeah and it's fine actually yeah so there you go you can actually just delete the last policy you don't need it because if no policy applies to a request then it won't be allowed to happen Okay so all right so in this situation I would have for example read and update yeah like this way a user can update and read their own user yeah uh and you might have like specially named actions and so you might actually switch on a specific action like update password might be a specific action that you allow instead of using action type like that sort of thing like it's a very rich set of tools you have and the action would be for example yeah request magic link yeah uh so in that would be here instead yeah well you could add like another policy you can have as many policies as you want so you could have like you know a policy for requesting You' say action is request magic link so action yeah like this yeah exactly and then you could say like authorize if always to say like anybody can request a magic link like you don't have to do this because that that bypass at the top lets Ash authentication do it right um but that would be a way to do okay simple check yeah this one already has a couple of checks here all right let's not dive into that all right cool uh all right uh yeah so I I understand now we have attributes on the resource we have policies for accessing the resource uh identities so that is a unique email okay what what is the identity here can I have multiple identities I guess so right yeah yeah you can have a bunch and it's those will be created as unique constraints in the database and then also used for various things like that allows you to use an email to look it up with Ash doget and just other stuff like that okay okay so we got policies we got actions and actions are the crup actions we can take on uh on this resource but also other stuff yeah so that's that's the really important actually you hit on the the nail on the head about actions being the cred actions this is the one of the biggest things we want to disambiguate for people like we have create read update and Destroy actions those are like templates or like they're types of actions right but that right there what you're looking at that's just an action it's a it's an action that has that takes some arguments and does some stuff it's like a typed interface to some domain logic okay and so requesting a magic link for example is not an update action it's not a read it's like just an it's an action right yeah um and you can what's cool about with all of the Tooling in Ash works with generic we call these generic actions as well so you could put that up in a graphql with like one line of code and we figure out all the types from all the stuff and the return values and everything right you know from that so uh it's yeah crud is we try to it's not there's nothing wrong with using the word crud but people have often used it I think to like sort of typ cast what they think Ash framework is yeah and we because of bad bad communication for me early like when early on when I made the framework like I I get that but okay but I mean in in principle this is like quote unquote just a function right like like it it could be a death uh we would call this like request magic link I mean I this doesn't work in as right now but like just the comparison to Elixir would just be that you know this will be my function and like you also do a lot of um uh checking here you know so for example if this one was like nil then I would actually return like an error or something you know it's it's it it ends up with the same type of thing but what's really important is the thing that we pushed with Ash is like your application is represented as data yeah not so it's we don't actually gen there is no function generated called request magic link yeah like with that thing um but it is it is very similar like the way you would use it but to show you what I mean if you go to IEX and you you can say um ash. resource. info mhm doaction oh right uh no it'll be yeah info. action um the function is action um yeah and then pass in you know Jitter accounts. user and then pass in the atom uh request magic link so this this is how everything in Ash works right your resource is just a data structure we like I kind of joke sometimes that it's like elixir flavored yaml like it's it's just it's just a data structure it really doesn't do very much on its own but then when you say Ash do you know there's ash. run action you give it a resource and an action name and we go look up the instructions and we do what it says right and that's like how the whole thing works and that's why all of our extensions work is because they are running everything's looking at the same data structure and just following the rules okay okay I mean when when I tried Ash earlier like without the guidance of the Zack Daniel um I I kind of struggled a little bit because yeah I didn't see any functions anywhere like I I don't know like do you have an escape patch that if if I wanted to write a function here like could I probably not right well you can write you could you could Define a function but I would suggest like that action right there right yeah so if you if you click into that run module that oh I guess well yeah you can click into it right this run module like that is a really thin wrapper over a function a generic action is right so you can then write whatever you want your job is to just return what the Gen what the action is supposed to return right um and that's your thin rapper but like we do all of the typ casting and policy logic and everything is enforced like across all of the the various interfaces um and so yeah it's like you don't Define your business logic by writing a bunch of functions and my like hot take is that that's a really shitty way to define all of your business logic in my opinion like functions are not the magic composition tool that a lot of functional programmers would suggest that they are like a function is like a black box with a you know you typically cannot introspect it you can't ask a function what does it take you don't have type classes for types of functions we don't have any way to introspect metadata about functions all this sort of stuff at least not an Elixir right but with Ash for example when you know something as a read action anything know can understand how to call it and build an interface for it so like here's a good example TR try this do um uh uh uh okay we don't have an installer for this but do mix igniter do install Ash admin and then you're GNA have to add some you're gonna have to go to the ash admin docs to uh to actually look up how to add this to your app because all it's going to do is add that all right um um getting started right we edited uh we got to ensure your domains that configured you already have that yeah yeah the the generators do all that for you add on here okay yeah those are the domains yeah mhm add the domain extension to each domain we did that uh that's the yeah we do have the domain but not the extension so this will be so it'll go in the um the domain module not the resource module right so you use domain and then extensions this one y okay and also admin show True mhm we need this too right so here is that required I don't know I don't have it yeah yeah um all resources will automatically be included in the ash admin to configure resource use the ash admin resource extension so we do need to go to the user yeah just for the users you would do this yeah and add it to you all right and then do that block as well that block right and this here yeah that was the formatter Sorting your sections oh I see okay um interesting also that it doesn't do it by uh how do you call just by letters it has some logic it's in your yeah it's in your config file actually like we just set up a default for you but you can decide what order you like your sections to be in or something right and this actually tells this resource I am like this actor is uh allowed to access the resource right like yeah it says this resource something you could like that that might be a a user of my system in some way right oh and you'll see where that comes into play okay I see all right then we go to the router and we have we have to import the ash admin router so I'm going to do that and then we create the new pipeline you don't have to do that you already have a browser pipeline right that's only if you that's for apps that don't have that for whatever reason that says it here okay sorry yeah so we do the ash admin and just over live [Music] session just here let's see okay Co see I think that should be everything to get it running yeah yeah no I already have it running oh uh yeah okay is that going to work because you added a dependency let's see I mean I got to add yeah TR try no yeah so I think you got it it's not okay let's do this again oh this is a classic one this is a if you go to your router module it's it's it's because of the the Jitter web prefix yeah so just make a different scope make another scope for it so that it that doesn't have the prefix I got to fix that people hit that pretty often I just forgot to go to it all right okay cool now we have our admin here right so you can actually see I'm not sure why but it's just refreshing 100 100 times is there something crashing on your yeah wait it is your okay you do need to do like the there's like csrf yeah yeah know into that the configuration is there Che for all right so that is in the I think the admin guy does have that the getting started guy I just didn't think you'd have to set it up yeah but uh the cond security policy if your if your app specifi a conon security policy do we have this wait is it somewhere I think it might be in the end point or wait yeah I'm in the end point or maybe in the router right ah here put headers okay there you go interesting so I think you can configure that with the configuration we give you yeah um to avoid this you can add the default Ashman RS right uh behind the here so this as the default non Ashman self okay and alternatively you can supply your own L to the ash admin route by setting a I'm okay with this I guess yeah it should be fine let's uh let's try again and it does the same thing again why maybe I I just restart oh restart yeah yeah because you pick up the new well although it's on the router right so usually it's no oh it's do we need to add it in the appjs too I don't know I'm not really I don't think I've really seen this problem maybe I should look and see live VI session was misconfigured or the user token is outdated in session configuration yeah the configuration is in the module attribute I mean we have that change the plug plug session to use set attributes plug plug session yes session option where's my session options is using it also pass a session option to your Live use socket we do that I think oh we forgot to pipe through browser oh do we uh oh yeah you're right to chat right because yeah we created a new scope makes sense hey it's right there oh no oh but it's in yeah it's a this one there you go yeah okay right that makes sense there we go and um oh yeah take I think our example might have been bad I don't did they change how that works I'm not sure um but you can probably leave out you can just you can just leave out the the the CSP Stu because you don't have a Content security policy in there currently right yeah we just missed that we just missed that pipeline makes sense all right okay no yay everything works yay cool okay so what I was trying to get at is like because it's all data yeah like you can go to if you go to the drop down and select like users yeah and you go to like read read yeah you actions yeah so like you can you have like there's an admin dashboard like automatically it's not hooked up to your database right it's it's um it's using your actions like the rules of your app as they're actually set out that your users actually use so if you wanted to like request a magic link for a user like they're like hey I can't you know like you can go in there you can fill it an email this looks really ugly by the way but you know yeah it's an but if you look yeah exactly but you know so you can use any resource in any resource action in any combination or not any combination but like with regardless of its interface yeah and we have all these types like unions and maps and and embedded resources and you know we have a little plus and minus buttons for lists of things and all this sort of stuff it all just automatically happens because it's data driven right and the question when it I feel like this is where I want like try to sell the value prop for something like ash is like do that for a phoenix context right yeah that's not easy it's not possible I mean I I use the uh Cy that's true yeah but that connects directly to your database right it goes through the Ecto it goes well yeah it it uses the acto repo but you give it the resources it should Fetch and then you can also Define a couple of actions it should be offering and forms that should offer but yeah it's much more like you have to write not terribly a lot of code but it's not easy either like I mean look my concern isn't so much with the with how much code you have to write it's like the it's like it's I I don't want an admin dashboard connecting directly to my schema like a schema is a representation of data in a database an admin dashboard is a representation of things that users can do and at no point should a thing a user can do be directly hooked up to a thing that happens in my database like the whole point is that there's an application layer that's determining all these things right right um yeah and so and and a good example here too is like if you wanted to if you had a a database or a data resource using Ash csb for example or had manual actions that don't have anything to do with a data layer all that stuff still works yeah so like that separation is actually like in the simple example not super powerful because you're like I could do this with Cathy but yeah when you actually start to build what you're doing and have like resource actions that call external apis and blah blah blah blah blah all that sort of stuff all of a sudden it's like oh holy [ __ ] you know you have like a list GitHub actions action on your user resource that returns a list of structs that are like or that are like the GitHub issues open for that user and then you go into your admin and it just works there's no like M yeah you don't actually you don't actually try the same thing that the user is trying like you use different functions like to list something for example but yeah if you have the same action as the user in this case uh you know like if you get the same response you know you will always get the same response as the user does so that's and you can take the action as them like that little user up in the top right yeah like if you were to create another user and then run this and like go to this page with that user active you would only see themselves because they're the only user that they can see interesting that so yeah okay well I mean I only have one user now any you have to go make another user yeah yeah okay get by sub I have a cre here all right yeah but it's cool I mean yeah if you if you want to define a an action that you that a user can use out of a sudden you can also use it in the admin panel just like that yeah that's pretty cool yeah and that's the same way all like all that other stuff gets really easy like the um yeah make Ash admin beautiful agreed but I don't mind I mean it's an ash admin it's an ash panel thing like you yeah it's fine it works I have buttons I can click you know um but that's how graphql works too right like if you wanted to make that an action in graphql it's like literally one line of code MH like that's not like an exaggeration just the initial installation setup that set up of like a you know that's with an installer and then one line of code to put a an action in in graphql and it it automatically knows how to do it that's true yeah yeah I like this I like this yeah okay well you know we were here to build a Twitter clone we have done everything except building a Twitter clone correct so how about we just do a speedrun no distractions anymore I'm going to shut up as well with my like pesky questions all the time about you know action stuff um so okay let's do it let's let's do this so what we need is obviously a new resource for creating the tweets right um I'm just going to stop this so that would be mix Ash Cod genen no you got to you got to help me gen resource gen. resource yep right and I'm going to do the help so what we need is Gen resource and then uh we also have to provide the domain and default actions is read the primary key we wanted to have U7 actually the the ID for the users also well yeah I think it's also a V7 here actually like it says it's so at least on the type yeah yeah we it is we you have to run Coden mix as. Cen update user U ID or something because you changed it oh right uh coachen dot not just like this right Y update user ID have a mix help in the front right s see it actually created something modify fragment updating the default from random uid cool all right uh okay no more questions just just coding Ash G resource so what I want is uh [ __ ] and then weeds I guess going to call it like that so the classic yeah that would give me the yeah the resource and then default actions uh these can be default actions where is it attribute default actions a CSV list CSV list interesting yeah it's comma separated so you can have like multiple oh yeah okay I never thought about it in that context if CSV file is for me a file makes sense yeah I see what you're saying yeah it's kind of weird but you're right a list of youra actions to add for example read and create the read and update actions except the public yeah we want to read and create that's what we want so default actions read and create okay next up The UU ID primary key should be V7 so this one and then just ID we want attribute subject string required public yeah so we want attribute um so we want this text or content that's a string is there a difference between string and text no all strings are text n and this is required and public yep good um or time stamps yeah we want to have the time stamps what else do we have con yeah just the content for now right and the relationship um yeah yep the relationship so we do relationship and now we need to Define belongs to author my appon author and it's required okay so we do belongs to just user I'm going to call just user and required like this yeah all right what else uh time stems yeah let's not foru about the time stems and then you'll want um to dash dash extend with postgress postgress extend yeah all right yeah I think that's about it right integer yeah V7 default actions relationship attribute yeah yep enter and also you have always shortcuts for that so minus t minus B minus E so that's cool yeah all right so let's see we have a new Ash domain the tweets domain we have a new yeah that's the domain then we have a new resource that has this domain and the data layer postgress that makes sense it has default actions read and create B7 primary key the content allow nil fults public true public true doesn't mean like any user can see this can query this or no so public true it doesn't matter nearly as much if you're building like a live view app okay um but the general concept is private to the resource so you might have hashed password is like private to the resource you'll never display that across an interface ever okay um and public means like this might be visible to the outside world in any in any way but you can you can lock it down more granular and do all stuff like public yeah what happens to content if I would make it private would it just be redacted or um in the context of live view really nothing okay that's it would just still be there in content you know because as a developer you might it might be like private but you might have to use it for something like we don't okay strip it from the resource automatically but there's there's a thing called field policies and if you start writing field policies they're likei field level visibility of individual things than public private matters even in the context of live view but you don't okay you don't need to worry about it too much all right I don't worry about it cool yeah we got the thing perceivers changes yes and let's commit at tweets cool all right so yeah your next step is we have a this is old and sometimes I think doesn't do exactly what we want but and we we're going to rewrite it with igniter but we do have oh you need Ash Phoenix so mix igniter do install Ash Phoenix there's no installer for this one it's just yeah the a package that you need okay and yeah has no install a task all right so now you can say mix Ash phoenix. gen. live view or mix Ash phoenix. gen. live yeah and let me let me double check what it expects you to give it um okay so the first thing is going to be the domain so this is why it's old it's like we actually can get that from the resource now this is from 2.0 when we couldn't but then the resource okay uh you need the whole thing zitter do tweets. tweet um and then yeah just run it from there it's going to ask you some questions please provide a plural name for tweet for example the plural of tweet is tweets interesting is that a did that make it because of my name here um I don't know do we pluralize maybe we do pluralize but in in the future versions we're just going to figure out the plural for right okay no but it gave me this example so I'm like is that actually related to my resource name uh I don't know oh I think actually no you're right that's all it is yeah just an S wow it just happens I well I think it's it's a hardcoded example for example the plural of tweet is tweets really oh we have the generating tweets okay that's funny all right yeah that well in this case actually it works so plural name tweets yeah uh no no but it's not it's not gonna it's not guessing that for you okay let's do you have to still do it tweets would you like to name your actor for example current user if you chose no we will not add any actor l I would like to add that yeah yes would you like to name it default current user no just enter well yeah yeah just enter yeah pery update action not found and update action not supplied would you like to create one didn't we have a default action you have a default create action but not an update action so it's going to not do like a update form in the generated live view because there is no update action but we do have uh ah no I did we forgot that I thought I I gave that didn't I oh no we don't have up no sorry my fault my fault right yeah good okay so you can just say no probably to that yeah uh would you like to provide an update no no oops a [ __ ] oops AR I think this is a bug let's see where is it haveing somewhere in live oh man that's all right what line is it uh 340 life. ex action. arguments nil how does oh man go ahead and just try adding an update action in that defaults just in case that's somehow related to it so well it won't add it for you you have to add it and then rerun the installer so go update yeah go to that and then add uh you know update content something like that because that might be the problem okay again I want to re revisit this and make it nicer soon okay tweets would you like to Yes uh it's okay PR reaction could not F and the destroy action of Supply would you like to create a destroy action no let's just say no no see okay that worked okay cool so that was the bug I'll I'll I'll fix that after this no problem okay uh yeah we need to add these routs and authenticated routes um well we're going to put the Tweet list and new well we don't want to have an edit but tweet new is going to be in the authenticated routes you can put them all in the authenticated routes and then you can use user required and user optional like in the live view itself to like authenticated routes just means that authentication happens it doesn't necessarily mean that there is an actual user or you know that sort of thing okay I see yeah so then we add them all here yeah and then if an authenticator user may be present life us are optional if the authenticator must be present live must not be present so yeah this is what we add to our live view your life user required optional or no user okay so it will be optional all right uh uh and it created the index form component shows so in here we would need to add honestly yeah you know what I worry too I'm not is this compatible with the Phoenix release candidate I actually have no idea we're gonna find out we will yeah because on Mount I mean this is the live you on Mount function right okay yeah nothing that that'll be compatible but I don't know if the stuff we do in the view is like you know I don't know they change core components and that right messes with this so you know we'll see let's see yeah uh yeah right all right so we have some stuff here some the live components for the form and yeah we have a stream for ash read tweet and then actor is the current user all right yeah so cool here we could actually limit the tweets to only the actor's tweets if we wanted to yeah yeah nice assign you uh nil all right okay uh and edit new yeah I'm just going to disable the edit thing here but yeah this is pretty much life view I I understand this cool yeah good yeah not nothing really changes much about how you use Phoenix above the context layer right like the context layer where is that's where Ash is about it's about the application layer right but UI how you build Phoenix applications not for apis but how you build user interfaces is still entirely run-of-the-mill Phoenix right makes sense yeah that's cool I mean you know what like the the the entry point or how you say the the the point where live you connect to Ash is literally just here like ash read tweet and the actor yeah yep cool all right um let's see we have our router set up tweets neon ID we got this so yeah let's let's run this thing let's see whether it works and I we I have to run our migrations did that run our migrations for the tweet no you have you need mix as. Cod gen oh I need to name it as well at yep tweets and migrate all right let's do this again something it doesn't like something about to edit routes or something but all right we get a did it blow up yeah okay new tweet hello world save tweet nothing happening here is an error no um yeah so it is an error okay it's it's not showing because this is kind of interesting it's it's not showing because there's nothing there's no field for this error that is occurring that's in the thing so I'll show you how you would like debug this as a developer right so you would go into well I mean as a developer obviously anyway go into uh the the form the um form component yeah yeah proba the ID right exactly yeah yeah submit forms yeah there you go right so that in that error case Ash phoenix. form is a little bit different than what you'd be used to but in that error case you're getting back a form that just gets reassigned so in here there's a function called Ash phoenix. form. errors that you could like inspect the errors on the yep and then so you'll pass in the form and then an option you're going to say four four path so four underscore path and then it's going to be the atom all so that's giv me all of because you can have nested forms in Ash so this like give me all of the errors on all of the forms inside of the thing or inside of this form okay and that's so now if you were to submit that you should see an error yeah users required right exactly okay um so uh however if if what you're thinking about doing or or not what you're thinking about doing actually tell how would you fix that how would you I would add the user ID to the perams okay definitely not the right way to do it okay um so there's a couple reasons for that I mean the the number one reason though is like somebody user could go into the form and submit user ID right and your thing would overwrite it yes right it would overwrite it but you're only one deleted line of code away you know what I mean from somebody being able to create a tweet for any user right um so it's I want to say definitely not the right way to do it it's you have to understand the ramifications of that sort of thing but the way we would do it in Ash is different um so go to your Tweet resource yeah and so everything like our business logic all that stuff lives in actions right so that create that create default remove that create from that keyword we're GNA actually Define our own create action um so and say create it should be create the word is create since it's a create action and then that name of it will be create for now like this yeah and then yep and then a do block okay and so set primary true yeah primary question mark true it's a Mac it's like a builder so it's like okay no no colon right um and then set an accept list so like AC EPT accept um and that'll be cont like that content attribute that we had for update um and now you're going to like this is the thing that you extend to change what happens when a tweak gets created okay so if you're familiar I know you are familiar with like plug right so an an ash action is like a plug as well you have all these builders that you can use so for a create action for create update and Destroy that's we call those a change so you would say make another option in here called change like this um and then yep and then there's a built-in change called relate actor so it's a function relate actor I this uh it's a function uh so it's a one AR function called relate actor and then the argument is the name of the relationship you want to relate the actor to so it be like user we call it user yeah yeah user okay yep so because like you have all the context we know what user is doing this right like it's up to the action to decide well it's the user who created this that is the user on this tweet that sort of thing um so this is like taking that logic from the that shouldn't be in The View and putting it into the domain layer okay um all right so now it should should work y let's try that again yeah that works all right it inserted a tweet ID content time stamps and the user ID all right cool and nice let's do another one all right all right so let me ask you another couple of questions I mean first of all we can also just update this one uh and remove the ID content yeah oh we don't want the edit one so this one can also go all right wonderful now we have our tweets here as so timeline all right so how how would I like a couple of things how would I first of all preload the user on in this query because I might want to preload the user to show the username and the the icon the the logo for example yes um so the way you would do that is add the um so data loading in Ash is the we called load we call it loading data you can load all sorts of things okay um to load a relationship you would pass in load a load option this is one way there's a lot of different ways to do it but this is one way to do it and then pass in like user like this yep okay so and then in here the tweet I could do user. email for example all right okay yeah that worked nice so what's really interesting now though go ahead and and um make open up the page or open up a new like a new browser window like sign up as a new user and stuff like that you'll see kind of why that's not necessarily the approach you want to take or well it could be but you'll see so sign oh something happened there I did sign did I do sign in sign in did you open a is that a incognito window uh probably not right yeah yeah yeah so it's like it's it's like logging you in automatically Clow sign in or i on okay so test two and I reest a magic link did I get that I did get that okay I sign in and I got to tweets right so that user can't see the other user right so when it the policies were applied like this is one of those things where it's like it can be a little inconvenient but it's the right kind of inconvenience it's like you you know your rules say that that person can't see that user right um so there's let's say there's there's two ways to go about this like you could say well anybody can see any user right right but there's a there's a better way to do this um in your Tweet resource um go to uh add a we're going to add a new block to this called calculations okay Y and then we're going to say calculate and we'll call it um you know user email and that they're going to give it a type so the type is it's a three AR thing so the type is string and then the third argument is the calculation we're going to use an expression calculation so you expert to to create your function this or to create your expression Y and then say uh user. email just like this so now oops yep now in your in your view um you'll have to load user do you have to load user email because the calculations don't come by default um so instead of user I do user email right exactly and so now if you both yeah right so you've defined that like part of viewing a tweet is seeing the user email um oh yeah you have to up you have to load that when you like there's a thing that when you create one there's somewhere in your live view where you like refetch the thing MH and you have to also load user email think safe to yeah stream Ina tweet um yeah so you can in this case you can say ash. load on the Tweet if you want like this yeah use an exclamation point to to yeah and then here I would do load just the just second it's just the load statement so just like use you know this yeah exactly all right let's try this and you could also do it like in your form after you after you create it you could do it in your form or you can even right you can even load it while you create it like you can tell a change that load this data when you come back so you know but this works for now all right um so that worked actually yeah here okay uh what else uh yeah pops up right I mean we need pops up here so that people immediately see my tweets yep okay and so in tweet yeah yeah we would can we add that to resos yep cool all right um so there's an extension called ash. Notifier pubsub so that'll go on your extensions list just uh okay well extensions and then was it Ash do ash. Notifier do pubsub with capital P capital S yeah exactly um that's just your language server being weird yeah all right so add the pub sub block that would be uh okay so somewhere here pup like this yep and I actually need to improve I remember I found a a little bit of confusion or like a thing that's missing in that Pub sub guide so good thing you have me here okay um okay so you're gonna add a module and that'll be um the module would be your endpoint in this case so like uh module oh no sorry it's the option is called module like what where do I Pub sub to right um so that would be Jitter web. endpoint right and then you can now we can give it a prefix called like you know tweets or something that's like a string and now we can add our publish our publication so in here you would say call it um we use publish all so this is to publish all events of a given action type okay and so the first argument will be create and then the second one is a list it's a it's a list of strings and we're not going to go into the format that's allowed here because you can do all sorts of things you know okay but and just say like uh create it for now that's the only thing yeah all right so this will be this is like you know that colon list that you make for like Pub sub events yeah this is how you can build it up and you can interpolate values in a way in there so but this yeah we don't need it okay yeah cool cool and that's it is it yelling at you about something so so that means that whenever I create like I run the create function here it uses pops up and it basically broadcasts a message with the topic tweets created yep exactly and it's pubor sub on line 13 that's why it's yelling at you pubor sub right makes sense yeah not it works all right and um yeah how do we subscribe to so that'll um so you actually the way you subscribe to is this classic Phoenix Pub sub subscribe that that works the same okay if connected Phoenix pops up subscribe uh probably let's got to look at the name what is it should have pops up and the topic would be tweets created yep all right um and then yeah handle info to to start I would just say like in handle info to get the message and then inspect it so you can see like it's going to be shaped you know it's a one of our notification trucks that sort of thing okay so Handler infin what what am I getting uh the tweets uh it's a phoenix Pub sub it's like destruct I think right um let me double check because usually what I do when I when I broadcast something uh because he and handle info I don't know which broadcast actually called the handle info right so I would do like um tweets for example and that way well so what you what you get right now is you actually get a struct you get a phoenix. socket. broadcast struct is that so so like you can you pattern match on on the struct itself yeah phoenix. socket. broadcast okay yep and so in in there you have the topic so you can match on the on the topic MH so tweets created yeah exactly and uh percent percent at the beginning right um so then you'll get the information created oops um that I mean that's all oh yeah oh you you want the ID so you can look the you can look the Tweet up so we should go change that in our publication I knew something looked wrong with that okay um so the the next item will be in that list will be the atom ID so it'll be in in that yeah exactly so that's how you distinguish you're like building up a message the atoms are brought in from the resource that was just created or updated the strings are like you know literals okay um so now you can pattern match on the ID in the um so here will be yeah tweet ID exactly and then you can uh fetch it look up the Tweet yeah yeah but but I mean because the the broadcast here also has a payload with the the pay would the payload also be the the Tweet the struct the payload is an ash. Notifier do notification so it has like a lot of information in it actually like the change set and all sorts of other things okay um which I keep waiting for someone to ask me to there a thing I keep waiting for somebody to ask for which is a a tool to limit the amount of data that's actually sent because it sends a lot right now but nobody's asked and I've been busy so okay okay but because like what the good thing about uh using broadcast with the payload uh that actually has a struct is that I don't need to fetch the the tweet from the database in every client correct you can and you can do that if you want you can pull it out the um in this case it'll be in the Notifier dot it'll be in the data field right so like it'll be in payload and then inside of payload data and it'll be the Tweet let me just uh see this one in the broadcast uh we didn't get the broadcast maybe a restart do we need to migrate something now that we added the P oh did you re it might have not recompiled from the resource you don't need to migrate anything but so it can I recompile I don't know I just rest maybe all right let's test that should be all that you need I think so it was created um do we we could have done something wrong with like our there's a there's an option for this um in there's an option to dbug Pub sub so you can like yeah so if you go to put in your like config your Dev X's file um oh yeah uh you can say config oh go sorry no I saw that here right it said something about that yeah debug y so that that can help you find like because you'll it'll show you like what it published in right Som oh I I sorry this is my bad this is my bad this is for me not not using the tools enough it's not an EXT it is an extension but go to your go up to your this yeah that goes in the key notifiers not the key extent so like change extensions colon to notifiers col that's what tells it use these extensions to send things out into the world so now now it's gon to work okay let's try again there was something yeah and we debugged it as well here okay the notification broadcasting to topics all right uh and we so we didn't get it in the UI did we uh yeah I didn't I didn't edit it I I just like I just IO inspected the broadcast like we don't do anything here yet uh where is it here well oh yeah yeah but but are you even is it even doing the io. inspect broadcast yeah it did this one right I think oh is that it no I think that's no that's your notification yeah I don't think you got it no oh true oh right right okay okay I led you astray again we don't want to we don't want to publish the Tweet ID in the created message um because how are you gonna subscribe to that yeah true you weren't right so yeah let's go change change our message and then yeah we'll get the ID out of the out of the no uh here yeah makes sense all right and in here we have the notification uh wait yeah I need top I un inspect the broadcast first but we do have the notification that's what you meant with all the data in here uh and we have somewhere the domain action there'll be a key in there called Data data metadata metadata data it might yeah there yeah so it'll be payload notification or payload do dat I think is where you would get the the data from okay let's test this one data test five yeah that looks like a tweet good all right so yeah um so the TW one sad thing is as far as I know these generators don't use streams um yeah I like I'm pretty sure it's just assigning like a list of tweets so you have to like they do there's a stream here stream insert oh yep all never mind cool the other problem here of course because uh then we need to remove this one again otherwise we addit twice because we also like kind of listening to our own broadcast like sorry that was confusing uh when when I write I think it I don't think it'll matter because it D duplicates by ID doesn't it oh that would be interesting yeah let's try that let's try that all right so yeah we just do a stream insert and we also got the load thing so I'm just going to create a little uh insert tweet we're going to move this here yeah so and L for should go together yeah yeah okay and yeah insert tweet s and tweet oh we can just payot data and we don't need this all right okay uh let's try this again so also my second person here no uh yeah of course I can't oh can we do a pent um I want to do insert tweet add oh yeah there's like a I don't know what it's called see stream insert no add zero I think that one right let's try this again so now tweet here testing yeah it worked nice both sides testing two there we go awesome so one of the things that's interesting right like I mean I'm sure you see like there's a lot of there's a learning curve to all this stuff because Ash has like patterns for all these things yeah um but another kind of underlying theme is like there's a lot of stuff in the way that it works that protect you from um that protect you from doing things wrong okay or protect you from Bugs and I'll to show you what I mean if you go to like I EX for example yeah um uh if you well I maybe it's not a good I'll just tell you about it it's easier than trying to to replicate it but one of the common things that happens that's that's wrong is um you let's say you have a context function that creates a tweet yeah right um and then something else there's some other button like a like a create multi- tweet button where you can create a thread of tweets all in one go right um and then that tries to comp POS your create tweet function in your context right so it tries to call that three times in a row um which maybe is not the best way to do it in real life you know but you want to do like a bulk insert or something but it's neither here nor there um and so what it does is it starts a transaction and then it calls create tweet three times with each one of you know once with each of your tweets but they send out their Pub sub notifications because your context function is in charge when Pub sub notifications go out right so it emits a pub sub notification the transaction's still open right so the live view tries to load the user email yeah it's not that and actually that would that would probably work but they tries to load something that hasn't been committed yet in the transaction um and it crashes and this is a really common beginner like a you know like one step above beginner bug with Live View apps is not realizing that you have to Notifications should only go out when for the most part when the transactions complete yeah and because Ash calls your actions we actually and starts transactions for you like every update action we manage your transaction we all stuff for you um we gather up all the notifications until the transaction is complete and then we send them right so you can't do that wrong interesting so the that that's the magic uh that pops up does for me here okay that's pretty smart like notifiers in general so you can write a Notifier to do this as well it's just a module that has a notify function but we gather up all the notifications and then when it's all done we then call the each Notifier with all the notifications to say emit something about something so that's for like your you wouldn't want to use that for something durable like you would use like an if you had something where it's like this must go out otherwise the world is over you know like then use an obon job or something like that and commit it in the transaction um but for this sort of thing or like a push notification that like your team scored you know it's like yeah needs to go yeah okay cool that's that's pretty interesting I never never thought about that I mean yeah I wrote everything by hand so if I would write you know like a multi insert I would actually have that I wouldn't call the you know the little create tweet thing I would just do repo insert or something and then yeah well here's what okay if I can nerd out one more time yeah sure sure that's a great example of the sort of thing you don't have to do if you're using Ash because every action is set up to be done in bulk or not right nice so you and I'll show you what I mean this will actually just demo so go to go to ex like you know find a user you can like ash. or actually use your by yeah use ash. that's fine um pass in the user resource uh. accounts. um capital u yeah and then a map of because you're going to get it by email so you say email is you know test at test you have to do authorized fals y yeah you're quick learner uh yeah string oh Dam man it's going to break okay here we go okay I got the user okay so now that's going to be the the user that's going to do the thing and so now say ash. bolt create uh one bolt create like this yep and the first the first argument is the input so it'll be a list okay and say you know it'll be list of maps so like content you know tweet one um content you know then content tweet two mhm and then the third the second argument will be the action name so it'll just be create M um actually I'm lying to you let me double check I think the it's um it is first or the second argument I think is the resource um I'm used hold on I'm used to having like intell ense and stuff like uh Ash def create yeah okay this yeah exactly then then the action name and then for the Ops pass the actor say actor is you know your user so like this before you submit this yeah um make it make your terminal halfway right all right now submit it bu result oh [ __ ] sorry hit up and do it again and say notify true so by default bulk actions don't emit notifications because it could be like a massive thing okay uh with a question mark notify question mark yay it did tweet one and what's cool so if you look up to the insert statement that it did somewhere in here yeah it's like the those are the live views reading the Tweet right where should be some green stuff somewhere we also have the debug on okay we got it it is MHM so it did it did like a bulk insert right in single insert into tweets but that one that change where he's had relate actor yeah right it it that knows how to apply to like a list of things MH so like you don't have to rewrite your actions to be able to do them in bulk or to do like CSV import if you had like upload a CSV call the same create action that runs your single things and you can just ashop all create accepts a stream so you can read a c file stream it into your bulk create and it uses all the same logic and rules and your custom changes so if you can the same way you can Define like a custom plug um you can define a custom change module that has a change call back like plug has a plug call back or whatever right um You can also Define batch operation callbacks so how do I do this on a batch of things and then that change can be like optimized for bulk okay if you need to and so like yeah go yeah question is like how do you handle create like bulk update and bulk deletes because in in like post you always need to when you do bulk update you need to kind of provide a like a query basically yeah so those that's how that works bulk update and bulk delete are or bulk destroy take a query as the first argument instead of inputs and then they take one One update like map of like what to do and then that gets applied to everything in the query right yeah so if you I mean yeah you can't uh well actually I learned something this like if you want to like that's me nerding out because there is a way of actually it's funny so let's say you want to update a 100 records but each one of them has individual Fields like they have not the same field you don't just do a set something you actually have 100 like maps that you want to update at once there is a way but uh there's a blog post and what the guy did is it's super smart because he kind of uses the the maps the list of maps and he joins that with with another table and then he inserts that table into your into your table uh so we we want to build that in to Ash post to Ash as we'll call it so we have bulk update and we want to have a version of that maybe like bulk update each where you give it a list of Records like a list of like a tupal of a record and the updates to apply and then we'll we'll do that for you because that's like all of our stuff is like automatically does you know um yeah it writes the SQL for you so should be like really easy for us to actually do that there'll be some rules you know like each map has to have well it doesn't really have the columns that we select will have to be like the super set of all them and stuff like that but it yeah it won't be hard yeah exactly but that was a pretty smart way yeah but because everybody else like otherwise you're always um like limited by postgress right because you can only do like a set or increase or something like yeah you there are ways to do it like with you with bulk update you can supply Expressions that will do the update and you can say if ID equals one then this and if ID equals two then do this but it needs to be one long yeah it's one massive query it's really ugly it's impossible to read and you know like not going to perform that well true a man I can't find the there was a really nice blog post about it um anyway maybe I find it then I will tweet about it later yeah it's one of these things yeah anyway it's a good one though yeah I I know the one you're I know the the strategy that you're talking about yeah right wanted at some it was so small it's just a little bit less common but yeah I know I mean you got to know about it but I mean if Ash like just takes care of it behind the scene you know then great like I don't need to and we might even do that by just if you supply a list to bulk update then that's the then we do you know what I mean we do that type of update um which would be actually very easy for us to detect so because you already can supply if you play if you do a stream we'll do a like let's say you want to update like a million things yeah this is a common example of like you can't use like Ecto doo. update all and pass in like a a stream of a million objects or a million things to do right it's not it's a because it's designed and it's very good Ecto is like one of the biggest Inspirations for me for like good software in general like I love Ecto um but it's designed to call SQL queries right like like one to one right and um but what we do is if you pass a stream in by default the batch size for a bulk update is 500 okay so if you pass a stream in MH we we take 500 at a time and we apply an update all filtered by the IDS of those 500 things okay okay so you could hook up like a massive data import to bulk update the same way that you would do a query or any other thing and we'll do it like efficiently a transaction you can configure transaction per batch or transaction for the whole thing or Max concurrency and all these different things you can do all sorts of stuff like that right um and so that's kind of the benefit I see like I almost like Ecto is like too good of a library like because it tricked in a way it's got everybody where their apps are just like views connected to databases and they don't realize that that's what they have like um and it's hard to explain like it's hard to explain that like if you have a shifting layer the application layer that is the the line you know between data layers and and web layers like all the cool stuff you can do is hard to explain I that's true yeah interesting though but I mean so in your situation with Ash like you you said you uh you create multiple queries no you create one query for the 500 items or how do you handle that it actually depends we could do either one there's three bulk update strategies right there's stream uh Atomic stream and atomic I think an atomic means do it all in one query right and atomic stream means do it in batches of atomic of of individual queries and stream means do it one by one um okay and the way that it actually works is you can pass in all three of those and say pick the best one that's possible for this action so we can look at the action and we can say this action has um a change on it that doesn't have an atomic implementation which means we cannot do it in we have to look up the record because the action is expecting to receive a record MH um and this is how the API extensions work so when you say like hit when you do like an update action in graphql we actually do a bulk update of the resource by that ID and we say use the best strategy available and If the action supports it can be done automically in a single update statement without looking up the record then no lookup happens it's just an update where do thing and the the policies are all applied in the query so like let's you know how you had that policy that said you can only update a record if it's you yeah or you can only see a user if it's you m um that gets compiled into the update wear statement of the update so it's we can also do policies atomically or non- atomically depending on what the policies say right so when you're writing these like things that plug into resources you can say use the best version of it but otherwise use and so what happens is you get best case scenario is twice as fast as it would be there's no lookup there's just an update but then you add some business logic that requires seeing the original record and when it does its bulk update it says well the best strategy I can do is stream I have to look up the record and update and and you like to the developer it's fully transparent it would just you get the best that your action can do that's pretty awesome yeah and as you said like with a permission checking I mean you you automatically would always add like where user ID equals this for example you know based on the policy there that's that's pretty smart yeah you don't have to do that and we can even lower like validations so like actually here's a good example let's try this go to um go to your Tweet resource right and add a validation on we'll just put it in the create action for now in the creaction here okay yeah you'll just say put it like underneath the other stuff or it it doesn't actually matter where you put it but um say validate um I think it's just is it length let me see built-in this is all documented you know but built-in changes or built-in validations length Okay it's string length is the function or just validate kind of how change is like validate and then the function is called string length and then the first thing will be the field so content M um and then you can say like Min 10 all right okay um max what is it now 280 believe yeah something like that you can put them in the both in the same you can just say m Max right in the same right um um actually okay make this make this we're not going to put it in that action make a validations Block in the whole the top level because we're going to apply this on all actions yeah um and then put that validate in there move it to there okay um so we have a an update action as well we're not exposing it in the interface right but in in IEX go ahead and fetch a single tweet let's see don't even fetch a single suet let's just do ash. bulk update uh yep and then uh just put the resource here so we're going to update all tweets um and then uh the action will be update and then the map put in content uh it'll be like yeah ex exactly put in I guess we need a string that is longer or shorter than our rules yeah so I actually made Min one so that should be fine here wait but that the that Min one this satisfies Min one this satisfies Min one yeah yeah no I'm saying we want to make it uh oh okay so we do out 10 and this is just fun okay but I also um have to recompile I guess wait no up did it for you or probably okay all right uh let's see all right here we go M oh this okay this is funny because we can actually tell we can tell without running any queries that fund doesn't meet the validation right um so it just gets a like there is no update that actually happens um true let's do something real quick go to um make an make another update action in your update action action create so update yep and call it set content to fun okay all right and then we're gonna add a CH say add a change called Uh set or called Atomic update like this um uh Atomic atom I ah sorry um let me just make sure I'm not lying to you yeah and okay now the um the attributes going to be content mhm and then we're try I'm kind of like trying to trick it to because like it's smart enough to not do so we're going to put an expression in here right yeah and then it's going to be like um hold on I actually can't think of a way to trick it because okay do fragment do do a fragment instead of a so like a not no no quotes uh but still expression yeah exactly fragment and then the the string in postgress fun uh you need single quotes no no double quotes for the fragment string and then for it to be a string in postgress you need single quotes inside of the double quotes oh interesting okay it's like this yeah okay now we're gonna go up go to our this is kind of crazy I know but it's worth it um if you go into the uh the thing you're not going to pass any input you're just going to call Bulk update call set content to fun right in in your I X in so I'm going to do Ash OH is is it on the res update yeah so B update for that resource tweets tweet and then it's called set content to fun and no arguments right so just close um add a empty map I'm not sure if it's required or not I forget but okay let's um yeah okay do that error com wets no so but what's interesting about this is like how do we do that because fund has to be determined in the database yeah right right like we how did we give you an error back about the length of fun being and and it has to follow the rules for example uh that this is crazy watch this okay let's simplify this go back to the the Tweet yeah and go to your attribute um for for content and yeah okay and add constraints and we're going to say trim false so it's a keyword list constraints are a keyword list so trim question mark false like this yep um okay now recompile and do that update again because what it's doing is it's putting the rules for trimming a string into the query right so right okay this is already small here and now it's also putting the r which is that when There's a constraint called allow empty and what that does is it means an empty string is treated as null right like so when you submit a form with an empty string right so go back to your Tweet and say allow empty true where we are actually comfortable with an empty value it'll be in that keyword it'll be in that keyword list with constraints yep like this right yep all right okay okay um so here so now you can see we're not putting so we like we know how to apply all the rules of things in a SQL query or not so that the validations can be run in the postgress database or not and have the same semantics 100% of the time right um so we say yeah when the length is less than this thing then raise an error in the database yeah Json B builds exception text inputs fun text else and then else case but you do that again even K wait this is for the I think this is yeah then um yeah this is for the the other one where that's the the men and the max is the next one right yeah when it's bigger than 10 so this is the Min check and this is the max check yeah yeah interesting and you put so what that means is like you know because think about the 99% of time when somebody submits a tweet right it's got the valid text in it because your like UI is validating that right yeah true so like do you really need to look like check it somewhere in your application side when you're trying to bulk insert many of them that means like you have to have that logic to go to do that for each one right um and IM you know if you get we can do the smartest one for you you could see that like when we could tell that the string was not too long in Elixir land then we just didn't do a query but now we can't and you this is what happens when you're writing regular apps with Ecto and stuff is you have to rewrite the whole thing now you're like I need to insert multiple at the same time and I have to put in all of my rules and rewrite the whole logic and everything because that's the only way I have to use insert all which takes a query you know in all takes a list of change sets right so you can actually run your tweets through the change set function that you already have and uh you also get an error probably if one of them fails thing yeah but the problem is when a result when one of the values is computed from the database like let's say somebody wanted to like randomize their tweets or put their email at the end of all of their tweets or some random [ __ ] right it's like then you have to rewrite everything because you can't validate it on a in Elixir anymore sense yeah I mean what people usually had back in the day where they had like the validations in the database layer that now nobody does anymore I mean not many people do it um but this actually adds it back to it but kind of dynamically yeah well what what's going to happen at some point again just time is um the migration generator there's no reason why the migration generator can't look at the global validations list and see those should be constraints um and then just allow the the data layer to raise it yeah um but the nice thing about do being able to do it dynamically is it works for Action specific constraints as well so like if you if you just had that in the create action it's not a rule of the table it's a rule of the action true it you don't have to to like throw all that stuff out yeah because maybe sometimes I want to allow it you know if I'm an admin I want to do something that a normal user can't do so I can't I can't add that as a constraint on my database but you know I still want to have the database check somehow yeah nice yeah man that's uh really cool stuff here I would say yeah I I I like it a lot like I mean last time I think last time when we because now I have you of course so I got the the best introduction I could possibly get um I mean it was just last time when I started with this I uh I went through the but I think that was all before you had the igniter stuff and and so on so now I I went through the get started thing and then it basically told me well you have to copy paste like these 50 lines of code if you want to get authentication and then so I was like maybe I'm I'm okay I'm going to wait a little bit but now it's just igniter install you know Ash authentication and I don't have to copy anything uh so yeah this this actually makes it a lot more approachable yeah the question is when is the book coming out that's a big question we're hoping to have it in beta this year no promises but but we're hoping to have it in beta this year good um making good progress so and like it's funny because you can kind of see like how like looking at how igniter happened like I take very I guess like ambitious is the right word approach it like I'm like okay Ash framework needs generators and I could have just like written some mix tasks but instead I'm like I'm going to create a whole whole new thing for the ecosystem a framework for generators so anybody can use it yeah um but that's kind of the philosophy behind behind how a lot of things Ash works is like when we want to get the a certain set of benefits we don't we solve the problem like in the general case of the problem so that we can use it anywhere so now any change can be can expose an atomic callback and any any type can say I live in the graphql like this or any I have a Json schema of this so then when you use as Json API you get an open API definition for free the same way you get the admin UI and your custom types can say here's what I look like in in an open API schema like all that sort of stuff is like we create these root this like spinal cord for everything and everything you know comes out of that um yeah true and igniter is kind of the same thing is like I want this I want it to be I want everybody to be able to generate to write good smart project patchers and generators um and so we have to do the hard thing definitely I mean I I like ignite a lot because I I thought the other day you know like a lot of people are building the starter package or what it called starter kits you know like uh bootstrap like where you can quickly create a project for something like let's just ship fast stuff you know these these um yeah whatever startup kits and I thought well there could also be starter kits for other topics like not necessarily a big you know s stter kit or something but just like here this is a starter kit for adding a Blog to your website right and and you want to use like nimble publisher and then you want to use some markdown converter and you want to use whatever some some CSS and maybe some JavaScript as well I mean maybe that that is a bit too much but still like you just want to set up Nimble publisher and you want to set up your routes um and you want to set up like SEO TXS you know that's something you always have to do manually so I was like hey you know like if I would do that what would I use and then I looked at igniter because I saw that Beacon is using it I it's like ha that's interesting yeah you can just like you know create a task like an install task for igniter and just run it and that's it basically absolutely I think the it's interesting because like in a part in a I kind of okay what am I trying to say here in some ways I think starter kits I don't like starter kits yeah in some ways primarily because they solve a problem I don't think that they one of the problems they solve is a problem I don't think we should have in the first place which is that I can't say install Ecto yeah in you know and all or I can't I can't build up my app I have to like pick use Phoenix new and I get what I gets you know you gets what you gets right and it's like I don't really like that so but with that said I think people who are making starter kits they currently the way they distribute those things is really not good no like the way that those start it's like download a zip file or like you know yeah all this sort of stuff right so I think those people should be like loving igniter like igniter is a way where okay you write here's what what it looks like to to do the my thing and you can write it now in the context of applying it to an existing app and provide a one-click install and so it's like I think even though I'm not I think you shouldn't need to reach for a starter kit just because it's get it's hard to get a basic installation of 10 different libraries I think that this allows those starter kits to go way faster right so the starter kit for pedal Pro is like runs the Ecto installer and the these installers and then it adds what their their magic at the end and their magic you know isn't the Ecto crap or or like setting up Phoenix or whatever in a certain way like that should all be provided by those libraries true so I I hope we get to that world yeah with igniter you know before long and and the other thing is like usually EST kit is a whole project thing you know but with igniter you can even have small parts and maybe even sell them as small parts you know if you only need like a strip integration with subscriptions that you need to handle in your product like just buy that and then use mix igniter and I'm sure do you do you work with uh private weos as well or does everything have to be on on Hex I think it should work with private oh there would be one okay maybe like a small change would require for it to actually work that way because we like explicitly hit the hex API so there might be like some small config like we do that to determine the version yeah um but if you give us a literal version like we could support like a dash dash repo option or something like that that tells us that would be the best because actually I'm in the Pro process of setting up my own private hex repo and it would be really interesting to have a like yeah I mean you need to add the repo anyway like you need to do mix Hees uh mix he. repo add and like with the authentication key and that kind of stuff so that's fine but then if you want to install a dependency usually in mix in the depth um uh array you can just add repo and then your private repo and it fetches it from there right so if you could add that to igniter I can just say igniter install and then my Library D- repo you know private repo that would be cool yeah yeah absolutely could do that I'd probably need to call it like Das D heex repo just because repo is such a loaded term but yeah anything somebody's gonna want to use that any option it' be easy because you can already do you can say mix igniter do install package at and then you can say path colon some somewhere on my file system or package at GitHub colon some GitHub repository yeah so we could do the same thing where we could say package at maybe yeah that's probably would be package at repo colon you know like a syx for saying go get it from this repo or a Dash D hex repo or something we there's a million we can do it just give me any option and I'm happy with it perfect yeah all right we got a couple of questions here first of all from Adam uh will there ever be a MySQL data layer uh we have an Enterprise app we'd love to use ash on but MySQL is a blocker there is a MySQL data layer okay so so Adam uh yeah it's a little bit myquel Yeah Ash MySQL um uh wait what we have SQL I we have my SQL it's in maybe it's only on GitHub is it only on GitHub right now A here there you go no that's no that's something else look at our GitHub I could swear there's a there's a MySQL so this or am I just thinking of sqlite and we got the SQL SQL light wait what oh somebody else made an ash SQL package ah wait am I being crazy I could swear we had MySQL yeah Ash codes 18 MySQL oh that's something else okay check in that check in that Forum topic because maybe I'm just wrong maybe so you said on May 28 wait for active changes Point Ash my sequel at those so already exists here oh there as Pro check my sequel wait what why didn't that show up when you were searching yeah that's weird I look for wait are there five polar requests do I think I'm not watching that repo Ash am I am I stupid how did this what I'm not I'm not watching it so I haven't been getting these oh my God issues in oh my gosh well it's just um yeah oh they're just depend okay there's there's one bug one issue yeah problems oh no wait I and I answered that one oh sorry uh they said mssql that's something different not my SQL oh yeah that's Microsoft SQL sorry thank you here say Al what I'll say about that is we have created a package called Ash SQL that's designed to be shared across SQL data data layers right so Ash postgress uses Ash SQL and it's like a it's a that you can use um it's not really like super well documented because it's not meant for like end end users but it's designed to abstract away the general process of working with Ecto against a SQL database so what could what would what you would do it's still a big process but what we would do is we would make an mssql you know Ash mssql we'd copy Ash MySQL or something like that M tweak some of the stuff but the bulk of the query building logic and all this other stuff actually lives in Ash SQL and so you wouldn't have to rewrite all that stuff so okay it wouldn't be an super easy thing but you know okay but okay for now if our company has a client we might do it but yeah for now try try oh no wait for now no you don't have I mean maybe Adam reach out to Zach if it's an Enterprise customer and they're willing to pay you know who knows maybe yeah money will kind Mak this a little bit more smooth the whole process yeah and and if it's an open source thing you know yeah we we help you know rates are a little different definitely yeah uh B said it would be nice to support Das D organization like hex does oh right right yeah we could do that see hex repo organization already to requests yeah yeah put them in the notes somebody says ignite I really re revolutionize my projects thank you Zach for all your efforts you are very welcome and I know the the project that uh that user is referring to oh nice I'm going to mangle his name so I'm not going to try to say it but but I'm excited about that project as well so yeah awesome cool uh no other questions yeah when's the book coming out where did that um cool there's another question from rosan a while back already any plans to make an UI for ignited generators something similar to y i i to code generators what is y i to PHP yeah I mean I don't have short-term plans for doing that sort of thing but I do have long-term plans for something maybe I would say even better right um but with that said it's open source software right so true there's and it's it's got us it's got stable interfaces you know everybody's welcome to to build that kind of thing um and you have my blessing and support yeah that's always the thing like you know just get an MVP or like a Pock ready and then you can ping the the library Creator and maybe they help you to bring it to production eventually like you just need to get started somebody needs to get started with that kind of stuff yeah exactly all right well otherwise Zack um I guess you know we could wrap it up a little yeah we've been going this is the longest live stream I've done so there you go yeah uh so yeah I could use I could use a bathroom break anyway so yeah that was a good time yeah I think so too me too but uh yeah thank you so much for coming on it was really really useful it was really really interesting as well sorry for asking all these like very detailed questions but you I mean you made it more fun for me because you know I you know we got to kind of take some tangents and onto the fun stuff and you know yeah yeah yeah you know it's always the point like you know if if I see something like this I'm like well but how how does it work under the hood you know and you actually explain it really well so that's that was really insightful thank you yeah cool all right well thank you everyone thank you Zach for coming along thank you everyone for join the stream uh the code will be on GitHub I'm just going to push it out right now and yeah the stream is also recorded on YouTube so you can watch it later if you want to and otherwise follow Zack he's live streaming as well on YouTube as well just look for Zack Daniel on YouTube and he's on Blue Sky on Twitter as well and yeah give Ash a try I I really like it well thank you very much everyone thank you Z and