Compare commits
No commits in common. "9fb71ea6429d87de4b6bf8d0604a25b9f66daaed" and "f86b04eac4f0a360c49ecc21823e4a5c922e0a51" have entirely different histories.
9fb71ea642
...
f86b04eac4
32
.github/workflows/gh-pages.yml
vendored
Normal file
32
.github/workflows/gh-pages.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
name: github pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master # Set a branch to deploy
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: true # Fetch Hugo themes (true OR recursive)
|
||||||
|
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
|
||||||
|
|
||||||
|
- name: Setup Hugo
|
||||||
|
uses: peaceiris/actions-hugo@v2
|
||||||
|
with:
|
||||||
|
hugo-version: 'latest'
|
||||||
|
# extended: true
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: hugo --minify
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
if: github.ref == 'refs/heads/main'
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: ./public
|
4
.github/workflows/pages.yml
vendored
4
.github/workflows/pages.yml
vendored
@ -3,7 +3,7 @@ name: github pages
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master # Set a branch to deploy
|
- main # Set a branch to deploy
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@ -26,7 +26,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/main'
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./public
|
publish_dir: ./public
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
title: "ClearSky == coolify?"
|
title: "ClearSky == coolify?"
|
||||||
date: 2022-04-03
|
date: 2022-04-03
|
||||||
draft: true
|
draft: false
|
||||||
---
|
---
|
||||||
ClearSky started with the idea of getting the "cloud devops experience" without the cloud. Since registering this domain about 4 months ago and writing the first post about ClearSky, I did a lot of development and thinking what that would mean.
|
ClearSky started with the idea of getting the "cloud devops experience" without the cloud. Since registering this domain about 4 months ago and writing the first post about ClearSky, I did a lot of development and thinking what that would mean.
|
||||||
|
|
||||||
@ -13,4 +13,4 @@ As always, there are still a lot of features that i would like to have. Maybe th
|
|||||||
|
|
||||||
Another optimalization that i would like to see is shared database servers. I don't need 10 postgres instances to host 10 databases. 1 instance is enough. Databases are more than capable of handling authentication and authorization of different users.
|
Another optimalization that i would like to see is shared database servers. I don't need 10 postgres instances to host 10 databases. 1 instance is enough. Databases are more than capable of handling authentication and authorization of different users.
|
||||||
|
|
||||||
While there is definitely room for improvement, coolify comes closer to what I envisioned for ClearSky than anything I've seen so far. So I decided to stop working on the ClearSky platform for now, and see what cool things I can build on coolify. This blog is now hosted on coolify as well
|
While there is definitely room for improvement, coolify comes closer to what I envisioned for ClearSky than anything I've seen so far. So I decided to stop working on the ClearSky platform for now, and see what cool things I can build on coolify. This blog is now hosted on coolify as well.
|
@ -1,50 +0,0 @@
|
|||||||
---
|
|
||||||
title: ActionMailer renders the email body twice
|
|
||||||
date: 2023-02-22
|
|
||||||
draft: false
|
|
||||||
---
|
|
||||||
Recently i was happily coding on my rails project. I wanted to add a feature that would send an email to all admin users when a certain event occurred. So i searched "rails email" and discovered [ActionMailer](https://guides.rubyonrails.org/action_mailer_basics.html).
|
|
||||||
|
|
||||||
It works simple enough. First you define a "mailer" which is a lot like a controller. I defined a "PublicationMailer". It fetches the necessary data and then renders the email. Step 2 is defining views for the mailer, both html and txt formats. Lastly, you call `PublicationMailer.publication().deliver` and bimbamboom your email is ready. Good! On to the next feature.
|
|
||||||
|
|
||||||
Fast forward a couple of weeks. The app is almost ready and i'm deploying it on a VPS to see if everything works as expected. File uploads? Check! Authentication? Check! Email notifications? Che... wait a minute! The email that arrived in my inbox had the right contents, but it had them twice! Sanity check: no this did not occur in my test environment. What was going on?
|
|
||||||
|
|
||||||
After some head-scratching, i took another hard look at my mailer object:
|
|
||||||
|
|
||||||
```
|
|
||||||
class PublicationMailer < ApplicationMailer
|
|
||||||
helper :application
|
|
||||||
default from: "notifications@mark423.com"
|
|
||||||
layout "mailer"
|
|
||||||
def publication(recording)
|
|
||||||
@recording = recording
|
|
||||||
User.where(is_admin: true).each do |user|
|
|
||||||
mail to: user.email, subject: "Podcast published"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
I immediately understood my mistake. What I would expect this code to do is to send one email to each user that is an admin.
|
|
||||||
|
|
||||||
In my test environment, i only had one admin user. In my production environment i had created 2, which triggered the problem.
|
|
||||||
|
|
||||||
> It turns out the **mail** function does not really send a mail. It **renders** the mail.
|
|
||||||
|
|
||||||
## Solving it
|
|
||||||
The fix was simple: call mail once with a list of recipients.
|
|
||||||
|
|
||||||
```
|
|
||||||
class PublicationMailer < ApplicationMailer
|
|
||||||
helper :application
|
|
||||||
default from: "notifications@mark423.com"
|
|
||||||
def recording_published(recording)
|
|
||||||
@recording = recording
|
|
||||||
emails = User.where(is_admin: true).collect(&:email)
|
|
||||||
mail to: emails, subject: "Podcast published"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
## Hindsight
|
|
||||||
I think the function 'mail' could have had a better name (maybe 'render' like in controllers?). On the other hand, i could probably have read the [documentation](https://api.rubyonrails.org/classes/ActionMailer/Base.html#method-i-mail) better.
|
|
@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
title: Rails doesn't save my added attribute
|
|
||||||
date: 2022-07-09
|
|
||||||
draft: false
|
|
||||||
---
|
|
||||||
A long long time ago in 2014, before I started to work in a place ruled by the evil snake called "python", I worked with a little framework called [Ruby on Rails](https://rubyonrails.org). It was a wonderful time. Rails was hip in those days. All the cool kids were doing it. What I liked most about rails was how little code was needed to achieve something.
|
|
||||||
|
|
||||||
There is a bit a learning curve with rails. Rails is magic. You don't need to understand exactly what is happening, but you do need to remember the right spells. The good thing is that once you get into the rails mindset, you start expecting things to work in a certain way. And 9 out of 10 times, it does!
|
|
||||||
|
|
||||||
Another philosophy that i like about rails is "**convention over configuration**". For instance: lets say you have a table "posts". What do you call the column that identifies a row? And the column that is the foreign key to the "authors" table? In most cases, it doesn't really matter. So rails decides for you: "id" and "author_id". The rails ORM called ActiveRecord understands these column. Now you can do things like `my_post.author` and boom you've followed that foreign key without ever naming it in your code. Ofcourse, of you really want to, there's a way to [change the name of the foreign key column](https://guides.rubyonrails.org/association_basics.html#options-for-belongs-to-foreign-key)
|
|
||||||
|
|
||||||
So rails was great in 2014. I hadn't used it or even looked at it since that time. The hype seems to have passed. The cool kids have all jumped on the nodejs/"single page app"-train. I seem to have missed that train. In fact, i never liked javascript or npm. So, when rails' big boss [posted a blog about a new rails version that steers clear from transpiling and bundling](https://world.hey.com/dhh/modern-web-apps-without-javascript-bundling-or-transpiling-a20f2755), I was paying attention. When rails 7 came out in december 2021, I decided to take it for a spin.
|
|
||||||
|
|
||||||
> rails in 2022: less hype, same magic?
|
|
||||||
|
|
||||||
It felt like coming home after a long trip: running `rails g scaffold post title:string content:text` and `rails s` and finding your crud functions ready and working. This is where a lot of "rails tutorials" stop. But a scaffold is not a building. It's a starting point. What happens when we want to add an attribute to our blog?
|
|
||||||
|
|
||||||
* First, we add a new migration to add a column to the table. Dont forget to `rails db:migrate`
|
|
||||||
* Next, we edit the \_form partial to define an input field for the attribute
|
|
||||||
* As i remember it, there was no step 3. Lets give it a whirl!
|
|
||||||
|
|
||||||
**Wait, it doesn't error but it also doesn't save the new attribute?**
|
|
||||||
|
|
||||||
It turns out that in the last 8 years, someone found out that it isn't the greatest idea to let the user define arbitrary attributes in the controller update/create calls. So now you have to define which model attributes can be updated by the controller. They call it [Strong parameters](https://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html). It looks like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
def blog_params
|
|
||||||
params.require(:blog).permit(:title, :content)
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
So adding an attribute now requires this extra step in the controller. This is a process i do very often when developing apps. I guess it makes sense security wise to have this validation. For me though, it also means rails has lost some of its famous magic.
|
|
||||||
|
|
||||||
There's lots of other magic left though, and even some new magic that was added since 2014. I really like [active storage](https://edgeguides.rubyonrails.org/active_storage_overview.html).
|
|
1
layouts/partials/footer.html
Normal file
1
layouts/partials/footer.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<script async defer data-website-id="1c1c8489-4fb2-4940-af2a-09eca940adb1" src="https://analytics.clearsky.dev/umami.js"></script>
|
@ -1 +0,0 @@
|
|||||||
clearsky.dev
|
|
Loading…
Reference in New Issue
Block a user