I don't see a lot of structure

Streamed

Content Security Policy images PR. Active user graph extrapolation PR. OpenGraph tags PR. Bump checkout action PR. Vote hydration refactoring PR -> ActiveRecordโ€™s limitations with SQL projections and joins with guest Marco Roth. ReactionView throwing levels of abstraction into contrast.

scratch


topics
  jujutsu and healthy communities https://lobste.rs/s/ghdv6w/i_see_future_jj
    brainwane's talk https://en.wikisource.org/wiki/Hospitality,_Jerks,_and_What_I_Learned
  PRs
    fix active users graph https://github.com/lobsters/lobsters/pull/1763
    vote hydration https://github.com/lobsters/lobsters/pull/1748
    open graph https://github.com/lobsters/lobsters/pull/1764
  open graph multiple author links refactor
  hat request approval bug
  markdowner: link based on contemporary usernames
  username change timeout
  story merging UI? https://lobste.rs/c/3ssni6


chamlis's second query:
  WITH user_interaction_rate AS (
      SELECT users.id,
              (
                  (SELECT COUNT(*) FROM stories
                          WHERE stories.user_id = users.id
                          AND stories.created_at >= (now() - INTERVAL 365 DAY)
                  ) +
                  (SELECT COUNT(*) FROM comments
                          WHERE comments.user_id = users.id
                          AND comments.created_at >= (now() - INTERVAL 365 DAY)
                  ) +
                  (SELECT COUNT(*) FROM votes
                          WHERE votes.user_id = users.id
                          AND votes.updated_at >= (now() - INTERVAL 365 DAY)
                  )
              ) / LEAST(365, TIMESTAMPDIFF(DAY, users.created_at, NOW())) AS rate
              FROM users
  ),
  
  user_active AS (
      SELECT users.id,
              EXISTS (SELECT 1 FROM stories WHERE stories.user_id = users.id AND stories.created_at >= CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE)) OR
              EXISTS (SELECT 1 FROM comments WHERE comments.user_id = users.id AND comments.created_at >= CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE)) OR
              EXISTS (SELECT 1 FROM votes WHERE votes.user_id = users.id AND votes.updated_at >= CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE)) AS active
              FROM users
  ),
  
  this_month AS (
      SELECT users.id,
              IF(
                  user_active.active,
                  1,
                  1 - EXP(
                    -1 *
                    user_interaction_rate.rate *
                    TIMESTAMPDIFF(DAY, NOW(), CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE) + INTERVAL 1 MONTH)
                  )
              ) AS expectation
      FROM users
      INNER JOIN user_active ON user_active.id = users.id
      INNER JOIN user_interaction_rate ON user_interaction_rate.id = users.id
      WHERE users.banned_at IS NULL AND users.deleted_at IS NULL
  )
  
  SELECT SUM(this_month.expectation) FROM this_month;

biz book history
  Crossing the Chasm https://en.wikipedia.org/wiki/Crossing_the_Chasm
  The Innovator's Dilemma https://en.wikipedia.org/wiki/The_Innovator%27s_Dilemma


"We build our computers the way we build our cities--over time, without a plan, on top of ruins."
  https://en.wikipedia.org/wiki/Ellen_Ullman

https://en.wikipedia.org/wiki/The_Death_and_Life_of_Great_American_Cities
https://en.wikipedia.org/wiki/Guns,_Germs,_and_Steel


Should Slack send a notification flowchart:
https://substackcdn.com/image/fetch/$s_!WJca!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2Fe677600d-de1e-4212-96bf-951fdceb63f5_1491x1421.jpeg


title
  soggy potato chip theory, I'm intrigued
  we should get Lobsters some piercings

post-stream
    

Transcripts are generated with whisperx, so they mistranscribe basically every username and technical term. They're OK but not great, advice appreciated.

Recording



01:01[SPEAKER_00]: Good afternoon. [SPEAKER_00]: Let's see. [SPEAKER_00]: There we are. [SPEAKER_00]: This is Lobster's. [SPEAKER_00]: I'm Peter. [SPEAKER_00]: And this is Lobster's office hours. [SPEAKER_00]: I stream. [SPEAKER_00]: Oh, and we do have a supervisor for once. [SPEAKER_00]: Let's get that camera. [SPEAKER_00]: See if that wants to behave. [SPEAKER_00]: There we go. [SPEAKER_00]: So let's add the boss. pushcx This is Lobsters office hours, ask questions anytime. The boss is currently sleeping.
[SPEAKER_00]: he is doing a big sleep but we'll see if he wakes up all right so this is lobsters office hours ask questions all right so yeah i've got this website is lobsters and if folks [SPEAKER_00]: Would like to drop in and ask questions anytime you can throw those in the chat. [SPEAKER_00]: And then otherwise I work on maintaining stuff.

02:12[SPEAKER_00]: And we'll take a look on. [SPEAKER_00]: What's happening? [SPEAKER_00]: So I think I nudged something since the last stream. [SPEAKER_00]: So let's also look at closed PRs and sort the useful way that's not the default. [SPEAKER_00]: That's the opposite of the useful way. [SPEAKER_00]: There we go. [SPEAKER_00]: yeah so i had a discussion about csp content security policy which has been a hassle for us it i mean by design it's supposed to be a hassle it's like a a hassle in the way having a emergency fire exit in your building is a hassle like oh i can't put stuff on that wall [SPEAKER_00]: We have, I don't know, four or five.

03:13 pushcxLet's put this in the notes.

...24pushcx https://github.com/lobsters/lob…
[SPEAKER_00]: And I'll share the link here if anybody's curious to see what that's about. [SPEAKER_00]: But we have, where's my list? [SPEAKER_00]: Yeah, literally [SPEAKER_00]: five posts that have images in them and the current content security policy prohibits them it's an easy oversight to make someone opened a pull request to permit images but it was too permissive it was basically let's allow images everywhere which is not what we want because there are so few things we really only want to allow it on those few things and [SPEAKER_00]: maybe what we should do is just pull the images into the local repo. [SPEAKER_00]: Cause there are, I don't know, only one or two images in each of these. [SPEAKER_00]: So I don't, it's odd. [SPEAKER_00]: It feels like a mixing of layers of abstraction to have images from posts in the code repository, but you know, it's five or 10. [SPEAKER_00]: And it helps us keep the site secure I think I can live with that as a compromise so we'll see where that goes. [SPEAKER_00]: The other thing is on the last stream I merged the. [SPEAKER_00]: Now it must have been between streams I merged the. [SPEAKER_00]: New extrapolation in the statistics graphs, which is the newest contribution from Felipe Vogel. [SPEAKER_00]: So if you look, and I added this little help text, because after I added it, I was like, yep, it's exactly what I wanted. [SPEAKER_00]: And I said I didn't want help text, but as soon as I looked at it, I was like, oh, this is not instantly obvious. [SPEAKER_00]: We've got to explain this. graefchen Heya limesHi
[SPEAKER_00]: So now, being on the 20th of the month makes this really easy. [SPEAKER_00]: If you had looked at this previously, you would have just seen a dot here, which is like, oh, that's kind of low. [SPEAKER_00]: Or... [SPEAKER_00]: stories by month it would be like oh that's really low but it's like well this dot is partial data we're only 20 days through the month so making it an outline makes it clear that it's partial data hey grave chen and now there's also a simple extrapolation of you know if we are 60 of the way through the days of the month we can multiply by the inverse of that and kind of just [SPEAKER_00]: naively extrapolate where we're going to end at the end of the month. [SPEAKER_00]: And that's what this dotted line is. [SPEAKER_00]: So I think this is a solid improvement to all of these graphs. [SPEAKER_00]: Huh. [SPEAKER_00]: Why are they different widths? That's strange. I don't know why that would be the case.

06:31[SPEAKER_00]: so i don't know why these are different widths i will have to file it as a bug i guess i don't love that the graph library like shoves this text out or i'd rather space the the dates out a little more and like right align the dates but it doesn't seem to have a heck of a lot of options the active users per month you look at this one and you're like oh this is wrong right like the [SPEAKER_00]: extrapolated value is ridiculous especially because none of these other graphs are way above trend what's happening here is lobster the the number of stories submitted per month or comments per month like each day is pretty independent of each other day felipe realized for active users [SPEAKER_00]: Each user who shows up Monday is probably going to show up on Tuesday, and so this is way overestimating because it is naively assuming that. [SPEAKER_00]: You know, tomorrow we'll have a whole new set of users when actually will have probably 80 or 90% the same users. [SPEAKER_00]: So that I think yeah. [SPEAKER_00]: He submitted a PR to fix that so let's grab that one in. [SPEAKER_00]: user graph that's that one and so he just says let's just cut it sure and it looks like some code got reorganized let's take a look scale y divisions extrapolate oh sure make it an option instead of special casing it that is totally sensible graefchen Stats and Graphs are fun. limesSit
[SPEAKER_00]: then you just call yields and then that move what is time series yeah yeah it's one of those where the the main version of this was not a lot of code to write [SPEAKER_00]: And it just makes so many things very clear to help the site understand itself. [SPEAKER_00]: This page is one of the best returns we've had on developer time for community understanding itself. Sure.

09:19Why does it have to be overwritten? [SPEAKER_00]: Why is it private? [SPEAKER_00]: Because it's temporarily coupled? Oh, that's really nice. That's a significant improvement.

...42I don't see that add data is. [SPEAKER_00]: Oh, time series is inheriting from. We're wrapping it. Got it.

10:03And then data must already be. No, I don't understand. [SPEAKER_00]: No, it's replacing it and then calling super. [SPEAKER_00]: Got it. [SPEAKER_00]: Is there a better Ruby way to express that?

...34[SPEAKER_00]: Not really. [SPEAKER_00]: The way super kind of carries arguments along is not my favorite Ruby feature. [SPEAKER_00]: I don't think there's too much we can do there. [SPEAKER_00]: All right. Start SVG. This is very nice. I like this a bunch.

11:06[SPEAKER_05]: Hmm.

...39The help text is going to be wrong. That's OK.

13:40Really? There we go. So let's go ahead and just merge that in. [SPEAKER_00]: I've kind of given up on fixing the GitHub titles. graefchen Line goes up limesYay
[SPEAKER_00]: It's such a chore. [SPEAKER_00]: So if I merged that, let's go hop over to browser yep i kind of like that emoji what state am i in okay i'm not anywhere i didn't think i left it anywhere

14:40Yeah. [SPEAKER_00]: All right. [SPEAKER_00]: So I don't want to say in all charts.

15:21That's good enough. [SPEAKER_00]: And do I want to... Let's look at that. [SPEAKER_00]: It occurred to me that this page doesn't have a title on it. graefchen Some Emoji are really fun. I for one *love* the triumph emoji, more because the Story behind it than the design itself, but it is fun. limesNodders
[SPEAKER_00]: And the way the help text kind of floats at the top of the page, I don't know, it just looks ugly. So let's see how this looks locally. Yeah, that's fine.

16:01What is the triumph emoji? That means triumph? That's a look of triumph. This must be a cultural translation.

...27[SPEAKER_00]: Not exactly one of Ekman's six universal expressions, huh? graefchen Yes. Because Japan. limesSmart
[SPEAKER_00]: so i don't know what this is this one we updated 12 hours ago great yeah i think there's an interesting cultural tweet there in that for americans the gestures of triumph tend to be made with the arms so either like you know [SPEAKER_00]: Fist pumping like the haha business meme or two arms raised overhead like a trophy. [SPEAKER_00]: What is it?

17:18I love this one. So yeah, triumph. [SPEAKER_00]: So let's see what we got here. [SPEAKER_00]: We got open graph tags. [SPEAKER_00]: But that's what I think it is. [SPEAKER_00]: It's been hanging out for like two years. [SPEAKER_00]: It is a well-aged.

...46Hmm. All right, then. And then we had refactoring.

...57Regression. [SPEAKER_00]: there was this chore, there's not a lot to show here, but, this one, 1761 is for grabbed the wrong ID number. [SPEAKER_00]: Didn't I is for, the continuous integration that we run on get hub. [SPEAKER_00]: So that's fine. [SPEAKER_00]: It's like a one-liner changing the number four to five, but might as well be on the current. [SPEAKER_00]: All right. [SPEAKER_00]: So this one, I talked about it, so I will grab it here. [SPEAKER_00]: Oh, no. [SPEAKER_00]: I already put it in. [SPEAKER_00]: Okay. One, two, three, four, five. graefchen Emoji usage by itself can (and I think even is) something that is studies. There are also those emoji that get another meaning. Like the high give emoji being predominantly used as a prayer emoji. limesD
One, two, three, four, five. All right. Let's just grab that link. So my notes are complete.

19:06[SPEAKER_00]: I always thought it was a prayer emoji or like a thanks emoji. [SPEAKER_00]: It didn't occur to me it was supposed to be a high five emoji.

...24[SPEAKER_00]: Maybe if the hands had been offset or something. bsandro VoHiYo hello cyberpals
graefchen It is official high five. But pictogram are indeed fun
[SPEAKER_00]: Along those lines, the high five is a surprisingly recently invented gesture. [SPEAKER_00]: I want to say late 70s. [SPEAKER_00]: A couple of baseball players did it. [SPEAKER_00]: Oh, hey, Sandra. [SPEAKER_00]: Welcome back. So let's look at this one because I have not.

...58julianwgs Hi :)
Well, that looks positive. And then we have a, why does it say test image? It must be there. Hey, Julian. All right. So an OG type. Yes, we are an OG website.

20:34it's odd that standard rv didn't complain about that we don't indent things like that so i would bet the build didn't run and the author didn't quite catch it so i'm going to name this property so if we looked at

21:02The open graph docs are what I want.

...09There's an author, but would require changing the type from website to article. Depending how they define it, that might be correct.

...38there's music video no vertical hmm book payment i don't see article or author mentioned okay so here's article i think it's safe enough to call our individual stories articles

22:14Yeah.

23:28[SPEAKER_00]: All right. [SPEAKER_00]: So that's a nice little thing. [SPEAKER_00]: I'll get that merge probably in a day or two. [SPEAKER_00]: Yes. pushcx https://github.com/lobsters/lob…
[SPEAKER_00]: So this one with the hydrator was interesting. [SPEAKER_00]: And my comments have apparently vanished because [SPEAKER_00]: The force pushed. Okay, get out. Thanks. [SPEAKER_00]: So the gist of this one is that we have a repeated bit of logic for there is a thread of comments and then it has to get hydrated with the current user's info like [SPEAKER_00]: Did you vote on this comment, did you flag this comment have you replied to this comment and.

24:35[SPEAKER_00]: yeah it's been repeated. [SPEAKER_00]: Several times through the site basically anything that mentions current vote. [SPEAKER_00]: yeah then there's this apply current vote and. [SPEAKER_00]: The two frustrations are there is a lot of duplication here. [SPEAKER_00]: It has been buggy because we have incorrectly duplicated that. [SPEAKER_00]: And so a number of times we've had minor bugs, like when I look at a comment on the search engine, it doesn't show that I've uploaded it. [SPEAKER_00]: Because one of these lines was missing. [SPEAKER_00]: And then

25:20[SPEAKER_00]: also this method of we're going to loop all of the comments and apply these things i have been trying to minimize how many times we loop the comments and i am aware that you know looping 50 or 100 elements is not a big deal but showing a single story view is our hot path this this is the one place [SPEAKER_00]: when I say it's the hot path, I mean more than 50% of all of our paid renders are showing the comments on a story. [SPEAKER_00]: And so I will take very, very fiddly, very small performance improvements to it. [SPEAKER_00]: Like don't loop the comments extra times because it is our, you know, it's where we get the most return on investment for nitpicky little performance improvements. [SPEAKER_00]: So, [SPEAKER_00]: What else do we have? [SPEAKER_00]: The user controller. [SPEAKER_00]: I thought I just added it to another controller in the mod namespace. [SPEAKER_00]: I don't see that listed or I skimmed it too fast. It's missing. [SPEAKER_00]: All right, so then this is. [SPEAKER_00]: See, here's another loop of. I guess we have to loop it, though.

26:59Why hydrate unless hydrated? Why would you call instance variable set instead of just equals. These are all accessible. julianwgs What kind of hydration is ruby (on rails) doing? This kind? https://en.wikipedia.org/wiki/H…
And I see what it's doing. [SPEAKER_00]: It's doing a just in time thing so they don't have to touch every call site, which is fine. graefchen The void is bathing limesAw
[SPEAKER_00]: No, not that kind of web development hydration. [SPEAKER_00]: I don't even have to click the link. [SPEAKER_00]: I know that's going to be front end. [SPEAKER_00]: Yeah. Yeah, he's the boss. Let me get the light on in here so you can see him a little better.

28:27[SPEAKER_00]: Alright, and I took the second to get myself a glass of water. [SPEAKER_00]: So Julian, the hydration that's happening here is kind of the generic idea of we have a data structure that has some amount of data. [SPEAKER_00]: In this case, it's the core comment information. [SPEAKER_00]: In other places, sometimes it's just the IDs of what we want to render. [SPEAKER_00]: And then we are [SPEAKER_00]: hydrating that existing data with more data. [SPEAKER_00]: And in our case, that's data about what the currently logged in user has been doing like voting.

29:25And I guess since all these are hashes, this is fine.

...34[SPEAKER_00]: Oh, wait. julianwgs But this happens server side, right?
[SPEAKER_00]: So this person is using the word hydrate to refer to whether these queries have run. [SPEAKER_00]: Yes, Julian, this all happens server side. [SPEAKER_00]: That's why I didn't want to click your link is usually what people are doing is [SPEAKER_00]: the server side is rendering some amount of data. julianwgs yeah that kind of hydration I know :D
[SPEAKER_00]: Like if we were a single page app, maybe you would click on a story and it would send back some story info and the client side would be responsible for hydrating the template for a comment with the data for a comment. Yeah.

30:27Okay, so I get what's happening here. I think we can just... [SPEAKER_00]: So a thing that happens is actually Rails is already lazy about these queries in that they don't run when you define them. [SPEAKER_00]: They run when you start accessing their responses. [SPEAKER_00]: All these things can move up to the initializer. Okay.

31:38HouseTube Hey HeyGuys Marco here, cannot login with my other account given the AWS outage lol
Oh, hi, Marco. Is that AWS outage still going? [SPEAKER_00]: I had no idea. [SPEAKER_00]: Man, that's a long one. HouseTube yup it is
[SPEAKER_00]: I want to say that one started before I even got up, which was like, I don't know, eight hours ago. [SPEAKER_00]: All right. [SPEAKER_00]: Rough. [SPEAKER_00]: Yeah, I tried to log into a bank today and it didn't work. [SPEAKER_00]: And I was like, oh, well, I guess I know where you're hosted.

32:27julianwgs Is there a live ticker?
I'm stealing a snippet of code.

...58[SPEAKER_00]: I think aws is status page has earned a reputation of having a green dot a little more often than it should, but I would assume if they've been basically down for eight hours that it's gotta have some kind of at least a yellow dot. [SPEAKER_00]: it's probably like status dot aws or something.

33:48HouseTube I'm surprised all my apps on heroku are still running, you cannot login into the dashboard though
graefchen I love one gif I see people post when it is an dns outage. It is the same dns haiku and it is so funny. limesGiggle
[SPEAKER_00]: Do we know any details about what's wrong with aws I haven't like I have heard the term that it's down and i've seen people posting memes about you got a distributed system that's hosted entirely in us East one but. [SPEAKER_00]: I don't know what's down.

35:22HouseTube I haven't seen anything concrete, but I also haven't actively checked haha
julianwgs Here is some info: https://health.aws.amazon.com/h… But not really properly aggregated
julianwgs Looking forward to the post mortem
[SPEAKER_00]: We see increased error rates and latency. [SPEAKER_00]: That's a pretty generic title. Epic_Ninja_Elephant Happy Monday.
[SPEAKER_00]: Can't start EC2 instances.

...39graefchen The BBC reports that it was a DNS failure. limesLurk
[SPEAKER_00]: Yeah, we'll see what that one is. [SPEAKER_00]: No elephant. bsandro of course it is DNS, it is always DNS
[SPEAKER_00]: Apparently this is sad Monday. [SPEAKER_00]: It's always DNS. Epic_Ninja_Elephant No, anytime AWS is down is a very good day.
[SPEAKER_00]: It's always mildly funny to me to hear of a giant old media company like the BBC reporting on an ongoing tech outage.

36:56Epic_Ninja_Elephant I noticed today that /inbox/all takes 13+ seconds to load. Is that expected?
[SPEAKER_00]: We want to do so we can't actually do or equals.

37:07[SPEAKER_00]: As long as we're in fiddly performance stuff, kind of my question is whether.

...28[SPEAKER_00]: whether we're going to be doing this multiple times, because as the views access the hydrator, which I don't actually see that they're doing, I must have scrolled to the wrong part. It's gonna hydrate them multiple times.

38:15We're having a

39:25julianwgs @Epic_Ninja_Elephant Just now it was ~6s for me. Seems longer than normal
[SPEAKER_00]: So I'm nitpicking in my head the idea of, oh, we'll just do this performance optimization where you maintain a hash of which comments you've hydrated so you don't rehydrate them. [SPEAKER_00]: And it's complicated enough that, wow, six or 13 seconds are both unexpected and both unacceptable.

...57Huh? julianwgs I had no messages
[SPEAKER_00]: I can't think off the top of my head of any code that should have touched that like this will touch that but sure hasn't been shipped yet.

40:12That's strange. Hmm.

...27[SPEAKER_00]: Julian and Epic Ninja Elephant, can you keep an eye on it? [SPEAKER_00]: Well, actually, let me go make sure that the server's not under load for some reason.

...44No, it looks pretty normal. Yeah, here, we can bring that on screen, right? [SPEAKER_00]: Yeah, there's no end bars or anything there. [SPEAKER_00]: Like we're ticking along, we're seeing decent utilization, but like, this is fine. [SPEAKER_00]: Nobody's swamped, RAM isn't going nuts. [SPEAKER_00]: We're not blowing out the swap. [SPEAKER_00]: Like this is a hundred percent typical. [SPEAKER_00]: A load average below the number of processors is good times, right? Let me check the database.

41:30[SPEAKER_00]: yeah database is you know barely working this is also the typical case for the database where it's just kind of slowly ticking along at single digit percentages because this was one of those where i bumped the box up to get more ram and it came with a cpu bump so i just wanted [SPEAKER_00]: To have basically our entire database fit in ram because that was a lot easier than thinking about. query performance.

42:19haha so here's where. They're using it just this one place. Okay. [SPEAKER_00]: That seems like a very... [SPEAKER_00]: So this is kind of an OO thing. Epic_Ninja_Elephant @pushcx Do you have slowqueries enabled in mariadb? I'd expect a 13 sec query to show up.
[SPEAKER_00]: It seems odd to me to pass the hydrator all the way down through the templates so that the innermost template can know how to use it.

...57So this one, this is just a duplicate due to partial.

43:11[SPEAKER_00]: I don't know off the top of my head. [SPEAKER_00]: We could check the Lobster's Ansible repo. [SPEAKER_00]: That's still what's live there.

...28yeah so i guess standing threads yeah so this is kind of an

...55[SPEAKER_00]: And oh, hassle, but I don't want to pass the hydrator down through all the templates. [SPEAKER_00]: It seems like such a implementation detail.

44:10Especially for this one that's multiple. [SPEAKER_00]: Right, like here, I could say, you know, don't do this. [SPEAKER_00]: Call the hydrator and pass in the comment it returns. [SPEAKER_00]: And that would handle it, but here, I think the answer is to replace at threads, to make the hydrator a proxy object or, you know, a facade for this collection. Yeah. Because if it delegates or if it defines an each. Yeah.

45:42Does that work here, though? Maybe not.

...58[SPEAKER_00]: So here on inbox controller, the thing you're exactly asking about. [SPEAKER_00]: Because there are two kinds of things.

46:13We looped over it to hydrate all the votes.

47:03chamlis_ hey all, I see we're under supervision today
It's weird that it's getting past an individual comment instead of an ID, because it's sort of, it is holding an array, but then it's providing a hash interface.

...39Yeah, yeah, we got the boss on stream today.

48:22Epic_Ninja_Elephant Cat needs to approve all PRs?
[SPEAKER_00]: Oh, he has to approve or disapprove everything. Epic_Ninja_Elephant Senior Cat review. Seems reasonable.
[SPEAKER_00]: Actually, he tried twice to go through the screen window to get a bird. [SPEAKER_00]: It was out on the porch, so... [SPEAKER_00]: He's a little bit of a monster today. [SPEAKER_00]: I gotta get one of those ring lights for him. [SPEAKER_00]: I am aware that he's a black cat with basically no definition.

...55Thank you.

49:45bsandro one of my cats is non-textured as well!
HouseTube For stuff like this we have been really enjoying to use `ActiveRecord::AssociatedObject` in RubyEvents
Could you explain by what you mean in associated object? I want to say I just read about this somewhere. Do you have maybe I guess what I should have asked for is do you have a link to where it's used in Ruby events?

50:47HouseTube there is actually a link in that README
pushcx https://github.com/kaspth/activ…
pushcx https://github.com/search?q=rep…
[SPEAKER_00]: Let's grab this link to share. If anybody's curious, that's this code search.

51:09[SPEAKER_00]: Yeah, this whole thing is a little bit frustrating. [SPEAKER_00]: If Rails had [SPEAKER_00]: better SQL support, all of this would just vanish. [SPEAKER_00]: Because instead of having to do multiple queries, we would just be doing one query that hydrated a comment class that was not a one-to-one mapping to the comment table, and so it would have much better support for these kind of virtual attributes.

...42Can we do that? HouseTube this feels very service-objecty, which is usually not really Railsy
[SPEAKER_00]: Like when we access comments, except through the inbox, we do go through the same set of scopes every time. [SPEAKER_00]: So if base said, well, I want to select star and then do this join, well, Rails is forcing it to be service objecty. [SPEAKER_00]: What I actually want is a projection. [SPEAKER_00]: and Rails has active record, doesn't have good support for projections. [SPEAKER_00]: That's been just an unending frustration for me. So let's... So let's find me and then... You've got those... [SPEAKER_00]: Let's find a positive comment vote where not comment ID is nil, where vote is one last.

53:07[SPEAKER_00]: That looks plausible. [SPEAKER_00]: All right, so here's a comment that I have upvoted. [SPEAKER_00]: So what I really would like to say is [SPEAKER_00]: As I'm searching the comments from this, I would be like story, right, s equals story.find whatever. [SPEAKER_00]: And then I would say s comments.

...40Is it not base? What is it?

...58[SPEAKER_00]: I would be starting from active along with for presentation right, so I would say story comments for presentation. And I could say like select star.

54:26[SPEAKER_00]: And that's basically correct yes because i'm getting star from comments, but what I also want to select is can I pass multiple things like this.

55:01I see what I would like to do is a left outer join where id is equal to How do I even say this?

...50Let's see.

56:09[SPEAKER_00]: I know my ID is 78, I'm just trying to force myself to do it through Active Record.

...37You're showing me everything instead of the query. Where are we now? Select comments. Yeah, see, this is. [SPEAKER_00]: I just got all of the comments instead of anything like what I want to.

57:01Now the cache is filled, so I can't see the query. [SPEAKER_00]: Does that make it a new query? Nope.

...32What's the way to accurate record clear query cache? Sure, let's just yellow the LLM suggestion. OK, so it's not actually running shit. [SPEAKER_00]: Only hash symbol and array are allowed. [SPEAKER_00]: Cool, in which function? [SPEAKER_00]: Because there are like eight. It's got to be select, right?

58:13And I don't want to say star. I want to say comments.star. Delete the nil.

...28[SPEAKER_00]: You see, it's not actually running anything like the query I'm asking it to run. [SPEAKER_00]: It's literally just loading all of the comments on the story. [SPEAKER_00]: So this is one of those places where [SPEAKER_00]: Active record is just not expressive. [SPEAKER_00]: What I actually want to do is select comments dot star comma votes vote as current vote come from comments left outer. [SPEAKER_00]: join votes on votes comment id equals comments id where votes dot well where comments dot story id equals you know one two three whatever that was and votes user id is 78 and this projection is i want all of the fields from comments [SPEAKER_00]: Plus, let me give you the SQL for one more column on the comment table. [SPEAKER_00]: And Rails just really does not want me to express this. [SPEAKER_00]: Let's grab that for the scratch. HouseTube I guess you might be able to using a CTE, no?
[SPEAKER_00]: What do we do in terminal? [SPEAKER_00]: That's a new one on me. Very trippy. [SPEAKER_00]: All right, let's get a new terminal. [SPEAKER_00]: Oh, actually clicking on the terminal a couple of times. [SPEAKER_00]: All right, brought it back. [SPEAKER_00]: All right, let's just get this new one then. [SPEAKER_00]: Don't know what Vim was doing there. [SPEAKER_00]: Oh, but I exited. [SPEAKER_00]: Great, so I effectively have a new one anyways. Oh, cool. Did it suspend? Why is that file still open? Okay, yeah, it suspended. All right.

01:01:05I lost that clipboard, didn't I? Yep. So it's still there. Okay. So without scrolling infinitely, we will copy that query.

...35Epic_Ninja_Elephant Ooh, big stretch by senior manager.
So yeah. Your public is adoring, sir.

...50[SPEAKER_00]: Maybe I should run a Kickstarter to buy him a ring light. [SPEAKER_00]: Actually, aren't the ring lights called El Gato? [SPEAKER_00]: Isn't that the brand name? [SPEAKER_00]: And he is El Gato? [SPEAKER_00]: That can't be a coincidence, right?

01:02:13[SPEAKER_00]: So even if I had a common table expression, right, and I called it with hydrated comments as, it would basically be this exact same query, and Rails doesn't really want to hydrate the comment model out of a common table expression. HouseTube it does
[SPEAKER_00]: Rails is, I mean, I keep saying Rails, it's ActiveRecord, is very much oriented to HouseTube it doesn't really care where the data is coming from
[SPEAKER_00]: individual tables in ways that i mean i think i've been streaming for an hour and two minutes and i've already seen four ways that this limitation has bit me we're just kind of because there's the the stats graphs has to do it there's the [SPEAKER_00]: notifications on inbox controller that we just saw where this is going to come up again there's the mod version of it with activity marco maybe i'm not understanding what you're suggesting is there any chance there's an example of this on ribby events or another open source repository you know bring this back come here HouseTube I sadly don't think so
That's not where I want to go.

01:04:03[SPEAKER_00]: Okay. [SPEAKER_00]: Because I've used common table expressions for selecting data. [SPEAKER_00]: We have a big one in comment actually down here at the bottom. [SPEAKER_00]: we we have like three versions of oh we're down to two versions of this now but so we say we get the sql engine to rebuild the tree and i guess it's fine as long as the thing that comes back is comment shaped if i put the hydration in here [SPEAKER_00]: like the left outer join I was just talking about, would it map that added attribute to the accessor?

01:05:19HouseTube yeah
HouseTube it's just not inspectable by irb
It's just not inspectable. I'm not sure what you mean by that.

...34[SPEAKER_00]: I mean, what I saw in IRB was it was just not running the query I instructed. [SPEAKER_00]: And that wasn't IRB, that was ActiveRecords logging to standard out.

...53HouseTube like the data is on the model, but you don't see it if you pretty print the record in irb
would i even shove this in here would i say like left outer join oh yeah that's fine that's that's not a hassle i see what you're saying because it doesn't know that that [SPEAKER_00]: Adder accessory is something I want printed as an attribute because it's sort of a second class attribute. [SPEAKER_00]: I follow.

01:06:46HouseTube yeah, exactly
I just want to see if it's going to run. The query I want. What are we mad about? Did I miss a parentheses? No, it's just OK, so.

01:07:03And I'm going to say.

...11[SPEAKER_00]: Select comments star and then I'm also going to select. [SPEAKER_00]: votes.vote as current vote. Okay.

...32So I have that story, and I say s.er, no, I say, [SPEAKER_00]: comment story threads for the story s undefined method it's left outer joins plural this always gets me error when inspecting the object okay so it actually

01:08:13Did it work?

...22[SPEAKER_05]: No.

...31So is it mad about the select or the join? Let's find out. It's mad about the join. Only hash symbol and array are allowed. [SPEAKER_00]: Okay. [SPEAKER_00]: It does know how to join the votes, so we'll tell it to join the votes and then select the things I care about. HouseTube it might be just when inspecting it
It didn't print me. Oh, here we go. [SPEAKER_00]: Select comments.star, votes vote is current vote. [SPEAKER_00]: Huh, this is... [SPEAKER_00]: This is doing what I want. [SPEAKER_00]: All my gripping. [SPEAKER_00]: So this might be nil. [SPEAKER_00]: What was the ID of the vote that I looked at? 262. So.

01:09:56ID it. OK, so found first. Current vote should be one. It's nil. So it didn't actually hydrate. It did the right query.

01:10:21[SPEAKER_00]: Let's double check that I didn't typo somewhere along the way, but [SPEAKER_00]: Well, where user ID is 78 and comment ID is that vote. First go. No, I must have type out, OK, hang on.

...51[SPEAKER_00]: Well, you know what? dzwdz only popped in for a second but yay, cat cam
[SPEAKER_00]: The thing I actually care is the hydration. [SPEAKER_00]: So let's go through the CS and then.

01:11:11Same typo. Yeah, I have been. [SPEAKER_00]: None of them are right. [SPEAKER_00]: so i've been mentioning that he likes to go up there mostly in the fall and winter and so the moment it dipped below 50 and i did a first stream there he is all right let's let's find a comment

...59[SPEAKER_00]: Here is the latest comment on this particular database that I have updated. So let's find that story.

01:12:281, 1, 8, 5, 45. Should have copied and pasted that.

...48[SPEAKER_00]: Wait. [SPEAKER_00]: Oh, the select was returning empty array because [SPEAKER_00]: So CS count or no, I'm not going to see us first found our guy. Yeah.

01:13:15[SPEAKER_00]: Oh, here we go. [SPEAKER_00]: Now it's actually running and it found us error in the query. [SPEAKER_00]: Weird. [SPEAKER_00]: I thought the previous debug print would have printed all that out. [SPEAKER_00]: Next to use, next to star. Let's vote as current vote. Comments. What does it not like about that?

...50Oh, it's the it's the count. [SPEAKER_00]: It doesn't like the count. [SPEAKER_00]: Yeah. [SPEAKER_00]: Yeah, we got there the same time, so. [SPEAKER_00]: OK, so there are three comments on this.

01:14:12[SPEAKER_00]: And the third one is the one I voted, right? [SPEAKER_00]: Where'd my vote go? 616948. The first one is the one I voted, and it definitely did not hydrate. So I'll bring that query back up. [SPEAKER_00]: But Marco, this is the thing you were suggesting, and I thought ActiveRecord couldn't do, and it seems to not be doing. [SPEAKER_00]: Hey Corey, this is an English channel. [SPEAKER_00]: I don't really have anything to say in other languages because without a facecam, my American Sign Language is not very useful. [SPEAKER_00]: And I definitely can't talk code in Spanish or Canada. So...

01:15:41[SPEAKER_00]: yeah i don't know what to say there i would really like it to work but it doesn't seem to

01:16:18Hmm.

...25Yeah, that's fair, but I would have to add that to the user model, right?

...35All right. Bye, Corey.

...46That's fucking Twitch.

...53graefchen Twitch is ... weird.
graefchen Unban
[SPEAKER_00]: marco if you're still watching i'm sorry the the chat message jumped and how do i untime out untime out house two and you know the best part of that is because twitch just did that has to be should be able to talk again but because twitch just did that it also just deleted HouseTube no worries
[SPEAKER_00]: all of marco's messages from the chat log so now the the archive is going to be swiss cheese where i'm just talking to someone who's not apparently talking back yeah so the command was on timeout grave chen unbanned just says that they are not currently banned which is correct that's that's so awesome HouseTube we also have the same color/almost same name length haha
bsandro does twitch still allow to use IRC for chat?
[SPEAKER_00]: kind of a pet peeve i have about guis like that if you tap on something it should probably actually figure out your tap target based on what was on screen about 100 milliseconds before because human reaction time is so slow that that's how long it takes even a very fast person to make a decision and [SPEAKER_00]: The phenomena of the UI moved under the finger is especially irritating. graefchen Hmm. Has been a while since I needed to use it. Good to know they changed it. limesNoted
Epic_Ninja_Elephant The UI should pause under the cursor.
[SPEAKER_00]: There's a longstanding bug in iOS Apple Maps where if you search for a location and tap directions, the UI will appear and it will show you the, oh, you can choose your mode of transportation that is the [SPEAKER_00]: like walk, drive, bike, those buttons will move in about 75 to 150 milliseconds as the routes come back. [SPEAKER_00]: And so if you try to tap them the instant you see them, the UI will have moved and you will tap on the wrong thing. Epic_Ninja_Elephant Adaptive UIs are the worst.
[SPEAKER_00]: And iOS Maps has had this bug for years.

01:19:35[SPEAKER_00]: Firefox gets this right with the tree style tabs, where with the tree style tabs plugin, as you close tabs, if your mouse is on one, it holds and it stands exactly where it is. [SPEAKER_00]: But if you move the mouse off of the sidebar, then the UI updates. Epic_Ninja_Elephant If you've ever watched someone with cognitive or physical disabilities use a computer, you'll scream (at the programmers).
[SPEAKER_00]: So the UI stays stable under your mouse cursor. [SPEAKER_00]: which is pretty dang handy. [SPEAKER_00]: All right, so I don't have to watch. [SPEAKER_00]: I have seen that. Epic_Ninja_Elephant And we are all temporarily ablebodied, as I like to say.
[SPEAKER_00]: So let's just say, all right.

01:20:47[SPEAKER_00]: Yeah, elephant, I mean, every tattoo is a temporary tattoo, right?

...56graefchen @bsandro Does not seem like it. It seems to be something like "EventSub". limesNoted
HouseTube User.select("users.*, 'custom' AS some_field").first.some_field
[SPEAKER_00]: HouseTube, I don't know if it's available to you if you tap up a couple times, but can you repaste your message that was supposed to be the simplest possible example before we went down the rabbit hole of... [SPEAKER_00]: Thank you. [SPEAKER_00]: So if I said comment.select comments.star... [SPEAKER_00]: Three as current vote. HouseTube oh, is this database-specific?
First current vote. [SPEAKER_00]: Yeah. [SPEAKER_00]: So this was the limitation I was talking about. [SPEAKER_00]: And to bring the model back up. [SPEAKER_00]: Here's my adder accessor on comment. HouseTube can you use something else, which is not defined as a attr_accessor
[SPEAKER_00]: So like it has a place to put the data. It just doesn't put it in that place.

01:22:04Oh, sure. So instead of current vote, let's say current vote two.

...15Whoa. Whoa, that's a surprise to me. [SPEAKER_00]: What just happened? [SPEAKER_00]: I didn't think that would work. [SPEAKER_00]: I thought I was going to get an error about it not having somewhere to save that value. HouseTube I've been using this so many times haha
[SPEAKER_00]: So it goes and sees, oh, well, you named a field you want, and I don't see a matching attribute, so I'm just going to invent one. [SPEAKER_00]: Wow. [SPEAKER_00]: All right, so wait. [SPEAKER_00]: Let's look for current vote. [SPEAKER_00]: And if I just delete the accessor. [SPEAKER_00]: And then I reload. And then I go back to my query. [SPEAKER_00]: OK, see us first. [SPEAKER_00]: Oh, there it is. [SPEAKER_00]: Okay. Last also has one. I don't know if I voted on that one.

01:23:34That's a little implausible. Which story is this?

...58I'm not on localhost, hang on.

01:24:11[SPEAKER_00]: I have actually upvoted all of the queries or all of the comments on this story. [SPEAKER_00]: So let me un-upvote them, one of them on local, which is apparently broken. The JavaScript does it, but it doesn't actually happen.

...41What a distraction. [SPEAKER_00]: Hey, channelists, if you're on and you want a bug, I don't know. [SPEAKER_00]: Actually, the error is that comment vote, current vote is not defined because I would have to update everything that loads an individual comment to also fill that.

01:25:19[SPEAKER_00]: So what's happening here is

...30HouseTube what if you define it as a `attribute :current_vote`?
[SPEAKER_00]: This code is attempting to run on. [SPEAKER_00]: That's it. [SPEAKER_00]: No, it's line five 11. HouseTube like in ActiveModel instead of a attr_accessor
What if I define it as attribute? All right.

...47Give it a shot.

01:26:06still filled. I did this query run twice.

...24Hmm. Oh, maybe the first. [SPEAKER_00]: Yeah. [SPEAKER_00]: And then I bring this up. Can I reload? Come on, clear this. And if I unvote, the comment disappeared.

...54[SPEAKER_00]: Wait, so there's 30 comments, but only three are visible. [SPEAKER_00]: That join is not a left outer join.

01:27:11Because if it was a left outer join, I would see all the other comments.

...33[SPEAKER_00]: See, it looks like one, but it can't be because I'm only seeing the comments I uploaded. [SPEAKER_00]: Because I'm selecting the wrong thing. [SPEAKER_00]: I should be selecting from commons underscore recursive. [SPEAKER_00]: I'm only selecting the... [SPEAKER_00]: This is because this is a CTE. [SPEAKER_00]: I was selecting from the underlying table.

01:28:17[SPEAKER_00]: no only selected two comments still why did this say from comments oh because i'm it's something about being a cte

...53Epic_Ninja_Elephant I just checked /inbox/all again with webtools open: 12.55s waiting, 1ms receiving.
[SPEAKER_00]: because I'm saying select from comments and then I'm joining against this recursive thing by the ID. [SPEAKER_00]: Ninja elephant, if you could file a bug for that, I'll have to investigate it. [SPEAKER_00]: It's not supposed to be slow like that.

01:29:37bsandro yeah 7.3 seconds for me too, curious
Should be comments.

01:30:38HouseTube i guess you never define a `from` and since you call it on the Comment model it selcts from there
There's the from comments right here.

...50HouseTube but this one is implicit, no?
[SPEAKER_00]: I think what's happening here is the common table expression discussion is all about getting the tree.

01:31:01Which one is implicit?

...10HouseTube the one you marked
You're saying this one?

...22HouseTube the one in L1
[SPEAKER_00]: I'm not sure what you mean by implicit. [SPEAKER_00]: They both name a specific field to join on.

...39[SPEAKER_00]: Can you give a line number for what you're looking at?

...48[SPEAKER_00]: Sorry to make that harder for you. HouseTube wasn't the issue on L1034 that it says "FROM `comments`"
chamlis_ is there something going on with the AS on line 1053 that shadows the comments table?
[SPEAKER_00]: The combination of a little bit of lag on the chat and not having a thing makes it really hard to follow subjects like that one. [SPEAKER_00]: Wasn't the issue on the L34 that it says from comments? So there's something going on with the AS on 1053 that shadows comments.

01:32:50[SPEAKER_00]: could be the shadowing I'm kind of chewing on this well let's here let's grab this and do a simpler version of it right the middle complexity version

01:33:25Copy and paste. [SPEAKER_00]: Let's say left outer joins votes. Let me just join this up. Don't need that part of it.

...54So this did the query I expect, but only got two comments.

01:34:15HouseTube is it because it pass an array to select?
[SPEAKER_00]: Is it happening because I'm selecting the current vote? [SPEAKER_00]: Something about that is forcing it to say [SPEAKER_00]: The field has to be present. [SPEAKER_00]: I mean, this is... No, we're only getting three rows back in the set. [SPEAKER_00]: So this is a SQL issue. [SPEAKER_00]: At this level, it's not an active record issue. [SPEAKER_00]: It's something about [SPEAKER_00]: This left outer join is not being done as a left outer join.

01:35:08Is it the where on votes? So what if I said, took this out of here, chamlis_ good spot
[SPEAKER_00]: and I said on this, I'm not sure this is gonna be valid syntax, but and votes.userId equals 78, 30 rows and set. [SPEAKER_00]: Okay, so let's put this back and we need to change the on for the left outer joins. [SPEAKER_00]: which only hashed symbol and array are allowed. [SPEAKER_00]: So do I say votes on votes.dominant ID equals [SPEAKER_00]: Oh, I see the supervisor has departed because he just brought me his toy. [SPEAKER_00]: So I'm turning off the supervisor cam. [SPEAKER_00]: Hello, sir.

01:37:02[SPEAKER_00]: Can't join vote to association named votes.

...40[SPEAKER_00]: It's not letting me do the left outer join. [SPEAKER_00]: All else fails. [SPEAKER_00]: Let's look at the docs, right?

...58Actually, let's go straight to the doc for left outer join.

01:38:23[SPEAKER_00]: It doesn't actually tell me what it will take, though. I don't know what it's supposed to do with that documentation.

01:39:30HouseTube IIRC, you can just pass a string, not in an array
That's not enough documentation to actually use this method.

...40[SPEAKER_00]: You can pass a string, just not in an array. [SPEAKER_00]: I thought it errored for me on that.

...51HouseTube oh, that was just on `joins`
[SPEAKER_00]: Yeah, only hash symbol and array are allowed.

01:41:01HouseTube joins("LEFT OUTER JOIN ...")
[SPEAKER_00]: That's not how I want to express it, but OK. Well, I did get all the comments.

...19And my local does load correctly.

...49HouseTube not saying it's the most elegant, but it works LUL
[SPEAKER_00]: I mean, the the obnoxious thing about it is. [SPEAKER_00]: It is like this line of code is painful with the select and the left outer join, but the actual experience of using it is elegant. [SPEAKER_00]: I just have to replicate it everywhere we fetch a comment. [SPEAKER_00]: Or. [SPEAKER_00]: Well.

01:42:23[SPEAKER_00]: So this is for presentation, so if I say that. [SPEAKER_00]: Like these others or presentation is going to start taking a user.

...56graefchen Code readability vs. Code usability. limesNoted
No, these are. What am I trying to say? I'm in the self context. So I can say.

01:43:23I don't want to call All. I just want to pass. [SPEAKER_00]: I guess I want to say self. [SPEAKER_00]: And then. [SPEAKER_00]: Here is where I want to say I'll work on the indentation later. [SPEAKER_00]: Don't at me.

01:44:21I think that's what I want to say.

...39Unknown column votes vote in select.

...49HouseTube it might be too early/olate
Turn that off for a second. So find the story. Select votes, vote. Yeah, it just.

01:45:16No, it's because this. Oh, wait, I didn't actually. Pass a user.

...34Unknown class integer.

...45Let's do it the dangerous way. And see where that gets me. That gets me results.

01:46:13HouseTube that looks right
[SPEAKER_00]: Okay. [SPEAKER_00]: So how do I do this that doesn't open just a SQL injection vulnerability?

...25[SPEAKER_00]: Yeah, but I can't pass a user model in here because, I mean, there's no concept that the user model is valid because of the other way Active Record works.

...48Is it, do I need to do this?

...55[SPEAKER_00]: Apparently not.

01:47:04[SPEAKER_00]: see i don't want to interpolate it because user id is untrustable input because of the way active record works by just slapping user params onto things that is one strong params typo away from complete sql injection some of this is

...38HouseTube isn't there a ActiveRecord.sanitize_query
[SPEAKER_00]: Some of my frustration is the ongoing disaster with rails and Ruby community issues. HouseTube or similar to built a subquery
[SPEAKER_00]: Where it is really thrown all of the design issues of rails into stark relief.

01:48:21HouseTube ActiveRecord::Base::sanitize_sql
[SPEAKER_00]: So this is implicitly called on the where methods inputs, but not on join. This is what I want to call yes.

01:49:06HouseTube you would pass this as the argument to joins
yeah yeah you got it that looks very promising because i can see the the join happening in here

...50[SPEAKER_00]: And we got all 30 comments. [SPEAKER_00]: It's just a question of whether they're hydrated or not.

01:50:08[SPEAKER_00]: And two of them are upvoted. [SPEAKER_00]: That's correct. [SPEAKER_00]: That's the thing I wanted. [SPEAKER_00]: And shoving it into the for presentation scope is like that's everywhere we grab a comment.

...31[SPEAKER_00]: OK, so let's if user, and then we'll do this. HouseTube I think there must be a better way to construct this joins
[SPEAKER_00]: Say q else self q.includes. [SPEAKER_00]: Come on, standard RB, make it pretty.

01:51:16[SPEAKER_00]: I'm open to suggestions on better formatting this, but I actually have to add two more joins, right? [SPEAKER_00]: So where were we editing? [SPEAKER_00]: Oh, this thing also has to go into for presentation, which case I should quote these.

01:52:04HouseTube looks like you can't customize the ON in left_outer_joins
[SPEAKER_00]: so the thing with hydration is wanting to get these other fields in there too looks like you can't customize the on and left outer joints ah

01:53:01[SPEAKER_00]: So I'm thinking about comment vote summaries, which would be painful to port into SQL.

...14HouseTube as long as there is a raw SQL way to calculate that it should work
I can't remember why we care about current reply.

...41[SPEAKER_00]: I care because you can't flag a comment you've replied to. [SPEAKER_00]: And vice versa.

...54So that one.

01:54:14That one we can port. [SPEAKER_00]: It's going to look like left out or join comments. [SPEAKER_00]: We'll call this replies on comments dot id equals replies dot comments. [SPEAKER_00]: And replies user ID is the current user. [SPEAKER_00]: Then we also want to select, let's just duplicate that and change this to say replies. [SPEAKER_00]: We only care if it exists. [SPEAKER_00]: Let's just grab its ID. [SPEAKER_00]: Because otherwise it'll be nil. [SPEAKER_00]: That's good enough as current reply. [SPEAKER_00]: And then model comment. [SPEAKER_00]: We have to change current reply to be an accessor or an attribute.

01:55:50HouseTube you might have to put the attribute defintions on two lines
The odds are pretty low that I did that right on the first try, right? [SPEAKER_00]: I might have to put the attribute definitions on two lines. [SPEAKER_00]: Oh, you're right, because attribute just takes one at a time, doesn't it? [SPEAKER_00]: Well, let's ask the Ruby docs. [SPEAKER_00]: Where are you?

01:56:44HouseTube maybe that works too
HouseTube it should be ActiveModel
Attribute has been used a few times. [SPEAKER_00]: is it rails yeah okay so you're right it wants them on multiple lines a name a type a default value okay well let's be more specific here and the default is nil [SPEAKER_00]: And default is nil. [SPEAKER_00]: Wrong number of arguments given three, expected one or two on comment 33. HouseTube `, default: nil`
[SPEAKER_00]: All right, so let's not give a type because clearly it doesn't like that. [SPEAKER_00]: And I don't want to think about that right now.

01:57:52[SPEAKER_00]: Unknown column replies comment ID because it's just ID. [SPEAKER_00]: Or is it? [SPEAKER_00]: No, it's called parent comment ID.

01:58:41[SPEAKER_00]: left outer join comments as replies on comments id replies parent comment id and replies user id is 78 that's good i don't think i left any comments in this one did i no let me leave a comment right now test reply post And if I reload this, hmm.

01:59:32Weird to not get any kind of trace here.

...54HouseTube that's expressive lol
Maybe if I go look at the... I'm going to reload the browser off screen. Okay.

02:00:10[SPEAKER_00]: Inload user votes. [SPEAKER_00]: Load user votes is the hydrating thing. [SPEAKER_00]: I could probably just delete this line of code. [SPEAKER_00]: Stories 419. [SPEAKER_00]: Let's go look at stories 419. How to place.

...49[SPEAKER_00]: It hasn't had. [SPEAKER_00]: or presentation called on it yet. [SPEAKER_00]: So then this thing, which doesn't really need to be here anymore. [SPEAKER_00]: So we replaced that. [SPEAKER_00]: We've replaced that. And not that yet. And that.

02:01:24When was it failing on? 419. All right, so we just commented out 419. No, we didn't.

02:02:26HouseTube does that for_presentation scope still work if you don't pass a user in your rails console?
Why would this be failing?

...36Probably. Let's see.

...47No, we get exactly that failure. Hey, good eye. All right.

02:03:01[SPEAKER_00]: Oh, it's because of the select, which I can move up to be only here. [SPEAKER_00]: So you can do them in any order. Yeah, let's break this out onto lines because that's kind of unreadable. HouseTube btw, sanitize_sql is an alias for sanitize_sql_for_conditions
[SPEAKER_00]: OK, so that's correct. [SPEAKER_00]: So now this should load. [SPEAKER_00]: And if I drop to the end, I see my test reply. [SPEAKER_00]: I do still see the reply link, but I think that's because I'm a moderator. And moderators see it regardless.

...50Oh. Well, that would be a little easier to read.

02:04:11[SPEAKER_00]: I don't actually need this query to run anymore. [SPEAKER_00]: So then the next thing is this vote summaries, and this one's painful. [SPEAKER_00]: Because it does a bunch of string stuff. [SPEAKER_00]: Oh look, some stuff for comment vote summaries.

...58[SPEAKER_00]: Oh. [SPEAKER_00]: Yeah, so it grabs them. [SPEAKER_00]: Oh, it's grabbing a data structure, not a...

02:05:11That's actually not so bad, right?

...28Like if I replaced the where with a left outer join,

...43but it's still, it's on the vote model rather than on the comment model. [SPEAKER_00]: So the vote summaries are, when you look at a comment, if you're the author or moderator, you'll see like, I mean, it says vote summary, but it should be called a flag summary at this point. [SPEAKER_00]: So you'll see like, minus two, troll, minus one, unkind, [SPEAKER_00]: obviously this is a wonderful comment that should not be flagged, but that's just kind of an example. [SPEAKER_00]: So it's really, it's vote, preloading vote records, not preloading something about the comment. [SPEAKER_00]: I mean, it's about the comment, but it's doing it on the vote model because the vote model has the reason field. [SPEAKER_00]: So this could be a like, [SPEAKER_00]: left outer join votes on votes is minus one, and then construct the string, and then just... [SPEAKER_00]: There's actually two ways of printing the string, one with usernames and one without. [SPEAKER_00]: So what that looks like is... Oh, it's in the model.

02:07:14[SPEAKER_00]: So if you are the user, you see like minus one troll. [SPEAKER_00]: If you are the moderator, you see like minus one troll and you see who did it. [SPEAKER_00]: You don't see this on your own comment. [SPEAKER_00]: This is just kind of a footnote that I want to mention that moderators don't actually see who flags their own comments because it's supposed to keep the moderator blood pressure down as opposed to like, oh, well, if Alice keeps flagging me, I don't want to be mad at Alice about that. [SPEAKER_00]: Another mod should take that up of Alice. [SPEAKER_00]: Is Peter actually posting unkind comments or are you just mad at him and trying to make number go down? [SPEAKER_00]: But that regardless, I shouldn't see that. [SPEAKER_00]: So there is always a special case in social software. [SPEAKER_00]: So the user just, the author, I should say, sees the number of flags. [SPEAKER_00]: All right, how do we want to get this data?

02:08:37[SPEAKER_00]: This is such a giant rabbit hole from what I thought I was going to spend the stream on. [SPEAKER_00]: But like, if we can get this, it really cleans up a bunch of code by moving this stuff into the query.

...58I guess what I want is an includes

02:09:08but I want an includes that does this group by. And I don't think I can have that.

...29[SPEAKER_00]: See, I already have the group concat here. [SPEAKER_00]: I'm like one more level of group concat away from having it entirely in SQL.

02:10:15Thank you.

...50Don't want to.

02:11:20[SPEAKER_00]: So if I ran this query.

...49Where's my left outer join?

02:12:03I didn't pass a user.

...39And then I could shove in, can I do another left outer join? Left outer join votes.

...58[SPEAKER_00]: As flag is on, votes comment ID equals comments ID. And votes equals minus one.

02:13:26Group by comments ID. Now with that second level of grouping,

...44That's going to duplicate comments. HouseTube you could do that grouping in another CTE
[SPEAKER_00]: Because if I said group by comments ID flags.reason, I can group concat. [SPEAKER_00]: Yeah, that's just where I was getting, Marco, is that it's got to be another CTE. [SPEAKER_00]: Okay, so let's get a SQL error. [SPEAKER_00]: Let's re-edit that. HouseTube makes it more composable anyway, I guess
[SPEAKER_00]: I don't like using SQL and composable in the same sentence.

02:14:55HouseTube or is that comment_vote_summaries already a pure SQL query?
HouseTube because then you could say Comment.with() and call that there, no?
yeah comment votes summaries is i mean it gets massaged a little by the view helper but that is just a query so if i said here

02:15:59Can I?

02:16:13chamlis_ the last group is in ruby, right?
[SPEAKER_00]: I don't follow your question. [SPEAKER_00]: So the problem is I need to pass the comment IDs into this, and I don't have them yet. It needs to be a join of some kind.

02:17:02HouseTube can't you do the filtering later and let the CTE be on all rows?
chamlis_ I think I'm behind, one sec
Yeah, Chamos, if you're a ways behind, that could do it.

...31HouseTube I think they are referring to L74 in vote.rn
74. Chambliss is sheep, by the way. [SPEAKER_00]: Yes, that group by. [SPEAKER_00]: Oh, yeah. [SPEAKER_00]: If Chambliss, if you were asking about vote line 74, that group by is definitely happening by in Ruby because it's up in that hydrating method that just grabs everything for the story and then creates a data structure about it. HouseTube so yeah, if you removed that, you could use it with `.with()`
[SPEAKER_00]: So yeah, there's one more thing where it's not, to Marco's question, it's not a pure query, but it could be.

02:18:20[SPEAKER_00]: I mean, Marco, I'm still left with wanting to pass comment IDs into this. [SPEAKER_00]: It's got to have a join to the comment table somewhere. [SPEAKER_00]: Otherwise, I'm pulling back every flag in the entire database.

...41[SPEAKER_00]: Actually, every vote in the database because it does say like three up minus two.

...48 marcorothYeah.

02:19:03HouseTube I see
[SPEAKER_00]: But it's almost there. [SPEAKER_00]: It's this property of being almost there and almost composable that's what nerd sniped me.

...42HouseTube I'm not familiar enough with the schema
[SPEAKER_00]: I think that the only thing you're missing is there's this votes table. [SPEAKER_00]: And it's called votes, but it is votes and flags. [SPEAKER_00]: So if the vote is, it's either minus one or plus one. [SPEAKER_00]: And if it's one, you know, that's an upvote. [SPEAKER_00]: If it's minus one, that's a flag. [SPEAKER_00]: If it's a flag, it has a single character reason, which we have a memoized thing or a data structure to transform those back into the human strings. [SPEAKER_00]: But then it's really almost just a join table. [SPEAKER_00]: It just has those two attributes of vote and reason.

02:20:31[SPEAKER_00]: And so the summaries end up looking like plus 21. HouseTube I mean, you could also do two queries
[SPEAKER_00]: minus one troll minus one unkind and if you're a moderator you see alice and then bob carroll

02:21:10HouseTube and then join them later
[SPEAKER_00]: If I do two queries, which is what we're doing now with comment vote summaries, yeah, you say join them later. [SPEAKER_00]: That's what we're trying to get rid of. HouseTube no, I mean in ActiveRecord
[SPEAKER_00]: Then we're back into this of now in the controller, we're looping comments extra times, we're somehow hydrating some data structure so that the view can present this information. [SPEAKER_00]: That's what this refactoring wants to get rid of. HouseTube like with a scope
[SPEAKER_00]: Join them later in Active Record. [SPEAKER_00]: Oh, OK.

...50 pushcxI'm really not following what you're suggesting then, like with the scope. Hmm.

02:22:05[SPEAKER_00]: You know, hey Marco, if you have Discord, we could join you into the call so you could just directly talk. [SPEAKER_00]: I've clearly got your full attention.

...19[SPEAKER_00]: I've used both Signal and Discord for joining people into pair programming.

...34Hmm.

02:23:01chamlis_ I had to pop out for a sec so apologies if this already came up, but do you want a subquery for each of the two possible generated strings on each comment and then you pick which one in ruby
HouseTube I can hop on discord
[SPEAKER_00]: chamlist that could work or honestly just grab this one and in the helper method could just regular expression out the parentheses i don't know let's see where am i i grab a personal browser

...37[SPEAKER_00]: I don't know how to make you a Discord friend, Marco.

...460x29A__ any chance we can get this any time soon? ๐Ÿ˜‡ https://github.com/lobsters/lob…
[SPEAKER_00]: Can I search for... Not without you having to put your username in here, which is very personal.

02:24:10Aha, you found me. That's better. Let's approve that.

...25[SPEAKER_00]: Let me see what you're looking for. [SPEAKER_00]: Person with a hex name. [SPEAKER_00]: Yeah, I would love a PR for this. pushcx https://push.cx/stream
[SPEAKER_00]: it's pretty low down on my personal to-do list but if it's something you want to pick up the there is a i think it's even on the stream archive let's see avatar did i tag it yeah so [SPEAKER_00]: if you look at these old streams where i mention avatars let me share this link i started on it and i ran into an issue where active storage didn't quite scale down to our need where the flow we want is for our web server you know our front end proxy which was nginx a year ago wow almost exactly a year and [SPEAKER_00]: is now catty. [SPEAKER_00]: We wanted them to serve the avatars directly so that Rails is not involved in serving that. [SPEAKER_00]: And active storage is very much assuming that you want Rails to be in the middle of any request for the stored file, which is a performance hit we don't want. [SPEAKER_00]: And so I kind of blocked on that and couldn't see a solution and then wandered off into other stuff for 352 days. [SPEAKER_00]: But 0x29A__ couldnt it be served from github directly instead of storing them locally?
[SPEAKER_00]: The way we could fix that is just use active storage for the upload and then have a job that just copies them to a place on disk that caddy looks in and just leave active support or active storage out of the loop. [SPEAKER_00]: So rather than having one copy of it, we'd have two, which is like, ah, it's a little annoying, but they're tiny. [SPEAKER_00]: It's fine. [SPEAKER_00]: If we served it from GitHub directly, then we would be sending browsing data on all of our hits to Microsoft, so no.

02:26:45[SPEAKER_00]: We do the same thing with our existing Gravitars where we don't serve them from Gravatar, we cache them locally. [SPEAKER_00]: And that's again for privacy there's a little bit of an ethos of hey shouldn't we be able to run a website entirely ourselves without depending on third party services for stuff like avatars. 0x29A__ Local cache with massive TTL? And the request would be proxied through caddy then, not from clients browser
[SPEAKER_00]: And that's a little bit of an ideal but it's not a super hard and fast one, as you can guess by the existence of gravitas. [SPEAKER_00]: So anyways [SPEAKER_00]: yep. [SPEAKER_00]: That's exactly the idea that we want. [SPEAKER_00]: And if you look at how Gravitars work, that's exactly how they work now.

02:27:440x29A__ Ok guess I'll look into learning ruby then
[SPEAKER_00]: I'm getting my earbuds set up to bring Marco into a call.

...58Oh, I was hoping you already knew Rails.

02:28:26[SPEAKER_00]: All right. [SPEAKER_00]: All right, I'm gonna mute my mic a second. [SPEAKER_00]: We're gonna do, I'm gonna try and get Marco joined to this.

02:29:13So I've unmuted myself and Marco. [SPEAKER_00]: Marco, can you say hi? Oh. [SPEAKER_00]: OK. A little bit of a clip at the beginning of your sentence there, but I think we're set. [SPEAKER_01]: Maybe Discord is cutting this off somehow. [SPEAKER_00]: It does try and have a noise floor. [SPEAKER_00]: And so sometimes you miss the first 50 milliseconds of the first word, because it's trying to isolate that, you know, chamlis_ yep!
0x29A__ confirm
[SPEAKER_00]: you're rustling around yeah yeah all right i think we're set now hopefully somebody in chat can confirm that they hear you maybe hex number 29a okay great cool wow look at that i have linux audio working properly so marco you were saying one more join [SPEAKER_00]: what were you thinking here in the comment model or in the vote model? [SPEAKER_01]: Yeah. [SPEAKER_01]: So if you, I guess we have a common table expression. [SPEAKER_01]: If you can have a query upfront, which summarizes these votes, which I think produces this string that you showed on line 73 there, right? [SPEAKER_01]: So I guess if you have a comment table expression that outputs these strings for each, I guess, user ID or each comment ID. [SPEAKER_00]: All right. [SPEAKER_00]: So I guess I would say we want to join. [SPEAKER_00]: And we want to say, I'm going to do the same syntax I have on the left for this. [SPEAKER_00]: And then we want to say what? [SPEAKER_00]: Inner join. [SPEAKER_00]: with recursive, or it's not recursive, is it? [SPEAKER_00]: With both summaries as, yeah, I don't know what the intending is doing. [SPEAKER_00]: And so we wanna say, select, [SPEAKER_00]: What do we need here? [SPEAKER_00]: We need the comment ID, the reason, the count. [SPEAKER_01]: I mean, do you want to reimplement this in pure SQL again? [SPEAKER_01]: I mean, you could just reuse whatever you have on the left side, I would think. [SPEAKER_00]: But maybe it's easier. [SPEAKER_00]: How would I turn that into a comment table expression? [SPEAKER_01]: Yeah, but it could even put this, I think you can even give this as an argument to joins, right? [SPEAKER_00]: Can I? [SPEAKER_00]: That would be great. [SPEAKER_01]: What are you thinking? [SPEAKER_01]: Yeah, I think, like, Rails 7.1, or whatever it was, introduced the new syntax for composing these comment table expressions into, yeah, the with, and I think even the join, like, the from. [SPEAKER_01]: But, yeah, I mean, maybe that's easier for now. [SPEAKER_01]: Just keep it working, whatever we're doing. [SPEAKER_00]: OK, I mean, I haven't super closely read the Rails 7 notes, but we're on 8.0. [SPEAKER_00]: So if there is a nicer feature. [SPEAKER_00]: Yeah, that should be available. [SPEAKER_00]: So are you saying instead of calling .joins here, I should call .width? [SPEAKER_01]: Right, and then it would do it upfront. [SPEAKER_01]: And then in the joins, you can just refer to whatever you were defining in that common table expression. [SPEAKER_01]: Maybe you have to do it at the beginning. [SPEAKER_01]: I'm not sure if the order matters, but. [SPEAKER_00]: Do we want to test in the console, you think, or? [SPEAKER_00]: Maybe that would be easier, I guess. [SPEAKER_00]: It'll be faster. [SPEAKER_00]: All right, so we can do, do you want to start with that as the setup and then say with here? [SPEAKER_00]: I guess I'm behind on the stream. [SPEAKER_00]: That's a, I can actually, let me bring back my view of the Discord window. [SPEAKER_00]: And then I can turn on, not the camera. What's my, come back. [SPEAKER_00]: so if you quit looking at twitch and start looking at just discord you should have a screen share yes cool thanks yeah so that'll be live for you and then yeah yeah all right so you're thinking of calling something here like [SPEAKER_01]: Yeah, I'm not sure if you can do it at that point. [SPEAKER_01]: Maybe you have to do this at the very beginning, where you have comment with at the very start. [SPEAKER_01]: I think that's where it was used. [SPEAKER_02]: But maybe, yeah.

02:34:32[SPEAKER_00]: And then how do we get that to join? [SPEAKER_00]: Because we do need to get it to match. [SPEAKER_00]: So we want to say, like, what? [SPEAKER_00]: Because the vote comment ID has to match the comments ID?

...52[SPEAKER_01]: The comments ID, you're getting out of the query behind it. [SPEAKER_01]: Or I guess that's the problem, huh? [SPEAKER_00]: Right. [SPEAKER_00]: That's why I was reaching for joins.

02:35:05[SPEAKER_02]: Right. [SPEAKER_02]: OK, I see.

...13[SPEAKER_01]: Yeah, let's do the joins. [SPEAKER_01]: That might be easier then. [SPEAKER_01]: OK. [SPEAKER_00]: I'm going to, well, yeah, let's try it here at the console. [SPEAKER_00]: So we'll say, let's get rid of that reload. [SPEAKER_00]: And then we'll say cs is this to a count, because that tells me real fast if we've messed up something important and also should print the query to standard out. [SPEAKER_00]: So let's say joins. 0x29A__ doube . after Comment
[SPEAKER_00]: votes as vote summaries on double dot thank you channels votes.id or no votes.comment id is comments id and then [SPEAKER_00]: No, this really does have to go into being a common table expression because of the group. [SPEAKER_00]: So we'll say. Right, yeah, yeah. Yeah, so we'll say, do I need the inner joined or do I just need the width? [SPEAKER_00]: Up here I see inner joined. So width summaries as. I guess I'm wondering, can you do width inline like that? Does that work? [SPEAKER_00]: I feel like the width only works at the very beginning. [SPEAKER_00]: That's what comment is doing here, right? [SPEAKER_00]: Right. [SPEAKER_00]: Oh, I think when ActiveRecord puts it together, it'll shove it to the beginning. [SPEAKER_00]: I mean, we'll see. [SPEAKER_01]: You might just be able to do it without the width keyword, I guess.

02:37:20You have an error. So what did it turn into? [SPEAKER_01]: Yeah, I think if you just say, like, joins and then, like, without the with, just, like, do, like, a subquery there. [SPEAKER_00]: Like, vote summaries as. [SPEAKER_01]: I think you would put the name after the subquery, right? [SPEAKER_01]: Like, you say something as and then vote summaries. [SPEAKER_01]: Yeah, so...

...54[SPEAKER_00]: right so i've got to have the join and then here i want to say select what like group concat well count one as count group let's just do the first level group concat reason and then it has to be reason as from votes group by comment id comma, the vote, no, the reason. Oh, you have to say joins, I think. Joins doesn't add a joins by itself. Yeah, I don't even have a comma.

02:39:27I think joins just really depends on whatever you give it. Yeah. Yeah. That's all. This type of summaries. [SPEAKER_02]: Yeah.

...59Okay. [SPEAKER_00]: I'm going to call them vote summaries dot comment ID in on. [SPEAKER_02]: I guess that's your join. [SPEAKER_02]: That gives up query, right? [SPEAKER_00]: Oh, yeah, because I didn't select the comment ID. Yeah.

02:40:34chamlis_ vote_summaries not votes_summaries?
Vote underscore summaries. Is there a typo there you're saying, Chamlus? Yeah. [SPEAKER_00]: Votes plural versus votes singular. [SPEAKER_00]: This is one of those that 20 years of Rails, and I still can't remember this. [SPEAKER_00]: So this should be... Not plural. Yeah. OK. That doesn't look too bad. At least you get 31 rows again. So what's actually, if I put the, [SPEAKER_00]: If I create a attribute for the vote, I think it's doing it plural, right? [SPEAKER_00]: Because it has votes. [SPEAKER_01]: No, you're not selecting it yet from the top out level select, I guess. [SPEAKER_01]: Yeah. [SPEAKER_01]: So it doesn't return anything. [SPEAKER_00]: But it actually wants to get flattened again, right? [SPEAKER_00]: Because we're not doing. [SPEAKER_00]: We're not doing the group concat yet. [SPEAKER_00]: Well, right now, we're just joining it. Yeah. Yeah. All right. So if I add that in, group concat usernames as username. [SPEAKER_00]: from votes join users on users id is votes dot user id unknown colon usernames it's singular here all right and then what am i selecting i guess i want to add [SPEAKER_00]: really gotta come on well on we gotta go back to that yeah because if you do a select without everything there it just overwrites say here get rid of this and then down here i can say right so i think i have a [SPEAKER_00]: Because I have to flatten one more level. [SPEAKER_00]: Otherwise, you're going to get multiple copies of each comment.

02:43:31[SPEAKER_02]: I guess call it. [SPEAKER_02]: You're joining it on the comment ID. [SPEAKER_02]: So.

...52[SPEAKER_00]: this because i'm grouping by the reason i'm gonna get one record for each type of flag somebody has by reason so like if you have both troll and unkind as in the example down here on 84 the comment would be duplicated we need to do another group and that's the one i can't quite see through yet I mean, I guess you could nest it one more time. [SPEAKER_01]: Do you have to group by a reason so you can count the number up, right? [SPEAKER_02]: Yeah.

02:44:46[SPEAKER_00]: Wrong number. [SPEAKER_00]: Oh, not 2S. [SPEAKER_00]: 2A. [SPEAKER_00]: How did I still get 31? [SPEAKER_00]: You know, it's totally possible that in this story, none of the comments have flags. [SPEAKER_00]: Yeah. [SPEAKER_00]: Because it was like a very technical post about at proto, and people don't always get. [SPEAKER_00]: So select ID from stories. [SPEAKER_00]: I'm in the Rails console. [SPEAKER_00]: Story. [SPEAKER_00]: Find.

02:45:28[SPEAKER_00]: What's the easiest way to do this? [SPEAKER_01]: I guess you're not using views, right, in SQL? [SPEAKER_00]: No, we actually had a big, long project to get rid of views.

...51[SPEAKER_00]: None of the comments have any flags, so we got to find a different. [SPEAKER_00]: spicier discussion. [SPEAKER_00]: What's a story that has flags? [SPEAKER_01]: I mean, you cannot say comment where flag equals or negative 1 or something. [SPEAKER_01]: Yeah. [SPEAKER_00]: Where flags where not flags is 0. [SPEAKER_00]: So we have this flags is just a memoized count. [SPEAKER_00]: It's persisted in the database. [SPEAKER_00]: Dot last, dot story ID. [SPEAKER_00]: All right, so now we have one. So if I said, these tend to clump up. [SPEAKER_00]: So I'm curious to see if we're going to see. [SPEAKER_00]: OK, just one comment has any flags on this one, which is enough. [SPEAKER_00]: Right. [SPEAKER_00]: All right, so let's. [SPEAKER_00]: Find that story. [SPEAKER_01]: I guess the count would be interesting before and then after we did that change, right? [SPEAKER_01]: To see if it goes up by one. [SPEAKER_00]: Yeah. [SPEAKER_00]: Or I could just, what is it?

02:47:17[SPEAKER_00]: Oh, it's, I think it's Memoized. [SPEAKER_00]: I'm missing a comma. [SPEAKER_00]: And then this count. [SPEAKER_00]: All right, so it has 44. [SPEAKER_00]: And there's some kind of typo in here if we're throwing a syntax error. [SPEAKER_01]: Yeah. [SPEAKER_01]: 72, like this comma after the end of select. [SPEAKER_00]: What were we saying about SQL composing? [SPEAKER_00]: Ruby doesn't. [SPEAKER_00]: Sorry. [SPEAKER_00]: There we go. [SPEAKER_00]: So let's . Okay, so that doesn't throw an error. [SPEAKER_00]: And then go back into here. [SPEAKER_00]: That does throw an error. [SPEAKER_00]: Unknown columns stir, because I said, well, what if we took the vote summaries as a single string and kind of mashed it down? [SPEAKER_00]: So that wants another level of group concat, right? [SPEAKER_01]: Or could you group it on the outermost select? [SPEAKER_00]: I'm so reluctant to do that, because the return type changes in Rails, where instead of getting back an array, you get back a hash. [SPEAKER_00]: And that's going to ripple through the entire code base. [SPEAKER_01]: Is that just nested here, then, I guess? [SPEAKER_00]: Yeah, so this is the slightly hairy part where I'm getting into clever SQL of.

02:49:00[SPEAKER_01]: But isn't there a way to extract this now, like this single subquery into one variable or something that we can do this independently of this whole scope?

...20I'm not sure what you're thinking of. [SPEAKER_01]: I mean, do we have anything that's dependent in that subquery on the auto query? [SPEAKER_01]: Or do we have to keep this here? I guess we have common. Because you are just selecting from votes, which is. [SPEAKER_02]: The table, right? [SPEAKER_02]: Not some other. [SPEAKER_00]: Yeah. [SPEAKER_00]: Votes is just joined directly to comments. [SPEAKER_01]: Right. [SPEAKER_01]: So I guess you could just, like, the whole subquery could extract this, or even keep this in pure Ruby, like in the active record. [SPEAKER_01]: And then. [SPEAKER_00]: Active record doesn't have the support for that group concat, which is awesome. [SPEAKER_02]: But that's just in the select, right?

02:50:29[SPEAKER_00]: If I said grab this, we selected concat.

...41[SPEAKER_00]: What do we want to concatenate? [SPEAKER_00]: We want to concatenate the count.

02:51:07[SPEAKER_00]: Do you have to? [SPEAKER_00]: The hassle here is that we don't treat these exactly the same. [SPEAKER_00]: We only print the usernames for the flags. [SPEAKER_00]: So like this example on 77 is we say plus 21. [SPEAKER_00]: We don't say plus 21 Dave Edna, right? [SPEAKER_00]: Like this part does not happen. [SPEAKER_00]: And since we're treating the two sides differently, [SPEAKER_00]: Like this, I can see how to group concat that. [SPEAKER_00]: We don't actually use this plus. [SPEAKER_00]: Actually, we don't need them, do we? [SPEAKER_00]: We could re-derive it because the comment memoizes both its score and its number of flags. [SPEAKER_00]: And the total number of upvotes is score plus flags. [SPEAKER_00]: So hold on, if we ignored that, [SPEAKER_00]: And we filtered these vote summaries to say where no and vote summaries dot vote is minus 1. [SPEAKER_00]: Now it's just flags. And then I guess for the other one, you don't have to group. Yeah. I can't think with everything on one line.

02:53:25The group is. Parentheses. Yeah, so let's.

...45[SPEAKER_00]: OK. Now it actually makes a little more sense, and then we're going to do is from. [SPEAKER_00]: The common level. We're going to join all of this as, what do we call this, by reason. And then you can select count, comma, group, concat.

02:54:30[SPEAKER_02]: Or do you need that second select con cut on that same line on 970? [SPEAKER_00]: Yeah, because we're doing two levels. [SPEAKER_00]: So it's sort of what I'm trying to do is, so I'm throwing away the plus 21. [SPEAKER_00]: And I'm trying to say there's one level where we generate like minus 1 troll Alice. [SPEAKER_00]: And then there's a second level. [SPEAKER_00]: minus one, I guess this would be two, minus two unkind Bob Carroll, and then we're group concatting those two levels together. [SPEAKER_00]: So this inner one becomes concat the number, which doesn't need this, we're just making everything stringly typed, space, [SPEAKER_00]: We can't get to the reason, because the reason is the single letter. [SPEAKER_00]: Let's just take it as a single letter, and I'll write that in a minute. [SPEAKER_00]: All of that as the, what would we call this? We would call this the, I don't know. [SPEAKER_02]: Reason summary? Yeah. And then group concat reason summary with the separator from this whole thing.

02:56:43[SPEAKER_01]: You need that comma after recent summary separator. [SPEAKER_01]: Online 70. [SPEAKER_00]: Yeah. [SPEAKER_00]: Yeah. [SPEAKER_00]: This doesn't need a count. [SPEAKER_00]: And then this actually needs the parentheses around the usernames. [SPEAKER_00]: And then there's the close parentheses around the usernames.

02:57:20There's no way I nested that correctly, but let's try it. It's not good. OK, it's still selected. [SPEAKER_00]: Yeah. [SPEAKER_00]: So this becomes. [SPEAKER_02]: It's a reason. [SPEAKER_02]: Oh, we didn't give it a name yet. [SPEAKER_02]: Yeah. [SPEAKER_00]: So we group concat that as. I guess that's your ward zone right now.

02:58:03Or that should be right.

...22[SPEAKER_01]: Why is that select doing one line 72? [SPEAKER_01]: Bad arguments. [SPEAKER_00]: Doing something? [SPEAKER_00]: 72? [SPEAKER_00]: Oh, it was a false start. [SPEAKER_01]: OK. And I guess MariaDB is fine with double quotes for strings? [SPEAKER_01]: Yep. OK.

...54This should match that.

02:59:27I'm missing code or something. [SPEAKER_00]: What's the second parenthesis? [SPEAKER_01]: Oh, I guess your here doc might be. [SPEAKER_00]: Ah, yeah. [SPEAKER_00]: Yeah. [SPEAKER_00]: OK, better. [SPEAKER_00]: You have an error in your SQL syntax next to onVoteSummaries.commentId. [SPEAKER_00]: Yeah. [SPEAKER_02]: This one then becomes might have to be one layer outside of that? [SPEAKER_02]: No. [SPEAKER_00]: So we're going to group concat that from this has to have the comment ID on it, doesn't it, if it's going to join? [SPEAKER_00]: Whoa, that syntax thing, standard RV. [SPEAKER_00]: Occasionally Vim is like, whoa, the outside process that I called to change the file, change the file.

03:01:13This goes out here.

...26[SPEAKER_00]: Have an error. [SPEAKER_00]: Next to use parentheses as vote summaries. [SPEAKER_02]: I don't want to need a name, too. [SPEAKER_02]: Yeah, underline.

...57[SPEAKER_00]: I think you have to name anybody. [SPEAKER_01]: Oh, you don't have to name it, but I guess you have to select it again, no? [SPEAKER_01]: Otherwise, it doesn't .. This one, this filter goes inside. Yeah, this has to be up here on. [SPEAKER_00]: And comment ID is this, and reasonSummaries.vote, because that's where I'm filtering. Next to onReasonSummaries as reasonSummaries. Am I missing a join keyword? [SPEAKER_01]: Oh, it's a select from, and then you do ask, and then it's the on, so that the on doesn't go there. [SPEAKER_01]: Recursors right now. [SPEAKER_01]: That's from the select. [SPEAKER_00]: Right, so wait. [SPEAKER_00]: So this section, I'm going to select this stuff. That's fine, yeah.

03:03:25I guess the name doesn't even make sense there. That should probably come after the... [SPEAKER_01]: I guess it has to come after the parentheses, like on 78. [SPEAKER_01]: And then the on comes after that. [SPEAKER_01]: And then the as vote summary doesn't even go there. [SPEAKER_01]: I think you can name it like that. [SPEAKER_02]: Oh, that's from the join. [SPEAKER_02]: Wait, that's from the join. [SPEAKER_00]: And they call it structured query language. [SPEAKER_00]: I don't see a lot of structure. [SPEAKER_00]: I see a lot of text. [SPEAKER_00]: So we want to grab the common ID, select [SPEAKER_01]: I mean, are you planning on keeping this in line, or do you want to extract this at some point? [SPEAKER_00]: I don't think it'll be possible to extract. [SPEAKER_01]: Oh, but I mean, the inner query itself is not dependent on anything from the outer query, right? [SPEAKER_01]: From line 70 to 76, that's independent, no? It could be. [SPEAKER_01]: I mean, I'm just thinking, if you just run this independently, just to see where we are. [SPEAKER_00]: Does this need to be joining against the comment ID? [SPEAKER_00]: Because it's selecting comments.

03:05:24[SPEAKER_02]: I guess that will make it so you have to keep it in line, I guess, yeah.

...29 marcorothYeah. [SPEAKER_00]: And we can move that filter in here, too, where, well, let's see, cool.

...40 pushcxNegative 1. And then written summary is comment ID equals comment ID.

03:06:03If this outer layer is both summaries, that's what we're joining against. [SPEAKER_01]: Where are we referring recent summaries from then? [SPEAKER_00]: No comments ID and on.

...30It's typo. It's comments.id. [SPEAKER_00]: Well, I think that worked, and it just joined every comment against its vote, which is, I don't know, 200,000 comments and 4 million votes, something in that neighborhood.

03:07:00[SPEAKER_00]: No, 600,000 comments and yeah, 4 million votes. [SPEAKER_00]: So there's something that's uncorrelated in there.

...26[SPEAKER_00]: Vote summaries, comment ID.

...37Let's try maybe an explain. [SPEAKER_00]: The explain for this is going to be ridiculous.

03:08:01[SPEAKER_00]: I can't fit it in 1080p because it's

...17[SPEAKER_00]: okay great now it's on one line and it's so small i can't actually read it i'm gonna get my bifocals out so temporary yeah file sort there's where performance goes away rows two million

...56[SPEAKER_00]: See, the dangerous thing about this is I feel like we're almost there because it's like there's one bit of correlation that needs to get added so that it's searching comments and then joining to votes. [SPEAKER_00]: But I'm not instantly seeing it as reason summary. [SPEAKER_00]: Oh, it's this. [SPEAKER_01]: This is adding a join. [SPEAKER_01]: Should it just be a where, like on the where instead, I guess? [SPEAKER_02]: Yeah. [SPEAKER_01]: Then you should not have to join all of them. [SPEAKER_00]: Yeah, that's the error. [SPEAKER_00]: I don't actually need that join. [SPEAKER_00]: All right, let's see how that works. [SPEAKER_01]: But you want it on the where, no? [SPEAKER_01]: Just do it for the comments that you are looking for, like on the outer. [SPEAKER_00]: Right, but I want to correlate it to the outermost one, so like this part of the query is not cascading in. -oh. Because we're clearly joining all of the votes. [SPEAKER_00]: This could be an issue with a correlated subquery where it's running the whole thing once per row. [SPEAKER_00]: No, it's got to be doing the inner for the whole database if it's going to stall like that.

03:10:22[SPEAKER_02]: Is it maybe because you have to put it on the reason, on the votes, like the on? I guess you don't have access to that out there.

...37[SPEAKER_02]: You don't have the comments there, right, do you? [SPEAKER_00]: Yeah, I do, because comments are the outermost layer, so it's sort of always available. It does not run first, like from the inside out.

03:11:02You still there, Mark? [SPEAKER_00]: Yeah. [SPEAKER_00]: OK. [SPEAKER_00]: I just heard a funny noise the way you cut off. [SPEAKER_00]: Unknown comments.id. [SPEAKER_02]: I guess you don't have access there. [SPEAKER_02]: I think it's from the outside in. [SPEAKER_01]: And that's why you aren't able to reference comments there. Yeah.

...58[SPEAKER_00]: So one thing I could do here just to see the query finish is I could drop my database and we have a seed test that seeds the database with a couple hundred stories and comments, and then it would actually finish. [SPEAKER_02]: Yeah. [SPEAKER_00]: Within an hour. [SPEAKER_00]: but I'm not sure what I would learn from that besides my query is running in the wrong order. [SPEAKER_01]: The question is more how can we teach the query planner to optimize that out of there so it doesn't want to join all of the votes of all of the comments. [SPEAKER_00]: I think what we've done is convince me that maybe it's not so bad that we loop the comments an extra time up in the controller as opposed to try and shove all this work down into the database because [SPEAKER_00]: yeah this is like this is not maintainable aside from like i have to shove a case statement in here for the reason this is not a i can almost project out what i want but sequel is so not great with i have a bunch of rows that i want to smash into one that i'm really fighting for this [SPEAKER_01]: The only thing I could see is if you put it in a common tape expression, that it doesn't immediately try to execute the actual join. [SPEAKER_01]: And then only when you're trying to use it, then it can better plan it, maybe. [SPEAKER_01]: Right. [SPEAKER_00]: But since I have this within story threads. [SPEAKER_01]: So you would have to nest it. I guess it's even more. Yeah.

03:14:06[SPEAKER_00]: So this one, because I have to fall down into raw SQL, I'm aware that active record seven has better support for these recursive common table expression or just common table expressions in general. [SPEAKER_00]: But because I fell down to SQL for this, I don't have a nice composable thing. [SPEAKER_00]: And so. [SPEAKER_02]: I would have to refactor this, which would make it shorter, but... Because you're doing this in the scope, I see. Yeah. [SPEAKER_00]: Of course, if it's doing all this, I could probably throw away confidence order path. [SPEAKER_00]: Confidence order path is a zany performance hack. [SPEAKER_02]: Yeah, I'm not sure how to continue from here. Unless you can put it right next to [SPEAKER_00]: the other GTE you already have, but then you might be- But then everything would have to go through story threads and it's not appropriate because, so what story threads is doing is it's trying to get the database to produce the comments as a tree. [SPEAKER_00]: And we do that most of the time. [SPEAKER_00]: We do that when we're showing a story and all of the discussion [SPEAKER_00]: like here. [SPEAKER_00]: But if you search for comments, you see a flat list or if you are looking at the newest comments, you see a flat list. [SPEAKER_00]: And so we don't call story threads. [SPEAKER_00]: It has been kind of a hassle to get queries composable enough that I could remove a whole lot of special casing. [SPEAKER_00]: But this one is still hanging out here. [SPEAKER_00]: So [SPEAKER_01]: So yeah, I guess if you don't use the active record methods, you cannot really compose them nicely. [SPEAKER_01]: So you were saying earlier, I guess there's not really a way for you to be able to yield stats. [SPEAKER_00]: Well, and even if I, even if I do, I'm left with, we want to smash, we want to join against the votes and then like do a group concat at the level of a reason and then a group concat at the level of a comment. [SPEAKER_00]: Yeah. Right. Yeah. Yeah. [SPEAKER_00]: So it's, I mean, you know, comment is our God object. [SPEAKER_00]: So it's not surprising that we have a special case for a tree so that we can have a group so that we can have a group. [SPEAKER_00]: That's the kind of thing you see in God objects, but.

03:17:19 marcorothHmm.

...28[SPEAKER_00]: yeah so if so we gone we we went way down the rabbit hole and if we pop the stack and go back to this pull request if the hydrator class instead of becomes a delegate for the collection of comments when you say like hydrator.each [SPEAKER_00]: this thing says each and it hydrates the comments as it goes, it doesn't really matter that this thing is gonna do a couple standalone queries. [SPEAKER_01]: I mean, yeah, I guess it doesn't. [SPEAKER_01]: It just feels wrong. [SPEAKER_00]: Yeah, well, I mean, it is, it's just the pain of trees in SQL plus flattening at two different levels. [SPEAKER_00]: and trying to express all of this through the abstraction of active record yeah i don't want to complain too much about active record but it really is a little bit of a kludge when you're like i want this table except also a comment that's this other or also a column that's this other thing and [SPEAKER_00]: Two of these were OK. [SPEAKER_00]: But this one, where the other thing that we want to add on is a group by of a group by is we just hit the limits of expressiveness. [SPEAKER_01]: Yeah. [SPEAKER_01]: The only other thing I can think about is not doing the concats in SQL, but giving a returning [SPEAKER_01]: pieces that we need to be able to piece it together in Ruby. [SPEAKER_01]: So you do the necessary joins of whatever you need. [SPEAKER_00]: That's what this hydrator is doing. [SPEAKER_02]: Yeah. [SPEAKER_01]: I mean, right. [SPEAKER_01]: But then you could still just call it on comments as a method. [SPEAKER_01]: And then you have the comments class itself that knows how to piece the whatever the concat is doing right now in the SQL query, you could do in [SPEAKER_01]: Yeah, somewhere. [SPEAKER_01]: Maybe in the hydrator. [SPEAKER_01]: But then you can get all the pieces that you need to be able to put it together from the SQL query. [SPEAKER_01]: Right. [SPEAKER_01]: And then you can just piece together there. [SPEAKER_00]: And then you don't have to... And then ideally, the hydrator doesn't make any extra loops over the comment, because if it's a delegator, it's just getting called once by the view. [SPEAKER_00]: It's more like a presenter at that point than like a... Yeah, I'm using terms like presenter and delegator pretty loosely there. [SPEAKER_00]: I don't have a strong opinion on the distinction between the two. [SPEAKER_00]: Speaking of views, though, because we've kind of beat this to death, I did actually... [SPEAKER_00]: make a branch and install reaction view and click around the site a little bit with it and it caught oh nice yeah yeah it caught two bugs which ones were they there were there was an extra closing tag and then this one [SPEAKER_00]: There is a thing that we do a couple of times in the code base. [SPEAKER_00]: Let's grab this. [SPEAKER_01]: That must be recent, though, right? [SPEAKER_00]: Because I just fixed all the- Yeah, I did the yesterday or the day before. [SPEAKER_01]: No, I mean the closing tag that was introduced there, the missing one or the extra one. [SPEAKER_00]: The extra one, this is on a mod-only view, so maybe you didn't see that. [SPEAKER_00]: It's also totally possible that there isn't an active code path testing it because the mod stuff is very lightly tested. [SPEAKER_01]: No, that's what the analyzer is doing. [SPEAKER_01]: It's pretty much doing it statically just for all the files that are ending in HTML, ERB. [SPEAKER_01]: So it should have caught that if it was there a few days ago. [SPEAKER_01]: But maybe it wasn't used since. [SPEAKER_00]: No, this has been here for... [SPEAKER_00]: Okay. [SPEAKER_00]: The activities table has been here for maybe two or three months. [SPEAKER_00]: think, at least weeks. [SPEAKER_00]: But the other one I thought was actually interesting. [SPEAKER_00]: So I decided that I would just delete the color because it was redundant. [SPEAKER_00]: And I had changed some help text around. [SPEAKER_00]: So I thought something was obvious enough. [SPEAKER_00]: But where's my little white space toggle? [SPEAKER_00]: Because I changed an indent, so everything changed. [SPEAKER_00]: So this one, we had a span, and we were injecting a attribute. [SPEAKER_00]: And Herb said, hey, don't do that. [SPEAKER_01]: Oh, this was just a warning. [SPEAKER_00]: Yeah. [SPEAKER_00]: Yeah. [SPEAKER_00]: Herb said, don't do that. [SPEAKER_00]: Replace it with, I don't know what you named this guy. [SPEAKER_00]: The non-equals version. [SPEAKER_00]: Yeah, the non-equals version of this. [SPEAKER_00]: And I was like, well, but if I do that, I have to replicate this inner thing, and then I have to make a helper or a partial for this thing, and that's all painful. [SPEAKER_01]: No, what you would do is just say, like, if shadowing user is banned, and then you close it, and then just put the style tag as raw HTML. [SPEAKER_00]: Oh, so I put the open span in. [SPEAKER_00]: Oh, okay, yeah, I was thinking of it structurally, of, oh, I don't want to move all of this [SPEAKER_00]: Let me select the quick thing. [SPEAKER_00]: I don't want to move all of this into an if. HouseTube <% if is_banned? %> style="color: red" <% end %>
[SPEAKER_00]: But if I had just put the span into an if, yeah, that would have been short enough. [SPEAKER_01]: So you could do like this here.

03:23:37 pushcxI'll just type it out in chat. Like this. [SPEAKER_01]: Oh. [SPEAKER_01]: That's like an alternative, right? [SPEAKER_01]: So you can just put the style as a raw text, and then I have to do the raw in Ruby. [SPEAKER_00]: Oh, I see. [SPEAKER_00]: I also didn't think of that. [SPEAKER_00]: And so then you would surround. pushcx <span <% if is_banned? %> style="color: red" <% end %> >
[SPEAKER_00]: So if I could grab this. [SPEAKER_00]: So then you would say like that, where that just happens in the middle of the span tag. [SPEAKER_00]: Oh, I didn't see that refactor. [SPEAKER_01]: Because then you are not outputting anything from Ruby, like from ERB. [SPEAKER_01]: all it does from ERB is just the conditional and the stuff is static. [SPEAKER_01]: And at that point, you're not introducing any vulnerability because you're not outputting from ERB. [SPEAKER_00]: Yeah. [SPEAKER_00]: We had talked about one of the things that caught my eye about PaperCraft and ViewComponent was because they're builder style, they flip it, they know what they need to escape. [SPEAKER_00]: in things like this and so you know you don't have fewer calls to raw and then this style of what you pasted in the chat where i mean i'm doing it here where inside of a tag i'm jumping in and then i'm jumping back out of the tag i can see how herb can be smarter about it but at that point [SPEAKER_00]: I guess what I'm saying is I also want to stop thinking about my HTML as strings because I don't know, it's such a mixing of levels of abstraction and, you know, obviously I don't think it's a complete scene because I did it here and I've, I've done it elsewhere in the code base, but it just feels like I'm not being expressive of. [SPEAKER_00]: I don't want to think about string concatenation. [SPEAKER_00]: I want to think about HTML tags. [SPEAKER_00]: Right. [SPEAKER_00]: And the builder style, at least, you know, I'm aware I'm taking like a function call overhead for every span, but at least I'm... [SPEAKER_01]: I mean, it's just... Yeah, I don't know. [SPEAKER_01]: I think at that point, it's just a matter of like preference and whatever you kind of feel like makes more sense to express your markup as. [SPEAKER_00]: Yeah. [SPEAKER_00]: And so I, I personally just feel like, sorry, go ahead. [SPEAKER_00]: I, I was just gonna say, I keep getting impressed that herb can cut up and down these levels of abstraction of, is it a string? [SPEAKER_00]: Are you starting an HTML tag? [SPEAKER_00]: Especially when, you know, I'm splitting up the brace and injecting various kinds of ERB inside. [SPEAKER_01]: Yeah. [SPEAKER_00]: It, it's a hell of a trick that you can do that and maintain the stack of where are you in defining a tag? [SPEAKER_00]: I'm really impressed by that. [SPEAKER_01]: And I guess that's kind of what has been missing. [SPEAKER_01]: So you guess you like, yeah, it is now possible to can write an engine that knows exactly at what point you are supposed to escape and where you aren't. [SPEAKER_01]: Yeah. [SPEAKER_01]: And with that, it is able to kind of replicate whatever these other markup engines are doing. [SPEAKER_01]: So it could probably escape it when you are depending on the context where you are interpolating it or and it's already doing that. [SPEAKER_01]: Yeah. pushcx https://github.com/marcoroth/re…
[SPEAKER_01]: But I guess, yeah, that's like just the implementation detail. [SPEAKER_01]: But then if you feel like HTML is better expressed as Ruby, because you don't want to kind of switch between HTML and Ruby syntax, then maybe that's the better way to write your views. [SPEAKER_01]: I think that's more maintainable. [SPEAKER_00]: It's almost not about syntax. [SPEAKER_00]: It's about the level of abstraction. [SPEAKER_00]: of yeah but then okay you know like in in a if i'm messing around with ruby strings like we talked about that the where'd it go my sample like this thing if i got this back from the database even if we had gotten this query to work on the first try and then i said oh well to produce this second string i'm gonna have a check that says if the user is a moderator [SPEAKER_00]: a G sub with this regular expression to throw away space, parenthesis, anything so that regular users don't see the usernames. [SPEAKER_00]: And I'm, that's the kind of jarring jump in the level of abstraction between I am expressing authorization and then I'm immediately leaping down into a regular expression that's smashing a string around. [SPEAKER_00]: And that's, [SPEAKER_00]: You know, I do those kinds of things, but every time I do them, I feel a little bit bad about it. [SPEAKER_00]: And so your, the, the string I had is like, oh, I have this domain concept of is a user band. [SPEAKER_00]: And then I'm jumping down into, I know this detail about HTML styling. [SPEAKER_00]: which like, you know, yeah, I could fix this with a class or something. [SPEAKER_00]: And then herb is so I guess what I'm getting at, the reason I wanted to talk about it is I am so impressed that herb can point out that this is bad. [SPEAKER_00]: And then it really highlights to me that it's also bad in this concept of jumping up and down and layers of abstraction. [SPEAKER_00]: Yeah. [SPEAKER_00]: So I'm saying it's so good, it's reminding me that my code is bad. [SPEAKER_01]: I guess that's kind of part of the reason why you want to have these tools, or why I wanted to build these tools, because for Ruby code, you have all these different other tools to kind of tell you why something is good, why something is bad. [SPEAKER_01]: Sometimes it's a little bit too much or too aggressive. [SPEAKER_01]: But yeah, for views or best practices or even how to make it accessible, [SPEAKER_01]: It's pretty much a blind spot in your application. [SPEAKER_01]: You don't see any of that. [SPEAKER_01]: And just bringing this to people's attention and having a tool that tells you, by the way, don't do it this way, I think is a good thing to have. [SPEAKER_00]: Yeah. [SPEAKER_00]: Boy, I wish we had Herb 20 years ago with Rails. [SPEAKER_00]: It's funny that it took so long. [SPEAKER_01]: I guess it was enabled by Prism and the way it is now independent to kind of be able to parse Ruby. [SPEAKER_01]: And that's enabled Herb to even exist. [SPEAKER_01]: If Prism wasn't around or that isolated and accessible, then Herb would be a lot harder to implement because you would have to figure out how to parse Ruby unreliably. [SPEAKER_01]: That's kind of the tricky piece. [SPEAKER_00]: Yeah, and I've seen various projects attempt that over the years. [SPEAKER_00]: And there's that alternate Ruby implementation that's Ruby in Ruby, and I'm forgetting its name because it's been a few years. [SPEAKER_00]: And then there's also the JRuby folks who are always talking about how parsing Ruby is. [SPEAKER_00]: Yeah, they talk about how JRuby's biggest problem is often parsing new Ruby syntax. [SPEAKER_02]: Right. Yeah. [SPEAKER_01]: I mean, it's fun. [SPEAKER_01]: It's a super interesting problem space. [SPEAKER_01]: And a bunch of people have worked on it, but nobody really solved it, I feel like. [SPEAKER_01]: Yeah. [SPEAKER_01]: And this is now getting close to it. [SPEAKER_01]: I'm not saying it's there or perfect yet, but it's getting close to solving that problem space. [SPEAKER_00]: Yeah, well. [SPEAKER_00]: I'm glad that I could contribute you a useful source of bugs and weird mistakes to use as test cases for Urb, because you know. [SPEAKER_01]: Yeah, and it found a few of them. [SPEAKER_01]: It still has some that aren't fixed yet that it still kind of jokes on. [SPEAKER_00]: Oh, yeah. [SPEAKER_00]: When I loaded a single story view, it threw up an error about [SPEAKER_00]: incorrectly nested tags and that goes through my my heinous inline partial thing and i was like oh i'm not even going to attempt to debug that that code is so painful because of what i've done for performance on top that i'm sure herb is correct because i think we even have an issue that under certain rare circumstances of if you nest the exact right levels of [SPEAKER_00]: replies there's like an extra ul tag or an or a missing ul tag i honestly don't know which it is but because we we are effectively doing loop unrolling with heinous inline partial yeah trying to find that is just so awful that i haven't i saw it and i was like no let me go check if the markup's correct on the about page [SPEAKER_01]: Yeah, that's the other thing, like nesting tags. [SPEAKER_01]: Like having a div in a p tag is technically not valid HTML. [SPEAKER_01]: Yep. [SPEAKER_01]: But browsers are fine with it most of the time. [SPEAKER_01]: Yeah. [SPEAKER_01]: Or having a div inside of a span. [SPEAKER_01]: Yeah. [SPEAKER_01]: Yeah, that kind of stuff. [SPEAKER_01]: I mean, it is valid, again, if you used to write CSS and tell it to be a block again. [SPEAKER_01]: But that's like... [SPEAKER_01]: Too much to ask for, I guess. [SPEAKER_00]: Speaking of mixing layers of abstraction, the idea that your CSS can fix your HTML nesting is a little funny. [SPEAKER_01]: I'm not even sure if it's then still strictly valid HTML. [SPEAKER_01]: I guess, yeah, I'm not even sure if that's... [SPEAKER_01]: I guess, yeah, syntactically it's correct, but semantically it's not. [SPEAKER_01]: Right. [SPEAKER_00]: All right. [SPEAKER_00]: Well, I've got to roll up the stream here and head out because I have some social plans. [SPEAKER_00]: But I appreciate you jumping on and banging on this wild query with me for a while. [SPEAKER_00]: This has been fun. [SPEAKER_00]: And to chat about ReactionView for a minute. [SPEAKER_00]: So I put the ReactionView link in chat for folks because it's such a neat project. [SPEAKER_00]: I hope folks check it out. [SPEAKER_00]: Awesome. [SPEAKER_00]: Thank you so much. [SPEAKER_00]: Well, I hope to see you around. [SPEAKER_00]: My next stream is Thursday morning as usual. chamlis_ thanks for the stream!
[SPEAKER_00]: But yeah, either way, thanks for dropping in and for everybody watching. [SPEAKER_00]: Have a good one. [SPEAKER_00]: Take care. zemlanin bye
[SPEAKER_00]: Bye-bye.