Mid-day shots to boost your energy.
Recently I just completed Ruby2->Ruby3 + Rails6->Rails7 upgrade for my private project. Initially I thought it would
take a lot of fixing to make it work, but was surprised it only impacted 17 out of the 88 Ruby files out of the app/
directory. Since it was a relatively simple fix, I decided to just write a shot instead of a long article to document
my changes.
Recently I just completed Ruby2->Ruby3 + Rails6->Rails7 upgrade for my private project. Initially I thought it would
take a lot of fixing to make it work, but was surprised it only impacted 17 out of the 88 Ruby files out of the app/
directory. Since it was a relatively simple fix, I decided to just write a shot instead of a long article to document
my changes.
I have 27 gems before the upgrade. In order to use Rails7, I had to deprecate webpacker
and add the replacement gems:
This also removed a few JS packages related to webpacker:
While adding new ones to replace the missing webpacker package:
Then, I added a new webpack config file in order to compile my Vue2 assets:
Finally, I added new scripts in package.json
to allow me to build my assets:
That’s about all the configuration changes for the Rails7 upgrade.
Next there’re some syntax and API changes due to Ruby3 and Rails7. The list is non-exhaustive, because I might not have used many features that are impacted by the upgrade. I also omitted the ones where there’s deprecation warning and documented fix for it.
Previously, I could use ActiveRecord#serializable_hash
without any arguments and it will serialize additional
instance methods in the AR. For example, I have a User
with a #avatar
method:
I used to be able to serialize by invoking user.serializable_hash
. In Rails7, I had to explicitly pass in the
methods
argument: user.serializable_hash(methods: %i(avatar))
.
Previously, these lines of code worked.
In Rails7, I have to add the prepend: true
argument to protect_from_forgery
, so that it will prepend this method
to the before_action
chain.
The thing I haven’t figured out is why it didn’t work without prepend: true
, even though I have declared
protect_from_forgery
before authenticate_user!
.
This is the Github README of the devise gem explaining the problem above.
That’s about all the changes I had to make. I’m still observing if anything else is broken, if there’s something new, I will update this post again. Happy upgrading!
I needed to build a bi-directional indefinite progress bar for the Triple Tee App.
I needed to build a bi-directional indefinite progress bar for the Triple Tee App.
I found some tutorial on how to build a static uni-directional one on W3 Schools, so I improvised and tried to built one that is bi-directional and runs indefinitely like this:
(This progress bar is running in real-time, click here to stop the bar)
The idea I had was to use 2 <div>
s, 1 growing towards the right side, and the other growing towards the left side.
Let’s call them the forward-bar
and reverse-bar
respectively.
At the initial state, the forward-bar
will have 0% width and colored, while the reverse-bar
will have 100% width
but not colored:
Then, when the forward-bar
grows to 100% width, I append the .reverse
class to the progress-bar
container, so
that I can use it to style the forward-bar
and reverse-bar
in reverse colors:
In order to determine the current direction, I created a variable named direction
and initialised it to forward
.
We could also use a boolean forward
and set to true
, but I prefer to use string for clarity here.
Then I need to know what’s the current width of the bars, so I created a function for that:
Once I know the width, I can grow or shrink the bar by adding steps to the width:
When I step forward, I grow the width of the forward-bar
while shrinking the width of the reverse-bar
. In the other
direction, I reverse the action on the bars accordingly:
If the bar grows to the full 100% width, I will need to change the direction. This is also where I add the .reverse
class to the progress-bar
so that it will update the background color of individual bars:
Now we can put it all together in animation using the setInterval
function, so that it will grow/shrink the bar
every 10ms, creating the effect that it is moving:
That’s it! Hope this has been useful.
I released the installer for MacOS (arm64) distribution for the SG SSB Tracker app on Github Releases, and downloaded it to install the app, MacOS told me it’s damaged and should move it to the bin.
I released the installer for MacOS (arm64) distribution for the SG SSB Tracker app on Github Releases, and downloaded it to install the app, MacOS told me it’s damaged and should move it to the bin.
I tried installing the app locally from the installer packaged by Electron Forge, the app can open just fine.
After some search, I stumbled upon this thread on MarkText Github Issues. It seems like the issue is due to the app not being code signed, and so Apple blocked it from being opened? The only workaround is to remove the app from “Quarantine”, by running this command:
A quick look at the xattr
man page explains what the
command is actually doing:
xattr
is the command used to display or manipulate extended attributes of a file.-r
applies the command recursively to the file.-d
deletes a given attribute of the file.com.apple.quarantine
is the attribute that puts the app in “Quarantine”.On the other hand, if I build the app for x64 distribution, I can open the app on a arm64 Mac, this time it will still try to block me, but at least it allows me to “Open Anyway”.
Does that mean I have to pay USD99/year just to be able to sign a free app for distribution to Apple Silicon Mac users?
So the problem I encountered was this: I have a page that have 2 separate grid sections. Each section can have its own variable number of items. I want to display the items in a 3-column grid layout.
So the problem I encountered was this: I have a page that have 2 separate grid sections. Each section can have its own variable number of items. I want to display the items in a 3-column grid layout.
My first solution was taken from the web, and it’s something along this line.
But it turned out like this when I have 2 items in the second section:
Section 1
Section 2
Due to the auto
value for grid-template-columns
, when there’re only 2 items, it will stretch and fit the width of
the container.
So I thought I had to use math to calculate the width of each grid column, in order for the 2-item grid to only take up exactly 2 column-width.
It’s what I wanted, but there’s too much math going on.
Section 1
Section 2
Okay, then I read about this thing called fractional units (fr), so I thought what about I change to this:
Now this looks exactly like the previous one, without the complex calculation.
Section 1
Section 2
I drank a few cups of coffee to figure this out so you don’t have to. Enjoy this mid-day shot.
While building the SG Bank Interests Compare App, I faced a problem: “How can I serve JSON data API while hosting the app on Github Pages?”
While building the SG Bank Interests Compare App, I faced a problem: “How can I serve JSON data API while hosting the app on Github Pages?”
I forgot how I stumbled upon the idea, but eventually I decided to make use of Github itself as a pseudo-API server. Here’s how I executed it for my app.
But first, let’s talk a little bit about why Github is actually a pretty good candidate:
https://raw.githubusercontent.com/
domain.It’s screaming at me that: “Hey, I can actually be a pretty good versioned data API server!”
So I separated my app into 2 repositories:
sg_bank_int_compare-source
: This will host the source code, data files and build scripts.sg_bank_int_compare
: This will host the built page that can be served by Github Pages.For the sg_bank_int_compare-source
repo, I have both the page assets and the data JSON files.
Note: Omitted some files for clarity.
Then in the sg_bank_int_compare
repo, I further separate it into 2 branches:
main
: This is where the app index page and assets will be served.data
: This only contains the JSON data files.Whenever I make changes to the source, I will run a script that will checkout the data
branch in
sg_bank_int_compare
, then copy the data/*.json
files into the data
directory. If there are changes to the data,
it will create a new commit.
The script then reads this commit hash, and compare it with the current LATEST_VERSION
in the source file. If it’s
different, then it will replace it with the new commit hash.
And finally, the script will build the page and checkout the main
branch in sg_bank_int_compare
to create a commit.
Now when I push the data
branch to Github, I will be able to see the raw JSON files under
https://raw.githubusercontent.com/coffeebrewapps/sg_bank_int_compare/${LATEST_VERSION}/data/
. And then I push the
main
branch to Github, and it will be able to request for the JSON data from the same URL.
So, after reading so far, you might be thinking: “Why not just hardcode the data in a variable in JS and read directly?”
Yes, I did think about that question too, but I wanted to have a separation of “client” and “server”, so that in the future, if I do have the resource to host the data on an actual server, I don’t have to change a lot of my client code, and just have to update the API URLs.
I hope this little trick is useful for you too if you intend to build an app hosted on Github Pages that requires a data API but don’t have an actual server to serve it.