I want to yassify the StoriesController
Streamed
- Filed issue about StoriesController complexity - controller has grown too large, needs breaking up into resourceful routes and separate controllers for different story actions
- Reviewed PRs:
- Avatar uploads: got Active Storage basically working; dealing with metadata stripping, file naming, and variant generation.
- Added some copy to usernames/invites to help trans users avoid footgunning
- Documented IRC vs Discord discussion in discord-vs-irc-notes
- Requested books on managing open source projects, got rec for How to Open Source by Richard Schneeman
scratch
topics:
x Railsification of StoriesController
yay PRs
x second pass at form errors disappearing https://github.com/lobsters/lobsters/pull/1343
x www10 bug https://github.com/lobsters/lobsters/pull/1350
x active_record_doctor https://github.com/lobsters/lobsters/pull/1351
x merge! individual story disowning https://github.com/lobsters/lobsters/pull/1345
x privacy footgun prevention
x IRC is eternal, unfortunately https://push.cx/discord-vs-irc-notes
avatar uploading https://github.com/lobsters/lobsters/issues/547
Single Layer of Cleverness
a little bit unknown, but this early DHH opinion was foundational for rails
means we miss out on a lot of correctness and db features
https://dhh.dk/arc/2005_09.html#:~:text=Choose%20a%20single%20layer%20of%20cleverness
(though it's right for the wrong reasons about stored procedures; they're code
that's not really managed like other code, so versioning/testing/deploying is
hard enough to make them generally a bad idea)
https://github.com/testdouble/good-migrations
https://github.com/ankane/strong_migrations
on 'claiming' issues, I'm looking for better practices/tools
> espartapalma
: I was AFK, but here's a book about managing Open Source communities/projects
which is modern than Karl Fogel one.. How to Open Source by Richard Schneeman
(@Schneems) https://howtoopensource.dev/ for those who doesn't know it, Richard
is the maintainer of CodeTriage a very popular open source software (written in
ruby too) https://www.codetriage.com/
preload: User.first.avatars.with_all_variant_records
avatar todo
x photos: enforce max dimensions
x how does rails handle resizing non-square images to square? we resize_to_fill
x photos: strip exif metadata from jpgs (but not orientation)
x avatar: don't leak filename of original upload
variants: replace filename with: username_variantname.ext
test: what happens if you upload a non-image?
manual test: can I DOS by uploading a huge image?
replace existing avatar service with ours (avatar_img, rm avatars#expire)
migration to fetch avatars (ignore placeholders) for all users
generate placeholders for users without uploads
trigger rails generating various file sizes
nginx config: download avatars
rename user avatar class
is there a code way to prohibit using the original image?
post-stream:
file issue to make _comment.html.erb <a> tags work without js - all href="#"
active storage: file bug about prosopite; deleting variants is a N+1 query
vip: chamlis_
title:
I want to yassify the StoriesController
Transcripts are generated with whisperx, so they mistranscribe basically every username and technical term. They're OK but not great, advice appreciated.
Recording
03:47looking ahead at prs please say hi i'm especially curious about this person who's been really active i'll pick him again in a minute as the stream kind of gets rolling but i'm curious to talk some more so where did i want to start so the one of the recurring themes of Oh right, I should do a standard intro. Standard intro, this is the office hours for lobsters. If you have questions about the site, the community, code base, those are overlapping concepts, speak up. We can also run queries against production database. And otherwise, it is kind of my dedicated coding time. So you can watch me code. We can talk about stuff. All right. So where I was going to start was this issue I filed yesterday. Which. Yeah, it does show the edit history that that might actually be kind of fun. So the. Issue I wrote up was basically that we've had a couple of bugs and a couple of feature requests all related to stories controller being a little bit overloaded. More than a little bit. And it's funny, I looked at the history for the couple of templates involved and the history for the controller and it felt like, oh, you know, I'm really only seeing two bugs three bugs i look at the recent edits i'm only seeing two or three things this year why is this bugging me so if i go look the stories controller well just right off it has like nine before actions that's a little suspicious and if i pop open the the tags view. So here on the right, you can get a list of this almost never comes up on the stream. A list of all the methods in here, like most of these are actions. And then down at the bottom, three of them are like, set up the kind of stuff. And I realized So it's like, okay, that's right off, that's a lot, because Rails wants resourceful controllers where everything has the same set of verbs, new, create, edit, update, index, destroy. And maybe in the second stream, if you dig back, I talked about execution in the kingdom of nouns, a classic blog post by Steve Yeagey. I actually mostly like this about Rails. So if we go look at the routes, it's easier to see it here. Where's the stories block?
07:24Here we go. There's tab bars out there. like nine extra actions i mentioned so this is this is kind of two things happening at once but this one is like one more of those clues that the stories controller could use some love number one instead of so lobsters doesn't quite predate resourceful routing in Rails. It's not too far behind it. So kind of what we're seeing here is that this was someone's first Rails... I don't need to be coy. This was Joshua's first Rails project. And he didn't presumably see much value in leaning into the Rails style of using standard routes. And when you don't have a noun to switch on, switch on a concept that's related to that noun. so the example here might be maybe, actually all of these are nouns really smoothly. D get the text D. Man, coffee is taking its time kicking in this morning. I did actually drink some. So this is kind of a sneaky suspicion that something's going on here. The big one that says, hey, there's a lot to fix is the view. And I want to get over there. Most of the complexity the stories controller most of the thing that concerned me is this stories feed the the thing that is a big deal is ifs this this view is kind of shotgunned with ifs where lots of things are like if the form object if the story is edited by this user will then include this field or if it's a new record so actually I really let's find any if watch me struggle to write this regular expression yeah Oh, right, vim uses the other way. And I need the slash. Just trying to select all the ifs and else ifs. There we go.
10:52There's eight of them in this file. That's actually a lot for a view, especially because They're all switching between doing different things with a story. So are you suggesting things for this story? Are you editing this story? Are you submitting this story? Are you the moderator? Are you the submitter? Yeah, there's a... I'm not going to try and tweak the regex to do it, but a bunch of this stuff is... bunch of this complexity is in ternaries so there's more than my little search found and if you look at the other because this form gets reused so many ways and places the errors have to be split out to their own full own template and it also has a whole bunch of ifs so it's like okay wait a minute these these templates know a whole lot about Now, let me turn that. The concern is when a template has a bunch of ifs in it, instead of being terminal, instead of being the end of the line, like the template is where output happens, all of a sudden the template starts knowing things and containing business logic. And that's what's happening here. The template is sort of reaching back up into the controller concerns of are you resubmitting? Are you suggesting? Are you editing? And so it's not just that there are ifs here. It's that these are all controller concerns. And then it gets even more complicated. And that was kind of the The bug that pushed me over the top was... It's, what, 1334? Yeah. But... It's... Where's the URLs? Fetch. The story model, or the story form, has a bunch of JavaScript on top of it. actually like a quarter of the site javascript is for this one form let's call it our custom javascript rather than the tom select library which is also running on this form so there was a really unpleasant interaction where if you were editing a story it sometimes and if the story was a resubmit And if, wait, yeah, hold on. I can't even keep track of this bug. If you were suggesting improvements to a story that was a resubmit, you would sometimes see the resubmit UI, or when you were editing, you would see the errors that we try and JavaScript in to give you faster. Like, so as soon as you enter a URL and unfocus the field, We try and figure out if it's a duplicate so you don't waste your time formatting the title and picking tags and deciding on story text. And then there was kind of a three-car pileup where if you submitted and saw an error, sometimes this would fire again when you tried to interact with that error, like select text out of it, and the error would disappear. And having an inconstant UI that's jumping away from you is super frustrating and so it was like oh there's all these layers and you have to know all of these layers and how all of these things interact where you can't safely edit the story form that's not great and so i i wrote this up and i was like oh there's only two bugs when i wrote this first paragraph and then i was like oh god there's actually like 15 features stuffed in a trench coat pretending to be one piece of code one controller and i started writing these bullet points and if you look at the edit history for this comment you'll see that i just kept thinking of things to split out oh there was one more i thought of this morning and i forgot it but especially think oh it was the the story voting issue i said move it over to a votes controller there's also comment voting that should really be a separate controller because it has different rules around it so i'm pulling this up off stream let's update that so many edits like i can't even It is a real big sign that the tech debt is creeping up when you can't even write a blog or a bug about what to fix without like 10 revisions. So this is one of those like code quality things. And the way we're going to fix it is to just lean more into the Rails resourceful routing because we can get back on the happy path of pairing new and create actions or create and destroy actions. as opposed to every action is custom and you have to read them all this is where some of that complexity we saw in the last stream came from where comments have those the very old school style href equals single anchor tag way of attaching oh yeah i even figured out after i wrote this that Not only are we using the one form for submit, resubmit, suggest, edit, and mod, there's actually so many other bits of functionality that I couldn't write the title of this issue very accurately. So it was just a really interesting experience writing this up. So that's why I wanted to talk through this one, because the more I wrote, the more I realized there was to write, it just kind of kept going. I think this one is probably going to end up landing on me. We'll see. There have been one or two people. Yeah, so I see this Eduardo Lopez has looked at it. Eduardo has been opening a ton of PRs out in the repo. I've actually really appreciated his contributions. But there's a real chance that there's so much functionality here that I end up doing it. Most of our issues, I get to put the good first issue label on it, because I'm like, well, if you know Rails or you're comfortable diving into a medium-sized code base, you could probably work this one out. And this one is, there are like 19 things going on, and you have to be very familiar with all the site verbs of what does it mean to suggest, what's the difference between a user editing and a mod edit. Let's just break all this up. It's like that... The Sandy Metz dictum that duplication is cheaper than the wrong abstraction. We have the wrong abstraction. A single template and a single controller have to know tons of things. I didn't get into it, but the controller, where were we? Stories controller. The stories controller also has tons of these ifs where it's like, what are we doing? Are we resubmitting? What are we doing? Are you allowed to? Why is that not a before action? Or a validation? Are we saving? Are we merging a story? Wait, really? Are we resubmitting? Has it already been seen? How is that different from a resubmit? There's just tons of these ifs. I need a better name for it. There's tons of these branches where there is a conditional that is fundamentally switching between two different things. And yes, some of this code would be repeated if I split this out into two functions, but that would be fine because it's very simple, very straightforward code. This feels like it could be a one-liner. So yeah, I hope to... It's a shame that... Railsification is not like on, shoot, where'd it come from? I don't know, Instagram or TikTok, where they had yassification, which is one of those like filters you put on your face and it makes a ridiculous parody of masculinity or femininity. I want the, you know, I want to yassify the stories controller is what I'm saying.
20:31anshulxyz TIL:yassification?
And I know I've been taking notes on these.
Yeah, OK.
If it's not super well known, it's silly enough I should find this reference.
Google.
God, how do I?
These things are so bad.
Oh, why don't you have semantic markup so I can block your easier Google?
Nobody, nobody wants that.
So, ah, yeah, there's actually a pretty good one.
Except it's not going to have a, a photo.
And when you see a photo, you instantly get it.
21:24There we go.
...29So.
Here is Yassified Mark Zuckerberg.
anshulxyz lmao ok, I get it
So you take one of these like filters that's supposed to touch up skin imperfections and you just crank it all the way up, up to a thousand percent.
Yeah.
Yeah.
It's like I could tell you a million words, but you see like one picture and it's like, oh, it's it's the ridiculous overkill of improving things.
Yeah.
There was a good one.
There's that iconic photo of Prince Philip near the end of his life, and then just turning it into something kind of ghoulish.
anshulxyz samsung phones come with these turned on by default, they call it Beauty+
So I'm not totally serious when I say that I want to...
I'm totally serious when I say that I want to yassify the Stories controller, but that's sort of it.
There is a style issue available.
Samsung phones come with it turned on by default.
Oof.
I hope they do not do as much to your face.
I couldn't recognize Biden and Harris here unless it had said, have them in office.
That was the clue.
Otherwise, I would not even have recognized their face.
It does so much.
I hope your phone does not do that much to you in your selfies.
But, you know, it's a little bit of a fair description because the Stories controller will be unrecognizable after we Railsify it.
God, I wish it was just a filter.
anshulxyz btw I love your website, lobsters, my favourite part is "what are you doing this weekend"
Like, if I could pull out my phone and snap a photo of the Stories controller and just Yasify it into resourceful routes and nicely factor code, that would be pretty delightful.
Maybe one of those...
AI tools like Cursor will do that for me in a year.
Ah, thanks, Anshul.
Yeah, so this is office hours.
If you have any questions about the site or community, we can talk about it.
Oh, I keep forgetting to post about the stream.
I said I would post about the stream in the What Are You Doing This Week threads on Monday, and I've been forgetting about it.
That feels like the sort of thing I should do.
I should be putting an entry in the post stream notes for.
but I don't know what the note is, like quit forgetting things.
Maybe I should put it on my stream checklist that I rushed through in the five minutes before.
Actually, I should put it on the stream checklist.
Where is that?
Yeah.
All right.
24:23So, Good point for a break. If anybody has any questions about the site, otherwise I'll roll into pull request review. And obviously questions and such are welcome anytime. I just get humorously distracted and discombobulated. So that's its own kind of fun. So I was going to pull up some of these PRs and I was saying that Eduardo Lopez was very busy and We've reviewed, this is the one I was just talking about a minute ago, where if you click on a error message, it can disappear out from under you. That's the one I was just talking through. His first attempt at it was to just throw away the attempt to pre-validate, just cut the JavaScript out, which, you know, it's, one of those destroy the village to save it kind of moments. This PR, I peeked at this before the stream, like a one-liner to... Oh, God, I actually get what it's doing. So this is one of those signs that Stories Controller is way overcomplicated, is... The fix for a weird JavaScript interaction is to add what looks like a no-op to a helper function. Well, it's not a helper function. This is actually an action.
26:17I actually get how this works but I don't know that I can explain it in a way all right let's so let's grab this url this one's kind of
...48So Eduardo's PR does, and I got to talk through it to make sure I understand what it's doing. Make sure the build passes for it. Kick that off. Yeah, build is passed. Is he adds a call to story valid here.
27:15And this is one of those elliptical Rails-y kind of features. If you call, because ActiveRecord models are so mutable, they work by you stuff a bunch of attributes in them, like we do here, and then you find out if that's valid. And in the meantime, you have this weird, partially valid object, and every method that is on it or interacts with it, has to know that it could be invalid or that it could be in this partially invalid state. It is my least favorite thing about Rails. But what's happening here is when you interact with form errors, it's up in the JavaScript, isn't it?
28:22There's another that might even be related. So what I'm expecting this does is by making sure that errors are on the story, it's causing one of those many ifs to switch in a way that makes it more consistent. So somewhere there is an if that says, if we have errors on the form, No, it's got to be the other way first.
29:04If we're checking for a URL dupe, show one set of errors, and if we're checking
...24So if we're splitting up, let's take a look back here at Eduardo's PR.
30:05So one thing I've seen in a couple of Eduardo's PRs is they sometimes make odd edits that make me think he doesn't use the site. So I want to see this branch here, Oakland. So since this PR is a one liner, I'm going to put it in here and try to recreate. Well, let's try and recreate the behavior. Cause if I can see it locally. All right. So the problem is someone let's pull up local host helps start the rail server.
31:16All right, so if we submit a banned website, yeah, what's a banned website off the top of my head? Oh, dataswamp.org, so after the origin code, I was able to unban this website. So I know that my local database has some out-of-date data.
...43So if I say submit, Should get a nice error here. Yeah. And then when I click, it vanishes. Well, there's the bug. And then the form layout changes. So form layout is all done with CSS floats. And we keep seeing odd breakages like these. I saw one more for code we'll get to later in the stream. But I have an issue open on the GitHub for anybody who's interested in contributing about how we should use CSS Grid on these, and somebody just expressed some interest in it, so hopefully we'll get that fixed. All right, so if we go ahead and uncomment this,
32:49I will bring this back on. Let me just get a fresh form. Come here. Copy. Fresh form.
33:10So I get that. That's Wrong. I immediately start getting validation errors. That's just wrong. This is not a good fix. I got to see it happen again. Yeah.
...45So I do get that error. Yeah. All right, so.
35:11All right. This one, I almost wonder if it would be better to punt on this one until after that stories controller cleanup is done. If I were the one implementing this PR, I'd be real tempted to. Got a couple others. I didn't realize I'd gotten this.
...48tidy up.
36:05So let's jump into another one that came from streaming. So we noticed on stream that There was bad data in the production database where normalizing a URL www10.org just normalized it into org. There's a couple of places that, excuse me, a couple of places that normalize URLs to present them nicely. And we are just doing the wrong thing. where we're not we try and strip off dub dub dub and sometimes it's so much less common now but sometimes people have like www.ibm.com which is a weird thing to leak but kind of made sense with the way web apps were architected in the 90s
37:21Majora and others. Who wrote these other commits?
...39Majora and Majora. Okay. Someone with an odd Git setup. I'm just kidding. This might be, I bet there's a force push in here. No, this might be somebody using the GitHub web editor and having a little hassle with that. So let's go ahead and swap these over so I can see a full view. I'm actually a little surprised that this is like seven commits, four files changed. I thought this was going to be a one-liner somewhere. Oh, we're getting straight into issues with the public suffix list.
38:30I bet we would do the wrong thing. Yeah, because of...
...38This is spurious.
39:07This was a different fix we made a little while ago. There is some hassle where I think it's people running MySQL.
...54Can I just say MariaDB dash dash version? Is that it? Yeah.
40:53This is really... So when I first filed the issue, I thought it was going to be just here in extras util, this normalize function. So what this does is try to recognize duplicate URL. So if you submit example.com and Alice comes along later and submits example.com with a trailing slash or with index.html on the end, we could be very, very confident that that's the same link and we should treat it as the same link. So normalized strips out a lot of cruft that ends up on the end of URLs, mostly of .htm, .html, index.html, index.php. And I thought this was just going to be something like this. And I'm a little concerned that I see two parallel changes where we just have two different places where the code base edits URLs, both when we normalize and we try and figure out what a domain is.
42:28All right.
43:26That's the test file. The test file for this is... No, I think we have a separate spec just for this because there's so much of it.
44:07And then this one. So we do a split.
45:04Rails is big on nil and passing nil around. So there's a lot of extra complexity here. But if you kind of look through it, we could just fix this with a regular expression.
...28So if it's ww10.and,
...39It has sub is going to. So I'm trying to figure out maybe this is me being too clever with regular expressions. I'm wondering if there's a way to express. Yeah, I can capture it.
46:03And I'm going to have to run this in the console. Let's just do this all in the console. Otherwise, I'm just going to be guessing. So if we have. And I'm going to say.
...36This takes it. to main, not a full URL. So there's one change. And I'm going to switch to backslash A because that's the proper multi-line guy. If we had survey signatures on everything, I wouldn't need it.
47:04So I want to consume any amount of characters followed by a dot. Now, anything that's not a slash followed by a dot.
...27So that works. And if I said, oh man, regular expressions.
...43So this is kind of a way of, I'll explain it here in the comment of what did I grab? So backslash a.
48:31Call set domain and origin. And how much do I trust that it's actually a domain?
...54We've pulled it out of the match. And the match reuses that big regular expression And boy, I better be able to trust that or the site's on fire. So OK.
49:15There isn't going to be a slash.
50:15There we go. So knowing that, could this also do the same trick?
...52I have the same trick here from story model.
51:16All right. So there we go. I wonder if I don't. Yeah, I was going to say, I don't think I recognize Ryzen 114. This is literally their only activity on the site. I was going to say it felt a little bit like junior developer code. Who are they following? Lobsters. Okay. I guess they're a fan of the site. I don't know what this dog is. Kind of looks like a high school mascot for other Americans. Let's submit that review.
53:15So I read a lot of style cues out of somebody's code. Sometimes I'm reading somebody's Ruby, and I'm like, you've written a lot of JavaScript. Or I read somebody's JavaScript, and I'm like, oh, you write a lot of Python. Or sometimes I have that vibe that somebody is a junior developer. That's why I went clicking to Ryzen 114's profile. And just to highlight what I'm catching is it is the oddest thing, but junior developers, whenever they have strings, seem to reach for split rather than a string method to inspect it. And I'm aware the regular expression I wrote is a little obtuse, but that's part of how you know I'm not a junior developer is I'm comfortable writing fairly complicated regular expressions. And I think also a lot of it is a lot of junior developers now start with JavaScript. I think it's a great first choice because it's wildly popular and not going anywhere and reasonably clear. We've done a pretty good job of hiding the bodies on the web. Like somebody was talking about how last stream how es6 modules you cannot have one unless you opt in to use strict and if you opt in to use strict you cannot use the foot gun called with so like javascript is getting better over the decades is what i'm saying but javascript's string api has always been a little anemic compared to rubies Like Ruby started as a scripting language and a convenience language and as a philosophy seems to have really wide APIs on objects. Like we have sub and sub bang and G sub and G sub bang. And I want to say there's one or two other functions that do string replacement and then most of them will also take a block. So it's like a really expressive API. There is almost always a very specific string method in Ruby for the thing you want to do, which I guess is why it's such a, yeah, not a red flag, not even a yellow flag, just an entirely neutral colored flag that when I see somebody call split on a string, I think that they are either new to Ruby or a junior developer. And usually I lean a little more junior. The senior seems to have that instinct of, oh, I bet there's a method on string. And if I skim the API docs, you know, and my hair doesn't fall out because I looked at the string API doc and saw that it has 100 methods on it. That's my dev browser. Let's keep this. So this is great. I love that somebody dug into this. All right. So two more PRs here. And I'm going to pick the one I haven't clicked into yet or that I already peeked at a little last night. And it's funny. Lobsters wants to take all of the time I can give it. I mean, as you can guess from we have 120 open issues, what that kind of says is if I had 1200 spare hours for development to burn down this list, lobsters would be happy to take that.
57:23That's part of the reason I'm streaming is to kind of prompt myself to timebox myself a little bit more, especially on the development stuff. All of these, I would like to have zero bugs. I would like to have zero open feature requests. But most of them are not especially urgent. Even the bugs are not enormously urgent. And so if I can keep lobsters coding from entirely taking over my life that would be nice although it would be fun the other part of it is there are 120 issues open but only like five of them are feature requests and i have on my computer like a backlog of like a hundred feature requests or improvements I think the site could have and I try not to do too much of that while there are significant open bugs but yeah so one of the improvements and this one is I really appreciate Eduardo taking this one on and there was another pull request from someone else on the early issue was
59:00rails is kind of sloppy about a lot of database stuff it's not rigorous and strict at all so there have been a couple of plugins on top of it like active record doctor and database consistency and so This one is a long term investment in code quality and trying to prevent future bugs I mean you've all seen how many times the test suite has saved me or break man has saved me or just the linter saves me time from having really fiddly. conversations in pull requests and so Eduardo here has. Added support for active record doctor, which is a gem that plugs into rails and says here's a bunch of. Obvious stuff like if you have two models that have a foreign key between them, well, you should have a SQL foreign key. Rails... Well, you know... No, it's not Rails. It's DHH specifically. Where is that? Wrong browser.
01:00:27DHH wrote this blog post early on. called Choose a Single Layer of Cleverness. Does it have a... His old blog is broken. This single layer of cleverness.
...52There isn't an ID here, is there? For me to just link to it? Nope. Old blog. That... Having constraints in your database is an improper way of spreading out business logic. And it should all be in your object-oriented code. You know, it says September 27, but it's September 27 of 2005. So this is pretty early in Rails. It's pretty fundamentally wrong. Realistically, you are not going to be switching between MariaDB and Postgres or SQL and Postgres. So I understand wanting to keep more of your logic in Ruby, but it's okay to have some of it in database. Stored procedures are really painful to work with because They are executable code. And so you have all the issues around managing and versioning and deploying them and almost none of the tools for managing and versioning and deploying them. But he is just, Unfortunately, he was flat wrong about the value of having things like foreign keys and uniqueness indexes. And Rails has walked back a little bit of that with better support for uniqueness indexes specifically. But this other one of don't lean on the database for it just means that every Rails app has bad data in it. And I point back to this one because it is dhh is very strong opinion that set this one up for rails so bringing back the bringing back the pull request turn off this sidebar active record doctor is one of those things that should be part of Rails and almost certainly never will be. So it's trying to figure out, hey, if there's a column that looks like it's following the Rails convention of underscore ID, probably it needs a foreign key and probably it needs to be indexed. And in general, that is excellent. We have a couple of these, like what's your Twitter ID? What's your... We call them short IDs. I would maybe call this slug is the term I've seen in a lot of other databases, but it's not a convention that's so ubiquitous that it's worth changing. So Active Record Doctor just kind of helps you avoid put gunning yourself.
01:04:45One of my rules of thumb is if you don't have a. Strong reason to order things. Just default to the alphabetic. So. So we have a couple of these things that are not foreign keys that look a little bit. stories mastodon id this is where i caught myself last night because i started looking at this pr and i like popped open the story model and i was like wait is mastodon id something about the instance that we're posting to and then i was like wait a minute you are doing code work that you should be doing on stream tomorrow but it's fun it's a lot of fun maintaining this
01:06:25We have one view in the database called Replying Comment.
And it's there because Hunter is a big fan of views.
And it works, but Rails doesn't love views.
And so we keep having bits of friction around it, whether that's restoring databases from backup or,
Things that sort of treat it as a model, but don't know it's not quite a model.
Rails gets a little...
It's one of those, you can do it, but you're going to start finding corner cases.
Rails really wants one model to map to one table.
chamlis_ spent frankly too long preparing this https://dhh.dk/arc/2005_09.html…
And so if it doesn't... Yeah.
Yeah, these are fine.
01:07:23chamlis_ darn the comma didn't encode
Oh.
Thanks.
Yeah, one of those text links.
I don't think Firefox supports those, but I'm happy to grab that and put it in notes.
Yeah, let's put this over here.
...52chamlis_ works for me in firefox, which surprised me too
Oh that's great that it worked for you in firefox it's been a while, since I have tested it and I knew firefox was considering it so i'm glad they got it, we can check.
chamlis_ thanks
To see there we go I encoded your comma.
01:09:12I don't think SQLite supports stored procedures. It's a little funny, but like the way SQLite integrates directly into your application, it has the potential to be the one place where stored procedures are actually really comfortable to work with. That would be a Funny little bit of irony. I wonder if this is just complaining that out of the box the active storage tables don't have these validations or it's just that it does and see them because we don't really have models for them. The models live over in Rails.
01:10:19Password digest.
...49chamlis_ turns out firefox doesn't like the comma being encoded, so I guess this is on twitch's link parsing
Oh, so that quick edit of 2C that I did, that doesn't work?
That's kind of odd.
Are you sure you didn't typo?
Like it wants the spaces encoded.
All right, whatever.
I'll put it back.
I would bet that my, honestly, it's even odds whether the regular expression I wrote for my blogging software, whether it'll pick all of that up.
The way these text things work is I could just drop everything from the comma and hunt on it.
We don't have to know.
I can see how it would nerd snipe you, though.
01:11:38chamlis_ good shout
That seems to be an unexpected benefit of streaming, as it's nerd sniped a bunch of people into helping.
All right.
So now here's ActiveRecordDoctor working where rather than saying these are slightly odd things we're doing that ActiveRecordDoctor isn't correctly analyzing, ActiveRecordDoctor was like, oh, hey, you're missing validations for these fields.
And that's legit.
We are missing validations for these fields.
We should have all of these.
Yeah.
01:12:39Really minor stuff.
...47Seeing this validation only integer is just so... It tells you a lot that Rails really works by just slopping strings around. And that's fine. That's okay. So I'm skimming this part pretty light because all of these are great. Generally.
01:13:20Good to know we can only have 16 megs of JSON settings. That's just straight up a missing index. Yep. Good catch.
...39We're really missing this many foreign keys. Oh, and this one's on me because I just added the links table a couple of months ago. So I just totally missed having foreign keys. Honorations. This is very old. This is new. And the reason I talk about whether stuff is old or new is It kind of switches me into different gears of what context should I be looking at this? Do I have to watch out for those kinds of non-idiomatic Rails things, like the resourceful routes that we talked about at the beginning of this stream? All right, so then...
01:14:45i wonder if any of this was generated by active record doctor if all of that was eduardo but this is great man to have all this extra stuff
01:15:28espartapalma it's matching the types of columns (int => bigint?), but watch out those migrations over big tables
Yeah, the various...
So Espart Palma says, watch out for redefining columns on big tables.
That is totally valid for any app besides lobsters.
If we took a half an hour downtime on a migration, I wouldn't really mind.
The only...
The only big table here, and I'd say big very reservedly because nothing in our app is truly big, like votes is the one with the most records.
And I want to say the last time I looked at it, it was somewhere around 4 million, which is not a big database table anymore.
Stories has like 120,000 records, but it's also pretty wide and it's a God object.
So that one caught my eye, but all of the rest of these
don't have that many records links is probably close i want to say 80 000 ish yeah so aside from our database is generally not big in a like a big data sense for sure but
Even in a big app kind of sense it's also okay like no one is going to be waving an SLA contract around I know there are gems like.
Was it good migrations.
01:17:15yeah.
espartapalma yeah, you know better, but it was a general suggestion for those who just learnt about active_record-doctor
So.
wow last year, I wonder if this is slipping out of maintenance.
...30pushcx https://github.com/testdouble/g…
oh yeah it is a good suggestion yeah so i'm gonna bring this link in here and i will i will share it for anybody who's curious wrong clipboard the good migrations gem
espartapalma this is also goog https://github.com/ankane/stron…
Or is it the... Oh, no, this isn't the one I'm thinking of.
This is the one I disagree with.
So... One of those other strong migrations, I bet that's the one I'm thinking of.
Let me grab that link here.
I was going to say there's one that says, hey, don't do things that might lock your table for a half an hour.
there are usually alternatives to it good migrations is kind of an opinionated style guide and they disagree with it just dangerous yeah this is the one i was thinking of as part so thank you you just saved me a google just as i was figuring it out
This one, I might, gosh, I almost wonder, have I tried to install this on the app?
Because this one is the no-brainer.
I think pretty much every app should install it right from the beginning.
Good Migrations is a style of using migrations, and I disagree with it.
When it says some will reply who cares if old migrations are broken that is me that is like my exact migration or my exact objection.
or at least the start of it.
You know it says.
Oh, DB schema can't be regenerated from scratch.
That's fine.
DB schema, the big value you get out of that is if your DB schema is a
perfect reflection of production it is the mechanism that you use to mirror your production database in development to make sure that you have the same structure and doing so is much more straightforward and easy to maintain than oh let's take
these dozens of migrations, these years of migration, and keep all of this code in sync so that when you run this code, it perfectly recreates this existing thing.
I want to just use the existing thing.
Like, don't... You know, I would rather my house not burn down than have the plans to perfectly rebuild my house.
I live in an apartment, but you know what I mean.
So strong migrations is a really nice one because as Espart Pomo notes, it's got the don't foot gun yourself.
That's a theme we're going to come back to later in this actually.
It's adding a little bit of, I'm actually doing it almost entirely with text and a little bit of CSS of helping users not foot gun themselves.
01:21:30It's the Git pickaxe that searches your entire history.
I can't remember.
I want to say I tried strong migration once on lobsters, and I bounced off.
But maybe I'm just thinking familiarly of it because it's on that personal to-do list.
Nope, it's not there.
I peeked at it off stream.
All right.
Probably it should be in there.
espartapalma strong_migrations is very leaned to postgresql, maybe that's why you pass back in the days
All right.
So this is great.
Another very helpful PR from Eduardo.
Oh, strong migrations is very much about Postgres.
Yeah.
One of the really surprising things about the split between
competition between MariaDB and MySQL is that MariaDB is, or not between MySQL and Maria, but between those two and Postgres is that MariaDB is better at distributed multi-master kind of setups.
That is not at all what you would expect from the general vibe of those.
01:22:58where MariaDB is a little bit loosey goosey, like, ah, you gave me the string one. That's basically like Boolean true. So it's a little surprising of like, oh yeah, we're gonna make multiple hosts work in concert. We're gonna do that reliably. You're not gonna lose data. I don't know, it just feels a little more post-grassy to be operating at that level. I'm going to grab this URL. I forgot to put it in the scratch notes here. So we got this. We got... Come here.
01:23:55One, two, three, four. The Action Mailbox talked about this last one, but this one is still a work in progress. It's been a little frustration for me that GitHub... They've had to make a very general tool, and they've done a good job of that. But at the same time, it's really hard to put your own policy and process on top of things. so I can't really communicate to users that are to potential contributors that I would love them to click the review requested button so that I know that the PR is ready for my review and then the UI doesn't really reflect it yeah it's there if I all right never mind that part is wrong I forgot that When you get into the mobile layout, it disappears, but it comes back if you search.
01:25:06Oh, no, I'm just misreading. He has requested that I review it, but it just doesn't show on the UI there. The only thing is the I haven't clicked into it UI. Yeah. Let me take a quick personal note.
...30There we go. So I believe I've already reviewed this once. Yes. So this might be a real short review.
01:26:04So this was kind of split the balance between user privacy and site coherence. Users are allowed to disown stories and comments, but the only way to disown a story was to delete your account and disown all your stories and comments where you can individually disowned comments or yes, that's correct. So the feature that's missing is being able to individually disown a story. And I guess Eduardo is getting pretty comfortable with the code base because it means climbing up and down, you know, front end to back end, template to JavaScript. So I just want to give this one more skim. This is very similar to the comment disowner.
01:27:01There isn't really any code in the disown that can go wrong, because all we're doing is setting the user ID to flagable days.
...18Yeah, this could use the nil propagation operator, but it doesn't really need it. And I can see how it's copying the function from comment. This is the Stories controller getting even broader. And then yay, tests. Yeah, I think this is in great shape. If the build passed, it's ready to go. And it did. So I'm going to just go ahead and make a merge commit and I hate that.
01:28:24Lost my letter.
...40And let's go make sure the issue closed correctly. Yes, excellent. So I kind of griped about this on Mastodon yesterday or the day before, but We occasionally get these kinds of comments where someone kind of claims the issue, like they say, I'm working on this, or can I work on this, or can I take this? And then they don't open a pull request for whatever reason, like, hey, it's fine. Everybody is volunteers. Life gets busy. But then it feels like issues kind of stall because when someone looks at the list of issues and they click into an issue to see, oh, let me take a Maybe I want to take a look at this one and maybe i'll make a pull request for it, then they see somebody else claiming it. And it just you know the the whole thing enters a very ambiguous state and it's not just formally ambiguous. You know, maybe this is a place where we could. use assignment but it's also socially ambiguous and that's the part that's hard because you know when do i come back and say two weeks later three weeks later three months later and say like okay well you said you were gonna do this but you flaked like it automatically comes as a criticism when it's not meant to be So it kind of has to be a bot so it's not personal. But GitHub doesn't have great support for that. So... I don't know. It's this messy social and technical situation of distributed state. And I'm trying to... I am trying to make sure that people feel comfortable volunteering to work on stuff and don't waste their time. but also don't waste other people's time. I don't have a great answer for that. On the other hand, also, all of the books I've read about managing open source projects are on your mailing list because they're all pre-GitHub. If somebody knows a good book on managing open source projects that's a little more modern than, what was that one, Carl Fogel and Ben Collins-Sussman, that would be nice. Back to the PRs. And that's everybody for this morning. So I have four here that we looked at, but only three on my scratch lists because I must have forgotten. Why are these closed out of order? Oh, these are... This one gets me all the time. When you look at a list of closed pull requests, they are in the order they were open, not the order they were closed. So the thing I just did is the third on the list. It pulls me every time.
01:32:15I guess least recently, recently updated.
Yeah, I don't think it's going to remember that though.
So
Yeah, and then it's jumped back to its default.
That's one of those where if your intuition doesn't match the designer's, the designer can almost never change that sort of thing because people get used to it.
So I was just going to grab this link for the scratch nodes.
easeout you would think switching among common filters would also switch to their natural order.
So let's bring that up.
01:33:06You know, EaseOut, when you say switch to their natural order, what's natural?
I think this is a place where whoever designed that had a different intuition than I did.
It is a very natural ordering to... Or are you saying that if you filtered a closed, that common filter would have its own ordering?
easeout I mean, when the filter is "merged things" you can go off the merge event, etc
yeah it depends a lot about how you think about it i think of open as closed as two different pages if they think about this as story filtering it's a little or pr filtering it's a little strange to say that filtering by fields or changing filter on a field would also change sort i don't know but my mental model is that these are two different pages that i'm switching between and not
filtering the table, which doesn't match the UI, but that may just be me being old and opinionated.
Yeah.
Yeah.
I don't think this is one where I've tried to phrase this as very much, you know, this is my intuition and my opinion, not matching the designer and they can't change it.
Even if they, you know, whoever's maintaining this now couldn't change it.
even if they agreed with me.
But it's also just a matter of opinion.
And they have a really strong case.
So let's talk about that privacy foot gun.
Actually, this is a really good point to remind that this is office hours.
If you have questions about the site or the code base, pop up.
Or if you are DPK,
in Europe who wanted to quiz me about starting a workaround co-op.
I'm happy to chat about that.
All right.
So where did I leave this?
Did I leave this in my stash?
No.
I made a little branch for it.
So let's cherry pick.
And what did I even call this branch?
I called it invite, there we go.
01:35:39All right. So what I have just added, well, I guess let's start with the diff. I added a commit to a local branch. Oh good, I even remembered to bump the date. So I wrote this, months ago the last time we had to deal with this or a privacy issue specifically for trans users of the site roughly once a year someone who is transitioning wants to change their account name or basically like stay on the site but have their new name and their new username and not link it to their old one and we have one feature that is for this that doesn't do what some want and one feature that is not for this that also doesn't do what they want but looks like it can be pressed into service because a lot of trans people don't want to connect their old name and their new name and it's more than they don't want to be called their old name their dead name it's they want to be totally private about being trans and so if your new profile says, you know, Alice was invited by Bob. Hey, who are Alice and Bob? Hey, they have the same last name. Oh, this is the same person. And then they've just outed themselves, which is the opposite of what they want. So on the settings page, all right, so I pulled this in. We can use the dev browser here. I've added, it's funny because this is like, The feature works. These features combine in a slightly surprising way. And the fix is not to the feature. It is just to make sure that the users understand what is about to happen. So on the account settings, this is such a programmer form. Like literally the very first thing on the form is the thing you almost never do. Should I just reorder these while I'm griping about it? Like, people very rarely change their usernames. But I added this line here that says, hey, this is about to create an entry in the public moderation log. And so in the case where, well, let's keep up with the cryptography names. I already used A and B. So if somebody with the username Carol is changing to the username Dave, they will see. in the mod log changed own username from Carol to Dave. So we roughly annually, we the mods have had a like slightly panicked message from somebody who says, hey, you just logged that I transitioned and I'm trying to keep that private. And that's really been a difficult one to handle because there's not a lot we can do without violating the site's really foundational principle of transparency. So anybody with root access to a database could go in and do all kinds of things, like edit or delete mod log entries. If a moderator did that on lobsters, it would absolutely get noticed, but it would also really betray the trust of having a mod log. I mean, and aside from the incredibly dramatic thread, users would very rightfully, for years afterwards, doubt that the mods were being honest about other stuff. The transparency of the mod log, oh my god, it's so valuable. We don't get accused of, oh, a mod sneakily edited somebody else's comment, which is a real thing that the CEO of Reddit did was he wanted to, he was pissed at somebody and he edited their comment to embarrass them that was five years ago eight years ago something and it still comes up that people are like oh well maybe the admin just you by editing your comment like you can never you can never unbreak that trust Or the other one that's real common and people assume it of us because we look so much like red and hacker news is and say oh the mods are pushing this story up and pushing this story down. That is not a feature of the site, you can read the code for the site, you can see that it's not a feature, but also the other benefit of the whole site is open source is. You can do the calculations yourself and you can see, oh, no, these stories are in the order that is correct. If I kind of manually run the code myself, whether that's, you know, you play computer and you run it on a calculator or you set up a dev version of the site and you copy over the values you see, you will get the same ordering, period. so the reason the trans users foot gunning themselves has been really painful has been it's an opposition between we really want to be kind and understanding to these folks and respect their privacy and also we have a in contradiction obligation to transparency And we have sort of muddled through like four or five of these over the four or five years previous. That was why I say the commit has been sitting around for a couple months because I didn't want to do a commit 10 minutes after somebody changed their name and highlight them. So that's why I'm also being a little vague about how long ago the last one was. The other thing is, so if a user knows that this mod log entry is going to happen, they can say, okay, well, if I'm, where are we now? D? If I'm Dave changing to Edna and I don't want to see that in the public mod log, I will make a new account for Edna. And the way you make a new account is not that you just go to the form, it's you go down to the invite form. and you could send yourself an invite, right? However, people don't always read copy really closely. So it says persons you invite will be associated in the user tree. People don't quite get what that means, but on your profile, let's go up here, on your public profile, and on the users tree so let's just go to maybe i should touch that copy too hmm all right rails is doing that cache busting thing oh god i gotta fix that for these streams also for my gray hair but those will load in a second but basically your individual profile says, so example in mine is, I was invited by JCS. And if you find me in the tree, and you trace these little lines, you will find I was invited by JCS. And so if you are, where was I, Frank, invited by Edna, there is an indefinite link between those two. That one's happened. And so I added a a line of copy here that is specifically, I hope, like I was literally trying to start the sentence with the word trans in the hopes that it would pop out as the first word in the paragraph. So like a previous version of this, I wrote like trans question mark. I was tempted to put it in bold. I'm just trying to make sure that people get what's about to happen when take backsies are really hard. And so I said explicitly, That new user profile is going to list who invited you. And then this second part is like, all right, well, if we have all of these public commitments to let's be transparent and let's not sneakily edit things. Oh, the reason renames get listed in the mod log is because if Bob becomes Bob 2000, Well, if you knew there was a Bob and you try and look up their profile and it's just gone, you might assume that the mod's shadow banned Bob. That's really lousy. That's why there's the mod log entry. So if you want to avoid connecting your old usernames, just ask a moderator for an invite. That's all. And then there's no short way to say it in the copy, but this has happened once or twice where a trans user has emailed to say, how should I handle this? And we say, we will just send you an invite. And then after you activate your new account, please delete your old one and don't reactivate it because people aren't allowed to have multiple accounts active at once. So that one, I don't know. It's funny because... it's a thing that happens about once a year so it's hard to be really confident that this is going to fix the problem help people stop put gunning themselves. Because it's so infrequent if it happened once a week well, I mean we would have. attacked it a lot earlier, but hopefully it helps. So there's some privacy.
01:46:19So a different thing, although privacy comes up.
The Lobster's chat room, I've got a little page.
The Lobster's chat room, which I noted on our last stream has two new moderators, yay, is over on IRC.
And if you're not familiar with it, it is old people group chat.
pushcx https://push.cx/discord-vs-irc-…
Literally this morning, so a thing that comes up, I don't know, every couple of months on the IRC channel is some of IRC's clunkier parts, sharper edges, or being less friendly to newbies.
And that last one came up this morning.
So a couple of months ago, I wrote up notes from the stuff that has happened over basically nine years of having the chat room.
And this morning, so one of the things we talk about is like, oh, well, should we use Discord instead of IRC?
And Discord is kind of the most, it comes up over and over because it's the most popular other chat network among developers, it seems.
The.
01:47:53This morning, somebody kind of speed ran this experience of they had the bad news or new user experience on IRC.
So they.
connected and they kind of struggled through knowing if they were even connected and in an account because you sort of you don't really have to sign up to irc you can just connect which is strange at this point it's one of those places where so i wrote on the scratch like irc is eternal unfortunately we'll talk about that but and then they had a bunch of questions about like what's the difference between slash msg and slash query because
It's just a weird historical quirk.
God, I don't want to explain that one.
They had to do all of the setup.
When they joined, they didn't know that they had succeeded.
Because when you join an IRC channel, you don't get any scroll back.
And so it just looks like you are alone in the void unless someone happens to talk right then.
And if somebody talks right then, this person happened to say hello.
And so someone said hello back.
But otherwise...
you connect and it looks like nothing has happened.
And then like one minute later, they were like, hey, why is my IP address all over the screen?
Can you see that?
And it's like, yeah, that's personal information.
We all know what region of the world you're in.
And if we wanted to be a dick, we could DDoS you.
And it was not quite in this order, so I don't think they were doing a bit, but it was just really vivid to watch somebody
roll through the big characteristics about IRC or the big misfeatures.
And misfeatures is hard because a bunch of this stuff is just IRC doesn't change.
It's enormously impressive that I think I first got on
in 1992 briefly like i used it a couple of times at a friend's house sort of thing and then really i got on in must have been 98 or 99 and then i wasn't on regularly until 2002 or something yeah that's ballpark but it's like by any measure i have been on irc for decades
And it hasn't changed.
And some of that is impressive.
And some of that is just irritating because we've accumulated just over the decade of running the IRC channel for lobsters, we've accumulated just a big list of stuff we want.
And it, these are not unreasonable things to want anymore, like clear documentation.
Yeah, good user docs.
Where's...
goreng i'm too young to experience IRC. my generation started with BBM.
I don't want to pick on that exact document.
But there is a document I'm thinking of that's active, and it says, oh, to accomplish this task, you have commands A, B, and C. And command A is worthless for historical reasons, but it's the first thing
The doc explains because you kind of have to talk about it in this order, but it's just, it's calcified old, bad UI.
Welcome Goring.
It is okay to be too young to experience IRC and VIM.
I don't know, BBM.
espartapalma I was AFK, but here's a book about managing Open Source communities/projects which is modern than Karl Fogel one.. How to Open Source by Richard Schneeman (@Schneems) https://howtoopensource.dev/ for those who doesn't know it, Richard is the maintainer of CodeTriage a very popular open source software (written in ruby too) https://www.codetriage.com/
Maybe I'm too old to know what BBM is.
01:51:58goreng blackberry messenger
Oh, thanks for a couple of books on open source.
I appreciate you coming back around about it.
I will grab these for later.
Blackberry Messenger.
Yeah, let's grab that.
And where did I put?
Yeah, I'll just make it a little section here.
01:52:45Let's just indent all of this.
There we go.
Thank you.
I appreciate those references.
And depending what happens this weekend, maybe I will read them for the next stream.
Yeah, so you mentioned BlackBerry Messenger, Garang.
espartapalma you are welcome, I posted before I forgot about it :)
One of the things that I came to in the conclusion was, and I'm actually, I'm happy with this line.
easeout My IRC use started in the Quake mod days. I've never had a great understanding of it
Text-oriented group chat has products like Discord, Slack, Zulip, WhatsApp, Telegram, Messenger, WeChat, iMessage, Gchat, Skype, Teams, Kik, Mattermost, Snapchat, Wicker, and then, you know, some small ones that only have tens of millions of active listeners.
Or active users.
Yeah, quick modding is part of how I got into IRC, too.
I did some terrible level design in, like,
99 and then talked with friends about making a mod it was really funny because the mod we wanted to make when did counter-strike come out i can't remember i want to say we were like roughly the same time period yeah first release was 2000 so we were working on something that
In 2000 and then I think we all kind of wandered off middle of 2001 and I don't think we knew that counter strike existed we just kind of had that same idea of what if you had real guns, instead of magic lightning guns.
We didn't know what we're doing now never finished barely got started on a mod even.
01:54:37So there are so many options for text chat.
easeout Hell yeah biting off more than you can chew
And IRC, I don't know, it's not quite to the boiling point, but it kind of never improves.
Writing off more than you can chew.
Yes, as a toddler, we were the programming equivalent of toddlers.
We had no idea how much we could chew.
So I love IRC.
I've criticized it pretty sharply.
It's a little softer in the notes.
I'm deeply appreciative of the IRC communities I've been part of, but it's one of those things that breaks my heart because it could be better.
It could have so much more nicer stuff.
And I don't know if it's
The fact that it's a protocol instead of a product is part of what's held it back.
Or if it's personalities involved, because realistically, there are only, even at its heyday, there were only a handful of very active big networks because there are such huge network effects to these.
I don't know.
01:56:03espartapalma the dry-rb.org community uses Zulip, it's kind of new experience how it's the chat itself is managed but good overall nowadays
We'll see.
Maybe we'll just move all the lobsters to Twitch chat and we'll have one of those 24-7 streams.
Yes, I know Discord is sort of based on IRC in a weird way.
I don't think there's a meaningful connection between the two, although it still has an API.
Yes.
Yeah, S-part mentions Zulip.
That's down here at the bottom, actually.
The last note in the doc.
easeout I think chat is round the clock on twitch, stream or no
So I attended Recurse Center, which is a writer's retreat for programmers.
What was that, 2017?
Oh, actually, it's very memorable for me for two reasons that are worth mentioning.
So...
I was there fall of 2017.
So I was there right now.
Seven years ago.
And it was just today is the 17th.
So it was just two days ago that I became is the anniversary of when I became the lobsters admin.
So that was kind of a personal little birthday there.
01:57:25espartapalma yeap, that's why I bring that up. Some other ruby community uses ... sadly the only one I know
so when I wrote this post, it was the first time I'd updated my blog for a minute and.
Recurse uses Zulip.
espartapalma (meaning ruby community using Zulip)
And I think in the early days there was some overlap between early attendees and the folks who started Zulip.
The, the two communities are close in a way that makes me think they've been close a long time and.
Zulip in 2017 and 18 was just kind of janky and slow.
I'm not going to dig up the bugs, but if I used keyboard navigation, it was really possible to get the keyboard nav out of sync with what you were doing.
So you could use keyboard nav to open up a menu
and then move on to a new thread, and then the menu would either open so late or just fail to close, and you would have outdated UI overlapping in inconsistent ways.
But in the couple of years, it's gotten a lot better.
So I got reminded of it because I got a ping from the bot on the Recurse instance of Zulip of, hey, oh, Peter posted a blog post.
And it was like, hey, Peter is your name.
And it's actually gotten pretty nice.
Like it's still a little bit programmer UI.
Programmers do this thing, see, like I do here where we make big bold colors all the way across left and right for sections.
Nobody else does that, but it's a thing programmers do all the time.
And if I pulled up Zulip, even the mobile app does this where, and I'm just gonna...
I was talking about the quirks of
know i see dot split on a string and i'm like aha a junior developer or new to ruby and i see ui where there's a colored bar all the way across the stream and i'm like aha programmer ui and so yeah and it's really it really stands out on the mobile app where it's just it's such an odd ui quirk
programmers that we keep adding horizontal colored bars for section headings and I think that is some of the very little remaining
clunky UI in Zulip.
Although, yeah, the web interface is much nicer than the app.
easeout we look at UI and see the hierarchy of rectangles and perhaps want to fill them
But hey, there is an app.
And it's pretty good.
I'm going to...
If I can grow my user...
If I can grow my recheck to a point where I'm employing people...
would probably start with zulip instead of i don't know slack which i spend a lot of time mad at and it's just it fits and zulip the big thing that's really nice about zulip is it's run by a bunch of nerds
and it has really nice APIs and they're very friendly and they're like, yes, you should be able to write plugins for your chat network.
You should be able to customize the code for your chat network.
And as a big nerd programmer myself, I'm like, yes, I should be able to write plugins that are not just how much can I squeeze into a text bot?
I should be able to write something that plugs in and just a couple of lines of code.
And that is
It's so satisfying.
In addition to, Zula pretty much has everything on this list.
And ease out, yeah, the hierarchy of rectangles and want to fill them.
I think that is exactly where programmers get it.
I mean, that's where I got it.
I can't even tell you how many, I mean, you could see it down here, but I can't tell you how many UIs I've made where I've had
the big horizontal color bars separating sections.
It was maybe only fairly recently that I realized I was doing this and that it always looked bad.
02:02:10Yeah. I don't actually know EaseOut. If you're OK answering, do you work as a front-end developer? Because I know that you have a very solid knowledge of CSS. And so that tells me you've done at least some front end. But are you specifically focused there? And for anybody who doesn't know, ease out is why Lobsters has a dark mode and has done a bunch of other CSS fixes. Maybe they tabbed away. It is the American Workday right now.
...50So then, you know, usual reminder that this is office hours. We can talk about anything on the site of the code base. And then otherwise, I will be coding. And it's last session I started in on avatars.
02:03:16Oh, right.
goreng oh, whats wrong with checkout?
I'm trying to force myself to stop using Checkout and start using Switch, and so I un-aliased C, and I keep getting these...
There we go, I named it Avatar, finally.
Only took four or five tries.
I am just struggling to lose the muscle memory of the old one.
All right, so on Avatars,
we have been working out allowing people to what's wrong with checkout checkout on git is mildly discouraged because it does two very different things and they make sense in the git data model but they don't help you they well they have foot guns but i'm gonna say there's a nice article about this
02:04:23I'm not immediately seeing the one I remember.
Git checkout makes it really easy to clobber your files.
So if you want to retrieve an old version of a file, you have to use checkout.
And if you say git checkout and you have a branch similar to your file names, you can clobber them.
Maybe it was this.
So checkout let you switch branches and then also switch what revision of a file you have.
And it is weird that the two of those things go together unless you are thinking about the Git data model instead of the task you want to do.
goreng Ah
Or another way to put it is they make sense for the implementer, they don't make sense for the user.
And so I have been trying to, most all Git tutorials have switched over to, they may mention checkout, but they talk about, well, we're just going to use switch to move between branches and we're just going to use restore to get back old files.
And so I have been slowly nudging myself over the last, what, two months to use the current version.
goreng Im a magit (emacs git thingy) user, so im not sure if they use checkout / switch for switching branch
And you know, if I don't jump over to Jujutsu, which I still have a tab open for somewhere.
02:06:05All right. Oh yeah, Megid is quite nice. I mean, under the hood, Switch and Checkout do the same thing. This is just, does the user interface make sense or not? And since I almost never could remember the order of arguments for using git checkout to get back old versions of files, I could probably change my alias, that C alias. I could probably just change that to say git switch and have no hassle, but I'm trying to force myself to change because I occasionally explain git to junior developers and I want to explain the thing that they should be using. And so that has to be my default. And so if I'm like, oh yeah, You just use git checkout. Well, then I'm teaching them the old thing, and none of the docs are going to match, and maybe they'll put gun themselves. So that's why I'm forcing myself to use the new one. All right. So I've been working through a bunch of stuff on avatars. I got to mute and sneeze a second.
02:07:29ah the worst it tickled and i never sneezed you know i've seen people talk about like you know modern inconvenience curses and the the funniest one of those is you know cursing someone to feel like they have to sneeze but never be able to sneeze the cat's up on the desk so he's doing it to me so i've set up active storage
added a field to the settings and can upload a photo.
Folks on Monday did a great job of coming up with corner cases and surprises, which is nice.
Anytime you are going to take big blobs of binary data from users, you really want to be very deliberate about your uses and your edge cases.
So I appreciate that a lot.
And we're just gonna kinda clunk along through the to-do list.
If you have any questions about stuff, feel free to pipe up and interrupt.
Let's see where I'm at.
All right, I don't need that browser anymore.
Let's go look at the UI.
Yeah, so here's that new field.
And if I were to browse and add, I've been working with a,
espartapalma sneeze you said? https://tapas.io/episode/322712… - easy comic strip about it
cat photo hasn't shown up on stream yet because we haven't gotten that far but at some point here all right so browse save comic strip about sneezing all right i'll buy it what do we got
02:09:25espartapalma it's SFW
I'm getting a warning about Internet Explorer.
It was just over on Hacker News this morning, and someone was griping about browser detection.
I don't think this site likes people to have privacy.
I've got Adblock installed, and I see the number is leapt up to 50.
Yeah.
All right.
goreng So I just checked out lobster and read the "about" page. So is it similar to HN with better users?
So whatever...
espartapalma https://mastodon.social/@MrLove…
user info they want to sell, their JavaScript broke.
Too bad.
Oh, well, thanks for checking out lobsters.
espartapalma perhaps in mastodon ads-free
There is something worth pointing out on the About page that is maybe a sentence you missed.
02:10:22We have invitations to slow down registrations to a pace we can acculturate. not to make the Lobster's user base an elite club. So I try and step on anybody who says, oh, we're better or think we're better. Because honestly, the things that make the Lobster's community different and in some ways better are not the people. A lot of it is we're a little more focused and we have a much, much smaller scale. So many problems for communities come out of being huge. Oh, I like this artist. I've seen a lot of their stuff. This might even be what I'm thinking of for the curse. Thank you. The other part of it is lobsters are just doing its own thing. It's not about winning, losing, or beating. We did sort of... David Price- lobsters is. David Price- sort of a fork from. David Price- hacker news. David Price- I was I don't know if you were on the stream then but. David Price- I was talking a bunch earlier about our commitment to transparency, it was really foundational to the site, because the site creator jcs was shadow banned from hacker news for. Can't even remember if he disagreed with Paul Graham or just pointed out that Paul Graham was visibly wrong about something and got shadow banned for that. Not a great mod experience.
02:12:16anshulxyz this is why I am still not on lobsters but still have been visiting it for years, signal to noise ratio is so much higher
All right.
All right.
So where we left off last time was active storage is very Rails-y.
goreng I see. just saw the user tree and its cool! sorry for interupting btw
Ah, well, I appreciate you visiting, Anshul.
...39No, no, you're fine interrupting.
So I do these streams partly because it's fun, but also I thought that having office hours where we just were okay talking about lobsters would be...
useful to the community and to new users because if you want to talk about like how does lobsters think of itself what are you going to do like post a meta thread to the site well i mean you can't do that if you're not a user but then also it can become a giant complicated free-for-all i don't know just trying to make sure that also that mods don't appear to be like the gods up on mount olympus occasionally throwing thunderbolts
I am just a guy.
I will talk through my thinking on all of this stuff.
Asking a question is not a public call out.
We're just having a conversation.
So last time we were looking at active storage and it is so, so railsy where you just take bad data and you persist it and then later you figure out you shouldn't have persisted it in a nutshell.
And what I would really like, it's also a very general tool.
So we take these avatars and we want to make variants to the sizes we care about and use using ease outs, very expert knowledge of iPhone zoom sizes or DPI sizes.
and boy i hope that background noise doesn't come through too bad one of the things about living in the city is like okay so there are like 20 or 30 apartments around me and if you remodel an apartment every 20 or 30 years that means every year an apartment next door is getting remodeled and i hear some of that construction noise
goreng woah that font is wild
And the specific noise that just went by and knocked all the thoughts out of my head was those particular folks have stolen a shopping cart from Home Depot, and they load it up with heavy stuff, and they drag heavy things up and down, like construction materials, to their unit.
And it's so fucking loud.
Yeah, the font, there's a FAQ for this stream linked underneath the stream, assuming you're looking at the Twitch website.
The font is in Consolata for the Roman, and for the italic, it is Operator Sans Mono.
There are links to both.
Although Operator Sans Mono is like 300 bucks.
It's so worth it.
I don't know.
I figure if I'm going to stare at something like eight hours a day for the next 20 years, maybe it should, you know, be attractive.
So...
We would like the uploads to be immediately resized to these six different sizes.
And then I almost want to just throw away the original, because at that point afterwards, the original is like untrusted user data.
And more than being untrusted,
it's it's a little dangerous like number one we can't i know with nginx we were able to enforce a size that was the last thing we finished last stream but the dimensions could be all weird and there could be exif metadata that we don't want to leak in the original and we're going to make sure the variants clean that up that's one of the to-do list items
But I don't know that there's a way I can... Yeah.
Is there a code way to prohibit using the original image?
Speaking of foot guns, that's kind of a theme for this episode.
One of the things I learned working in a big code base with many hundreds of coders at Stripe was...
It is not enough to have an API that you can use correctly.
You also need to make it impossible to use incorrectly.
So if the original user image is going to hang around as this little time bomb, there needs to be a way for us to make sure that I can never accidentally call it.
And at the same time, I don't want to just throw it away, but it's sort of a...
It's sort of a toxic waste because you can only misuse it.
Like if I show the original, am I leaking the excess?
I don't know.
You don't have to think about that one.
So let's start with...
02:18:15Speaking of realty things, let's start with making sure that all of the variants get produced. And it's odd here because I've uploaded the file, and there is only one file in storage, so I know we're in a pretty good spot. These other directories are. I've uploaded and deleted the file a few times, and every time it gets another random file name, so that's fine.
...56So if I grab the attachment, that's this object.
02:19:06So if I said dot representation. No, do I say it on avatar? What kind of sorting these out? Oh, okay. So I did call it. It's just the number of arguments. So I don't want to pass this resize to limit. I want to use the variants. So I called them for what they are for scaling. We use one inline on text on the comment headers, and we use one on the profile page. So if I say, yeah, that doesn't get us anything.
02:20:01Too many dots. All right, so I'm not guessing the API. How do we access these variants?
...18You can call avatar.variant. Isn't that exactly what I tried? Oh no, I tried plural. okay so i've gotten back a blob and this key is that the same one i saw before ak 2k yeah all right so that's that's the key for the original upload and it knows that i want to transform it so i could pass that to an image tag So has it already done it? Everything is so lazy that I can't. Storage. Yeah, so it hasn't actually done it.
02:21:27Whoa. So I tried to call the image tag helper.
...40Can't resolve asset type.
...47Does it not know that it is attached to the user model?
...57That's not great. I'm very close to like the exact example in the docs of i called my i am on the user model and i am attaching an avatar so this is one of those places where if you spot the bug before i do you get to be a channel vip and the bug here is that i'm not actually like this code pretty exactly is not running Let's see if it's really picky about its environment in some way. I don't think so. I think I'm going to get the same error, but if I take this, let's just update the user profile, right? Because I'm going to update it at some point anyways. So here, instead of using the old service, I'm going to have to rename that class.
02:23:18I'm calling that. All right, so let's just say. All right, show me cats.
...47And define method user, right, because at this point it's showing user is our instance variable.
02:24:01Keep that over here.
...09So I got an image tag, but not a good one. I honestly expected I was going to get the same error. So it generated a URL, called it a representation. Huh, it remembers the file name, twocats.jpg. That's a problem. We don't want to...
...42We don't want to include the file name of the original upload because I don't know if someone puts an image in there. I guess it's doing that. I mean, I got a 404 anyways, but it didn't try to print anything. So what if I just said an image tag for the avatar without a variant?
02:25:18Okay, we would get two cats. All right, so something is wired up correctly. I'm genuinely surprised. It works here in a view, but it doesn't when I call it from the console. And I said helper image tag avatar. Avatar. I'm doing basically the same call, but it's broken in the console. I didn't start that console before I switched branches or something, right?
...57Yeah. That's frustrating. I was hoping for really quick feedback in the console. Even though I loaded that, yeah. So I bet if I was to inspect this, I would get all the... metadata that I want to strip out because it's just showing me the original uploaded file. I really dislike how easy it is to use unsafe data like that. Rails doesn't force me to clean it or validate it. That's very Rails.
02:26:53So let's say, let's go back to this. Say I want to see the variant for the profile.
02:27:05Let's go look at the Rails server output too. Ooh, big exception over here. Hold on.
...20Cannot load, oh, is it just literally that I don't have the gem? Oh, I switched branches and I didn't bounce the real server.
...35Let's make sure I got that.
Bundle, yup.
I'll restart that.
goreng its 11.30 PM here & time to sleep. Hope can catch next week monday stream o7
So I used to have, when I used tmux, I had muscle memory for only ever switch branches
in the first terminal, which would force me to stop and start the Rails server.
Yeah, Guring, you must be, what, very far east of me.
So, hello, hope to see you Monday.
Monday I stream in my afternoon, so that may be your morning or it may be very late for you.
Either way, hope to see you again.
Now can I reload?
02:28:30There we go. Look at those beautiful cats. That feels like enough success that we can dwell on the cats. So this is pretty much what my desk setup looks like now. Although I have a different keyboard. Excellent. And at the moment, I only have one of those two cats laying on the desk, pushing the mouse around with his butt. So did that. What I'm hoping to see is that, oh, good, look. All right, so the important thing here is that generated and cached a variant.
02:29:27And it is a variant that copied over all the metadata from the original. I understand why Rails does that, but that is such an unsafe default. It also did not... So we told it we wanted a square photo and we got back a rectangular one still. I was assuming that My background was the same as the bars on it, that's not great. So we've got to tweak the variant and force it to be, was it resize to limit? We talked about how there are various resize to limit, resize to fill. And I believe it was spartapalma. Man, I'm sorry. I've been butchering your name for a while. Was it resize to fit or resize to fill? Resize to fill. Yes.
02:30:54espartapalma me? you can call me esparta, it's spell like the 300s fame
I should generate a new image.
I wonder if it dropped that.
02:31:03espartapalma yeap
Esparta?
...11espartapalma this.is. SPARTA
Are you saying Esparta or Esparta?
Oh, here we go.
Yeah, I think if this is...
...27So what does the Palma part mean?
espartapalma last name
Because as I recall from the movie,
Shouldn't you be spartakick?
Oh, it's your last name.
Yeah, because there was the big horse kick that came after, not a palm to the face.
Speaking of being railsy, so I updated that code, and the old variant is just abandoned here.
chamlis_ surprised it doesn't strip the metadata by default
Got the new file.
And then I bet if I look at that, that's going to have the correct dimensions, three 84 square.
Yes.
espartapalma yeah... that's actually my real name... I got it way before the 300s movie came along
Good.
And if you don't upload a square image, I am totally fine.
Like you get whatever crop comes out of the software.
Oh, you had it before the 300 movie came along.
Yeah.
There's a, you know, along those lines.
So my username has been push CX for a while.
there are some i think it's like a marketing thing i haven't seen it for a year or two now so maybe it faded out but people were trying to start you know how people talk about like user ui versus ux user interface versus user experience and then that kind of hybridized over to well let's talk about developer experience because
Mostly because developers are so allergic to being marketed to that if you admit you're doing it, they get all touchy.
But if you call it developer experience, it feels like being catered to instead of marketed to.
And then the next step that came along was customer experience.
And I was like, that's user.
That's the same thing as UX.
chamlis_ they're the ones that suck?
espartapalma exactly
then people talked about well we really want to push cx we want to push customer experience but then push cx oh that's my name arg so painful we had a a much bigger one i think we've talked about it when you were on they're the ones that suck yep that's exactly where i was going so if you go to
about hound Michael Bolton.
chamlis_ oh lol
Speaking of people who suck, we named the site Lobsters more than a dozen years ago.
And then a half a dozen years after we started, there's that self-help guy whose fans started calling themselves Lobsters because he doesn't know how evolution works.
And so now people come by the site and they're like, wait, is this a big Jordan Peterson fan club?
He kind of went away for years.
I understand he had very serious drug addiction issues that I am not going to make light of.
That kind of thing is especially tragic.
And I thought that was going to be the end of him.
And after like five more years, I'd be able to remove this.
But then he seems to have gotten it back together and is trying to make headlines again.
So I'm just never going to be able to get rid of this disambiguation.
I should probably put it in the Twitch thing.
Who knows how many people come by and see the stream and are like, lobsters, wait a minute.
That's that ooky guy.
All right.
So I've got a basic showing the variance.
I'm going to build this up to show it.
like an image with a source set.
But I just wanted to see how to access it, because you know what?
I'm going to blow it away.
So where I'm going is I'm trying to figure out, oh, don't give me a giant exception.
I thought I just made that delete work.
Wow, active storage chips with a N plus one?
That's irritating.
02:36:17I wonder if that's... I wonder if somebody else has... reported that bug because prosopite is moderately popular no active space storage now i'm gonna have to report that bug well not bug but opportunity
02:37:10So I'm just going to have to update the settings controller.
...21So I'm kind of groaning because active storage is so integrated into the active record object cycle that I don't have a separate line about updating the avatar here. There's just If all this stuff happens, where are we? We call edit user dot update, and that's triggering all of this. And I don't want to like wrap prosopite around all of this because if other parts of updating a user are triggering n plus one queries, I want to know about it. I don't want to silence all of these. So maybe this is the other way that prosopite should just allow n plus one queries if they're raised from active storage. Because otherwise, I don't know how to catch that. Rails makes a lot of things easy and then occasionally you just come drive into one of these tar pits where the auto magic stuff you have to layer on things like n plus one detection and the way there's just a rails world talk from the person who put a lot of work into Well, one of the people who put a lot of work into the improvements for SQLite. And he was like, oh, it's great. One of the neat things about SQLite is you don't have to worry about n plus one queries because you don't have the latency of going and talking to a remote database. So you don't get hammered alive by the overhead. And in fact, SQLite recommends that rather than do some big, broad, complicated join, just 1 plus n query the heck out of it, because it's going to be unmapped into your process space anyways. Which is fine for SQLite, but the way Rails is leaning on SQLite so much, I think it means that all the n plus 1 stuff is going to get worse, not better. Yeah. All right.
02:40:14What's that?
...30chamlis_ fwiw I think it's `saver: { strip: true }` to get vips to strip metadata, but not sure it that preserves orientation
oh shameless that's really nice let me take a look at that
02:41:05This is such a specific thing. I almost want to say, have a second code path that detects, are we deleting the avatar?
...36That's a pretty big change. Let's run the suite.
...49Yeah. Oh, I don't want to break the settings page.
02:42:03Oh, and this is all can't build URI. This is something about the testing I'm doing on the user profile.
...16Let's just comment that out for a second and see where the test suite is at. Because if that's all of it, great.
...31Yeah, so it's just the test that we're showing the profile. It's mad about some view thing. So my code change was actually safe. That's great.
...46That's weird that it would... Oh, the code, I get it. So this little manual debugging thing assumed that I would have a profile image And lots of the, I mean, none of the test users will. So like if I loaded my profile right now, I would get, it'd be fine because I haven't saved, but all right. So that needs to, that'll get wrapped up in the new helper.
02:43:28All right, so where I was going with this was I want to make sure storage doesn't have any files in it. Oh, it did get that one extra variant. That's interesting. And then I want to...
...52I want to add back that profile photo. And I want to have some way in the console of generating my variants in the update action. And I know it'll make the updates slower, but that's a really slow on common code path. And I want to do it explicitly once at upload as opposed to lazily in the background whenever somebody next loads a page that has your comment on it i don't like that i don't like that race and not knowing when it's going to happen all right so avatar dot I wonder if that console error I was getting was because I didn't have the image processing gem. Oh, it was. Good. Okay. So does just accessing it create? No. Nil URL. What's the... So what do we think... The image tag is called to pair. Really, that's a useful to pair. What do we think that image tag is calling on this to generate it?
02:45:51Oh, I didn't mean ls. See, I keep seeing these selects go by, but I'm not seeing inserts. So it's not really there.
02:46:23content type for serving like is it calling dot image like the worst case scenario here is that it's somewhere deep in rails magic and rails will not generate it or will not expose an api for me to force what if i called the helper back to this can't resolve image into url undefined method polymorphic url
02:47:26So I can't quite inspect what image help tag is doing, and I can't just call it.
...43I guess more broadly here, the downside of Rails magic is when the magic doesn't do the thing you want, you're in trouble.
02:48:05So you know I want the variant. You know I want it to be an image.
...17You're generating me the file name, which I don't want you generating.
...27Whoa, there we go. It was processed. So I'm literally just going through everything. If you know in advance, you can specify, ah, there we go. And now that I know the name of it, I turn up the documentation. Always the way.
02:49:07All right, let's see. So let's reattach my image.
...34Okay, we've uploaded. And now if I go look in storage,
...49excellent so i have my one image whichever one of these it is and then my six variants good so i don't have to worry about when is that going to happen good good good all right so I feel like we have handled strip off and force max dimensions and then wasn't there something else that covered how does rails handle non square images we've handled this
02:50:33I'm not losing anything. That documentation link is still in last stream's notes. So now let's look at Shamless's advice. Where do we stick that saver?
...54I'm sure not putting it in the image tag.
chamlis_ in the variant definition I think
But the way we see these
arguments matching this i think i can put it here in the definition yeah so let's say saver i don't really care how it interpolates script true come here give me all of this
02:51:38espartapalma stripe is a company :D
chamlis_ s/stripe/strip
espartapalma not the verb
espartapalma hahahah
stripe is a company yes oh well it shows that i worked there yes it's a typo i've now been making i have not worked at stripe for more than 18 months and i still am making that typo the other one that gets me oh i had a what was it even after i left stripe
They would come up in conversation because like anytime you buy something online, that is probably Stripe.
And so I would explain stuff to people and I would constantly, even after I left, I kept saying we.
Like, oh, we process the credit card by blah, blah.
We talk to your bank.
And then people would be like, Peter, you don't work there anymore.
No, God damn it.
became a running joke with my friends of like i will give you a dollar if you catch me saying we instead of they oh god it took it took like months before i wasn't doing it constantly and then i think the last time i did it was somewhere over the summer here and i was like oh i was doing so well yeah it's one of the jobs i was at the longest though
chamlis_ what'd be the worst company to work for and get semantically saturated on the name of
So I feel a little justified.
We're going to cycle again.
We're going to delete that.
Actually, can I just call?
Oh, I don't have the console up.
02:53:21The worst company to work for and get semantically saturated on the name of. That's a good one. The one that drives me up the wall. Why am I still getting this? Because it's doing the JavaScript replacement that's not hitting this. Yeah. Oh, it's a separate. I made a separate controller. I don't have to shove this in here. I want to keep the dot attributes because I like being explicit about that. But I made an avatars controller. I forgot. So here. Where are we?
02:54:07retype that there we go all right all right my pet peeve is go the programming language from google it was created so that they could have the go ogle pun or it was named so they could have the go ogle pun for their internal search engine. And it's very cute, but it just wrecks me to see one of the 50 most common words in the English language used in the wrong part of speech to turn a verb into a noun. It took me, I don't know, 10 years to stop stumbling over it. so you know someone would say oh i write go code and i would have to stop and back up and read that sentence again oh forever i have been sorely tempted to rename our tag from go to golang but that would be like just my personal peak and i try not to there is a limited amount of that kind of like Easter egg slash peak that I will slip into the code base, but only on new stuff. I don't want to break things for it. And so instead it's in the search engine. If you search for go, you will get me griping. So if we search the comments for
02:56:01We parsed your search query.
One and two character terms are not indexed.
For the terribly named language, use tag go.
Whereas if you search for D, which is another language with a name that's too short, it just says for the language.
That's it.
That's my Easter egg.
My one little gripe.
chamlis_ I think about some sister site focusing on classic board games hitting this easter egg
Don't use verbs as nouns like that.
Ugh.
All right.
so i fixed that n plus one well i patched out that n plus one in a way i'm much happier about and then we have all those and now i've did i finish re-uploading yes so now if i tree storage we have a new seven files how am i gonna
02:57:10All right, so I'm just running the file command on all of them.
So this is pretty much what I wanted.
Yeah, so orientation could still be an issue.
Well, for JPEGs.
But on the other hand, now all of these variants don't have the other one.
You can think about some sister site focusing on classic board games hitting this Easter egg.
Yeah.
Yeah, that's true.
Oh man.
I would, if somebody started a board game sister site for lobsters, I would be one of the first signups.
I'm a big fan of board games.
I used to run a website called nearby gamers.com.
That was a,
just an introduction service for if you would like to play board games and you don't know someone in your area, you can make a profile and meet someone.
You know, the other way to say it would be it's like dating for finding gaming groups.
It was really rewarding to run that.
It was the first big Rails app I ever made.
And...
I struggled to maintain it because the upgrades for Rails 2 and Rails 3 and Rails 4 were huge.
They were a lot of work.
And board gaming, at least in the States, is mostly the hobby of, or at the time, was mostly the hobby of students and other broke people.
Settlers of Catan was growing in popularity, but I don't know that even now I would say that lots of people play board games generally.
So it was just like, all right, it's a niche activity, but it's a hobby for folks who don't have money.
And I don't want to like try and rip off local gaming stores.
It couldn't be monetarily rewarding enough that I could keep putting time and energy into it.
So I'm trying to check off this box here for stripping orientation.
I wonder if I could say on this one, can I put a saver just directly?
Because if I can start putting arguments there, that'll make me happier.
chamlis_ vips has https://www.libvips.org/API/cur… but not sure if the ruby exposes that
Why am I still getting this error?
Unknown keyword saver.
I thought this was the one placenta at first.
All right, so no.
Unfortunately.
03:00:25So it's vips image map. Oh, I see.
...43This looks like it's just a traversal method, though.
chamlis_ there's a delete slightly further up
I think maybe I'm OK with keeping the attachment as their original upload.
even though it's going to have toxic waste in it.
And by toxic waste, I mean that metadata.
03:01:09Oh, there's a delete. The other one, the place to go look if you are feeling spry about researching would be the image processing gem.
...39chamlis_ I was a couple of gem githubs deep
chamlis_ oh whoops
is this saver undocumented basically like there's one mention here how did you find saver shameless a couple of gem githubs deep yeah it's here on the readme for
Add an instrumenter.
So I would bet that this saver thing just gets passed down.
Because I can see where operations is that other section.
And then I saw, yeah, vips.
So it's kind of highlighting here what's getting passed down into vips.
So we'll just forward to write to file.
03:02:55chamlis_ there's https://github.com/janko/image_… but you'd have to manually remove the keys
And you can give options as a hash.
Where's a list of all the options?
03:03:22That is not the right options. If I search for stripe. See, I typed stripe again.
...39Yeah.
chamlis_ not sure if you can iterate them (don't know that ruby syntax)
I think it's all or nothing.
...50The other thing to do, well, no, I can't.
Add arbitrary code.
Yeah, iterate would be fine.
But even if I iterate and grab the option of if it has a JPEG orientation, persist that, strip, how would I write it back?
Because the saver, by the time it's done, I don't have a way of apply.
I guess this builder does.
chamlis_ oh I was thinking drop the strip, then manually remove all the metadata that isn't orientation
chamlis_ yeah fair
I don't know, at this point, I'm just getting to, if you upload a JPEG with an orientation, it's just gonna be fucky.
I think I'm okay with that enough for a V1.
Drop the strip and then manually remove.
Oh.
Yeah, since this is sensitive,
I really, when writing sensitive stuff, try and do a universal operation like wipe it all rather than a whitelist or allow list, deny list kind of thing.
03:05:14chamlis_ the awful solution is to correct the orientation in css
I'm also not seeing a way to insert metadata.
...26Corrected in CSS. Oh, man. That is a delightfully awful approach. Thank you. I appreciate the creativity. I won't do it, but I will appreciate it. You know, I will admire it from a safe distance, like a demolition derby.
...51chamlis_ high praise
All right.
So I'm going to check this because I want to add a check.
But high praise.
I think programming can be fun.
I think it can be a lot more fun than we sometimes let it be.
03:06:19I wonder if vips.
I wonder if Vips just handles it.
I mean, if you were Vips and you were stripping out... Let me put it a different way.
Vips is already seriously rewriting the file to generate a new output image.
Why would it carry over JPEG orientation from the input to output if it's writing the output from scratch?
and presumably always has the option of outputting the image in its preferred orientation.
I mean, they might be doing something really clever where they only ever want to take the...
They only want to traverse the image once in the order they've done it, I guess is what I'm saying.
Does that make sense?
Sorry, off-screen, I'm trying to do something.
And every time I do that, my talking just becomes absolute nonsense.
chamlis_ I think you have to opt into that, but well predicted https://www.libvips.org/API/cur…
I'm pulling up the image editor, and I'm looking at my two cats image, because especially an image where I'm looking straight down.
All right.
03:07:52chamlis_ and image_processing calls it!
You'd think I'd have to opt into that, but there's auto rotate, and image processing calls it A.
So that sure sounds like we get it for free.
03:08:08Output the image was rotated by. VIP's meta orientation tag is removed from out to prevent accidental double. And then you're saying this guy, did you see ya?
...28chamlis_ https://github.com/janko/image_…
So an additional auto rotate option is accepted to specify.
Oh, you found it directly in the code.
Oh, that's great.
...50OK, so I think we get this for free. I would really love to. shove in an image i knew had rotation in jpeg but i don't offhand so i'm looking at the two cats image off screen i'm trying to pull up the metadata and i'm being careful about it because the metadata might have like gps in it blah blah even though that's not my apartment anymore yeah just easier
03:09:36so i don't want to write i just want to read so xf tool is a my go-to for finding metadata I just want to grab the orientation tag out of a few images to see if I can find one that has rotation on it.
03:10:24So I can say exiftool-Orientation.
...45Sorry to do so much off screen, but you know, so it goes.
...54All right.
utkarshg1 Wait Ruby on rails is still used ? LUL LUL
So yeah, the, inconveniently the two cats image does not have, okay.
I have one image in my home directory that has orientation.
I don't know which one.
If I extract on this image, what is it?
03:11:29All right, so is this something I can show on screen, or is it like a picture of someone I care about?
It is a picture of a box.
OK, we can bring that on screen.
So I have a picture of a, it looks like the back of a webcam.
Let's upload that as my image.
And it is rotated 90 degrees clockwise.
Hi, Utah.
utkarshg1 Hi you can call me Karsh for simplicity
I'm not going to pronounce that name.
That's, that's not enough vowels for me to say it.
Hello, you.
utkarshg1 Cool
ut you can tell me if you have a preferred short way karsh okay hi karsh yep rails is still used the site is actually about 12 years old still going strong so all right we are going to upload the photo of a webcam box and see what we get out
03:12:45So there's that.
Let's go look in the storage now.
So we got all these different files.
And if I say it has no orientation data, and if I look at it,
Hey, you were right, Chambliss.
So here's the back of a webcam box and the output image is correctly oriented.
So we have solved the issue.
chamlis_ well you guessed it first; nice
Specifically, you have solved the issue by figuring out that saver with strip.
And then otherwise we get
Well, yeah, I just guessed that Rails was maybe, I mean, as long as I'm whining about all the Rails magic, it occurred to me, maybe there's also Rails magic that'll do the thing I want.
This one I gotta put at the end.
I'm gonna think about that one and see the API some more.
So good progress here.
All right, so we don't wanna leak the file name of the original upload.
So I'm betting I'm gonna have to just overwrite that.
Like in the settings controller.
Up here.
03:14:18Let's play with it in the console.
...29Grab my avatar. So there's a file name. And so this one. It's not 2CAD's JPEG anymore, but that's the name of the file I uploaded that was the rotation test. Before I spend too much time here, file name. Just figured maybe I should just double check real quick. Is there something about the file name here? So you can say images, attach, and specify a file name. But I'm not calling attach. I'm just doing the attributes attachment.
03:15:27It's a little odd that it's here instead of something I'm specifying as I'm declaring the avatar. Yeah. I mean, I could probably put file names in all of these, right? So what if I said here that I'm changing the file name to be, just name it after the user. So that's there, save. So now the real question is, did that update all of the variants or not?
03:16:15It did. Look at that.
...23Huh.
That's an odd one.
Oh, I know what this is.
This must be the config is running in Rails config.
chamlis_ old filename in error msg?
When you are in the console, a couple of the config files don't quite load, so it's possible to not have some of these set.
But we did set these, so that's fine.
Old file name in the error message, is there?
...59Yeah, I don't really care if the old file name is there as long as, well, if it's possible for it to get used, it's there to get used. Yeah, I really would love to call the image tag helper, but I can't. So I guess I got to do it up in the view, right? I mean, seeing is believing. So let's go back to the user show.
03:17:49Here we go. Let's reload. i should see that nice green wi-fi box and i do and the yeah it's not present it got renamed to pushcx jpeg so i don't know where let's go look in the database it's going to be in here somewhere right so They're going to be wide, aren't you?
03:18:32OK. So it calls them different variant records. Let's just grab everything.
...50So it pulled some metadata out. Oh, that's interesting. So yeah, for the variance, it is just doing that. So let's, what if I try and put a file name in here? Is it an option it'll take? But what I really would like to do is interpolate
03:19:26Okay, not interpolating as long as I get something to overwrite that data. Because my concern there is that if I store it in the database, eventually I can burp it out. I just never want to store it. We talked about story disowning and comment disowning early. the way that code works is it just overwrites the field. because you can't accidentally burp up the old data if you don't have it.
03:20:18And if this works, I'm going to. OK. If it works, I'm going to update the update controller to overwrite the file name on the master one huh i got the jpeg but i didn't get all the it didn't see that it didn't make my variants adding that file name broke something all right
03:21:07so it doesn't like me doing that all right
03:22:05Donate present.
...22Oh, that feels so unsafe. So I want to say username. but I know I just smashed username with the form input and Rails works by taking everything and saving it to the model and then later figuring out if it's invalid. And I really, oh, it just raises the hair on the back of my neck to say, oh yeah, we're just gonna take this file name from untrusted user input. Even knowing that file name is a database attribute rather than the actual file name on disk it just uncomfortable yeah i'm gonna like it's tacky but i'm gonna save it and then i'll loop through and update all of them and then i'll save it again if it changed because It's just I need a file type, don't I? How do I get its extension?
03:23:49I deleted the thing because I was getting ready for a test here.
03:24:01Okay. All right. Did I have a way of looping the variance? Can I say all?
03:25:24This is just the alternate presentation of the exact same thing I was on, isn't it? Yeah. This is the individual variant objects as opposed to the parent object.
...53What's the What does it call the class? Calls it an attached.
03:26:11How do I ask you about all your variants? Come on, Ruby, you're an introvert. You're introspective.
...24Oh, yeah, I have to tweak my presence method there. There's no list. I can ask it for a specific named variant, but I can't get all of them? Where the heck is the variant method defined? Let's browse on GitHub.
...56This is just directly in here.
03:27:36I want to search all of Rails for the word variant.
...55Oh, I've searched too much. Oh, I've searched too much in a slightly different way. Thanks. Thanks, GitHub. How am I doing?
03:28:41Where's this come from? Oh, it's named reflection. That's positive. Reflecting is the thing I want to do.
...58So we can ask named variance.
03:29:14I'm not in a Rails console.
...22No, I cannot say. Where does the variant method come from if I can say variant but not named variants? And the method is right there. Did I typo? No.
...49I don't even see variant listed as a method I can call. So there's some kind of clever metaprogramming going on.
03:30:00And that's it.
...14Where does transformation come from? Who knows? Yeah.
...31So this doesn't even import from variant. It must delegate somehow. Representable?
...45Oh, it has a separate implementation of it in the abstract class.
...58I'll definitely be calling that preloader. Let's put that in the notes at some point here.
03:31:16Includes, we say dot variant underscore records. There we go.
...30chamlis_ have to head off, thanks for the stream!
I'm getting back a variant record instead of an attachment blob.
So I'm operating at the wrong level of abstraction here somehow.
...47Yeah, Shamless, take care. Thanks very much for coming by. I've appreciated your help today. You really were helpful for digging into image processing. bips so thanks very much congrats on being a channel vip i hope you didn't or they didn't immediately close the window and miss that i'll put it in the put it in my scratch
03:32:32All right, looking good.
...50So what I really want to do is loop all the blobs.
03:33:00I don't know how to... Maybe I do. I do know how to get the blob. This is such brittle coupling. OK. OK, so I'm seeing the data I want. And we are just going to break the law of Demeter.
...45Come here.
03:34:00I've been juggling so many things I lost track. Variant records.
...20And then can I get it the variant name? Because I'd like to combine this so that if it knows the name,
...53The digest, does it have a... No. Does the blob know its name? Let's look at the blob. So this stuff is getting in here, because if it went over to the pager, the pager doesn't interpret the escape code's key. That could be a key. No, it's not a key.
03:35:42Yeah, I don't think this is going to be on the blob. I think it's going to be on the variant.
03:36:05What did it refer to? It didn't call it a noun. Facing future class. Hmm.
...40Look at the wrong thing. I'm looking at a collection instead of an individual. So an individual variant has all this stuff like blob, blob ID.
...58What I'm really looking for is some kind of name for the variant.
03:37:09I think it's model name, but that's, no, just that.
...17Because this is a, that's interesting. It's interesting that it's importing from active record. I didn't think this variant object was, I thought it was a blob that was the actual record that got saved.
03:38:00Attachable variant, huh?
...16So let's go to the source, right?
...23The first. None of these have the right. Arity.
...37Where I'm expecting a method that says, you know, name comma transformations.
03:39:10Ah, it is called a variant underscore name. OK. So we take that.
...52What do you do with your variant name? In named variants, you say fetch. Are you a hash?
03:40:26No.
...36This is going to be, I think, my last bit of code, and then I'll wind up the stream. So if you have any last questions, now is a good time to ask them. While I'm beating my thick head against this until it breaks.
03:41:38I guess we won't introspect on that so much. It's so weird. I don't know why it's such a struggle. It knows what all its variants are, but these are the database records rather than
03:42:12And that doesn't help the pager keeps fucking up the color. Terminals.
...38You have a name field.
...51So you know what you are. But you don't know what variants you have. Because the word does not appear here. There is so much metaprogramming going on in this thing. I don't know what it's doing.
03:43:58reflections man this is more magic than my tired brain can follow it doesn't really help that i can't nest vim sessions
03:44:52A TODO is like writing the code.
03:45:04That ought to do it. So I'm going to give this a quick test with my local user here. And if this works, I think I'm about ready to wind up the stream. So let's grab the two cats. Let's save. Let's go peek in the database.
...40And if I don't see the wrong file name, good. Cool. It saved none of them.
...57So the select's fired. So u.save, nothing happens. New avatar save. Again, nothing happens. So I see what I set. But if I reload the user, it persisted, did I not?
03:46:55It persisted this and I didn't see the insert.
03:47:05Oh, there it is. There's the update I missed. It was just the wrong color. I started looking for blue instead of yellow. So instead of calling all that, I will call And then we'll find out in a second if that actually saves the one or I've got to do all of them. Each need a save. Honestly, I don't believe either. The variants are sort of dependent and sort of not.
...50And then let's go select in the database.
...57Yeah, got to save each one. I guess I better save Bang, right? Nothing is checking.
03:48:29There we go. And are they all in the database, please? No, not at all. Fuck me.
...48Rails. Rails, I am trying to clean up after you. And you are just assuming that I want to keep all this data around instead of specify what it is.
03:49:08That's so painful.
...46Save bangs, they don't raise an exception, and they don't save.
...55That's all right. I think I'm just too tired to see something that's happening here. So that part's fine, but.
03:50:20We're going to put that on the to do list and call it.
All right.
espartapalma thank you!
Well, thank you to everybody who tuned into the stream today and is still present.
I hope to see you again on Monday afternoon, whatever time zone that is for you.
I appreciate the various kibitzings and researching.
Take care, Espart.
Don't let anybody kick you down a well.