Category Archives: Development

Webdev Tip: ALWAYS Put the Record ID *in* the Edit Form

I started out this morning happy with my web host. They’d sent me an alert about disk usage that allowed me to catch an error that would have filled up all the available space on my VPS and taken down this site and several others, and I was able to fix it before that happened. That changed as I discovered what had actually set it up, as revealed by another, more pressing issue.

Background

A few months ago, my VPS did lock up, because I’d set up backups on a new site and forgot to add a cleanup script. Tech support brought the server back online, I cleared out the backups, and I copied the script over from this site.

But this site’s cleanup script stopped running, and it reached 90% usage. The script was there, but the cron job was somehow pointing to the other script. I figured I must have messed it up at the time, made sure it was correct now, and moved on.

Discovery

Later this afternoon, though, I discovered that a test blog I set up last week was pointing to the wrong site. That seemed really weird. I looked in the control panel and it was very neatly pointing to the other site’s folder. How does that happen?

Then I remembered: A few days ago, I’d reconfigured several sites to upgrade them to PHP 7.2. I’d opened them in multiple tabs to I could get them all at once. And I had this sinking feeling.

Sure enough: DreamHost’s control panel doesn’t put the form state in the page. As far as I can tell, the ID of the record you’re editing is stored in the session somewhere, which is fine if you only ever have one page open at a time, but if you open two pages, it gets confused.

That’s what probably happened a few days ago: I opened two forms, saved them both, and the settings for one site got written to the other. And it’s probably what happened a few months back with the cron jobs: I opened one to edit, the other for reference, and it overwrote the wrong one.

As near as I can tell it’s just the one site that got messed up, which is a relief. Even better that it’s the test site and not, say, this one. But I’m still waiting for the fixed config change to take effect.

Lesson

Always, always put the record ID for an edit form in the form. People will open multiple records in different tabs or windows, to compare them or just to speed up their workflow.

If you store it in session, or in a cookie, or anywhere else, you run a good chance of saving the data into the wrong record.

Groovy, null, and ‘null’

Groovy will let you call toString() on a null object. The result is the word ‘null’, which might be what you’re expecting if you know the object is null, but probably isn’t what you’re expecting if you don’t.

So if you’re, say, binding a SQL parameter and you forget to check for nulls like you would in Java, and you forget to use a null-safe operator like you should in Groovy, and you get a null value, what happens? Does groovy…

  1. Throw a NullPointerException like Java?
  2. Set the field to null?

Neither. It sets the field to the string ‘null’.

Make sure to use myVariable?.toString() instead of myVariable.toString() for cases like this!

Mobile: Design for Offline

I’ve written about the trouble with using mobile apps in dead zones before, so I’m happy to see that I’m not the only one thinking about the problem. Hoodie wants to design for offline first, and is starting a discussion project around the issue.

Offline reading is an obvious application. Most eBook readers handle that just fine, though it’s easy because you spend a lot of time in each book so it doesn’t need to predict what you’ll read next. It would be great if Feedly would sync new articles for offline reading. Heck, I’d like it if Chrome on Android would let me re-open recent pages when the connection dies.

Beyond reading, many actions can be handled offline too. Kindle will sync your notes and highlights. GMail will let you read, write, label, archive, delete, and even send messages without a network connection. All your actions are queued up for the next sync.

There’s no reason this approach can’t be taken with other communications apps for messages that don’t require an immediate response, even with services like Facebook and Twitter. Short notes of the “don’t forget to pick up milk” variety. Observations. Uploads to Dropbox. Photos going to Instagram or Flickr. Buffer would be perfect for this, since you’re not expecting the post to go out immediately in the first place. It shouldn’t give you an “Unable to buffer” error, it should just save it for later.

I’d like to be able to do work in a place where there’s no connection, have that work persist, and fire things off as I finish them instead of having to come back to all of them the next time I’m within range of a cell tower or a coffee shop with wifi. I’d also like to be able to post in the moment, hit “Send,” and move on with my life, instead of having to hang onto that extra context in my mind as I walk around.

First Stab at WordPress/MySQL Tuning

My job sent me to a class on scaling, optimizing and troubleshooting MySQL this week. I’ve been digging around a bit on some test databases at work, but of course as someone running a self-hosted WordPress blog, I had another MySQL server to practice on right here — one with real-world data and (admittedly low) load, but where I was only accountable to myself if I messed anything up.

Unfortunately, DreamHost’s MySQL VPS doesn’t give you much control over the server, and of course when you’re working with a third-party application, there’s only so much you can change the database without breaking compatibility. But I found some interesting surprises:

1: Everything was using the older MyISAM engine, because DreamHost is running an older version of MySQL that uses it as the default. Switching to the newer InnoDB (and back) is simple and safe enough that I figured it was worth a try.

2: There was a lot of junk left over from old plugins that I haven’t used in years. Continue reading

Dates and ColdFusion Query of Queries

Argh.

If you need to run any date comparisons on a ColdFusion Query of Queries, you need the following:

  • In the original database query, select the values as datetime. DO NOT cast them as date. (This is with MSSQL, anyway).
  • In the follow-up query, use CFQUERYPARAM and the cf_sql_date type.

I spent waaay too long trying to select subsets of the original query based on dates, and whether I selected them as strings (for implicit conversion) or using query parameters, I just couldn’t get any results out of them. It turned out that since the original query had cast the datetime value as a date, I couldn’t make any comparisons in the query of queries.

Once I removed that cast (originally there to simply group timestamps by day, but I’d since changed the query to group by month), it worked.

<cfquery name="realquery">
select mydate, mystuff from mytable
</cfquery>

<cfquery dbtype="query" name="followup">
select mystuff from mytable
where mydate = <cfsqlparam value="#somedate#"
                   cfsqltype="cf_sql_date" />
</cfquery>

Obviously this example is oversimplified, but you get the idea.