Posts

Setting up laravel and filament

Samstag, 29. März 2025, 10:25 Uhr | roberto@vasquez-angel.de |

Install php:

> /bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)"

Create a new laravel app:

> laravel new example-app

┌ Which starter kit would you like to install? ────────────────┐
│ Livewire                                                     │
└──────────────────────────────────────────────────────────────┘

┌ Which authentication provider do you prefer? ────────────────┐
│ Laravel's built-in authentication                            │
└──────────────────────────────────────────────────────────────┘

┌ Would you like to use Laravel Volt? ─────────────────────────┐
│ Yes                                                          │
└──────────────────────────────────────────────────────────────┘

┌ Which testing framework do you prefer? ──────────────────────┐
│ Pest                                                         │
└──────────────────────────────────────────────────────────────┘

┌ Would you like to run npm install and npm run build? ────────┐
│ Yes                                                          │
└──────────────────────────────────────────────────────────────┘

> cd example-app
> composer run dev

Add filament:

> composer require filament/filament:"^3.3" -W
> php artisan filament:install --panels

┌ What is the ID? ─────────────────────────────────────────────┐
│ admin                                                        │
└──────────────────────────────────────────────────────────────┘

Create a new user:

> php artisan make:filament-user

┌ Name ────────────────────────────────────────────────────────┐
│ admin                                                        │
└──────────────────────────────────────────────────────────────┘

┌ Email address ───────────────────────────────────────────────┐
│ rva@beegoodit.de                                             │
└──────────────────────────────────────────────────────────────┘

┌ Password ────────────────────────────────────────────────────┐
│ ••••••••                                                     │
└──────────────────────────────────────────────────────────────┘

INFO  Success! rva@beegoodit.de may now log in at http://localhost/admin/login.

Deploying:

  • add a Dockerfile
  • add a supervisord.conf
  • add nginx/laraval.conf

env vars:

APP_DEBUG=true
APP_ENV=production
APP_KEY=<create one with 'openssl rand -hex 16'>
APP_URL=<your-app-url>
DB_CONNECTION=mariadb
DB_URL=<your-db-url>

Setup the db and create your first user:

> php artisan migrate
> php artisan make:filament-user

Mark the user as verified:

> php artisan tinker
tinker> \App\Models\User::where('email', 'rva@beegoodit.de')->first()->markEmailAsVerified();

configure https to styles not loading:

# app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\URL;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        if (config('app.env') === 'production') {
            URL::forceScheme('https');
        }
    }
}

Configure access to the admin panel:

# app/Models/User.php
use Filament\Models\Contracts\FilamentUser;
use Filament\Panel;

class User extends Authenticatable implements FilamentUser
    /**
     * Authorize access to the Filament admin panel.
     */
    public function canAccessPanel(Panel $panel): bool
    {
        return str_ends_with($this->email, '@beegoodit.de') && $this->hasVerifiedEmail();
    }
}

Moving rails apps to coolify

Freitag, 03. Januar 2025, 08:46 Uhr | roberto@vasquez-angel.de |

Use Dockerfiles as Nixpacks bug out after install ruby (2025-01-03).

My assets don’t get served

Add the env var RAILS_SERVE_STATIC_FILES=true

Webpack build failing with ERR_OSSL_EVP_UNSUPPORTED

Mittwoch, 21. Juni 2023, 13:42 Uhr | roberto@vasquez-angel.de |

If webpack build fails with ERR_OSSL_EVP_UNSUPPORTED on node > 16 try exporting following variable before running rails:

export NODE_OPTIONS=--openssl-legacy-provider

Ruby < 3.1 installs failing on Ubuntu 22.04 with an openssl error

Montag, 03. April 2023, 11:07 Uhr | roberto@vasquez-angel.de |

Seems like ubuntu recently updated openssl to v3. This seems to clash with installing older ruby versions.

Fix it by having rvm use its own openssl version:

#> rvm pkg install openssl
#> rvm reinstall ruby-2.7.8 --with-openssl-dir=$HOME/.rvm/usr

See https://github.com/rvm/rvm/issues/5209 for more details.

Access WSL2 from LAN

Sonntag, 26. März 2023, 21:51 Uhr | roberto@vasquez-angel.de |
PS C:\Windows\system32> netsh advfirewall firewall add rule name="Allowing LAN connections" dir=in action=allow protocol=TCP localport=3000
OK.

PS C:\Windows\system32> netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=172.25.146.40

My zshell customizations

Mittwoch, 22. März 2023, 09:30 Uhr | roberto@vasquez-angel.de |
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
  local node_version="$(nvm version)"
  local nvmrc_path="$(nvm_find_nvmrc)"

  if [ -n "$nvmrc_path" ]; then
    local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

    if [ "$nvmrc_node_version" = "N/A" ]; then
      nvm install
    elif [ "$nvmrc_node_version" != "$node_version" ]; then
      nvm use --silent
    fi
  elif [ "$node_version" != "$(nvm version default)" ]; then
    nvm use default --silent
  fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc

# publish gems the easy way
function publish_gem {
    TMP=$(gem build $(ls *.gemspec));
    GEM_NAME=$(echo $TMP |& tail -1 | sed -r 's/.*File: //g');
    echo Publishing ${GEM_NAME};
    gem push $GEM_NAME;
}

# Dokku client
alias dokku='$HOME/.dokku/contrib/dokku_client.sh'

# SSH keychain
eval `keychain --quiet --eval --agents ssh id_rsa`

Installing edge orchid platform and orchid crud on laravel

Sonntag, 19. März 2023, 10:29 Uhr | roberto@vasquez-angel.de |
#> sail composer require "orchid/platform:dev-master as 13.10.0"
#> sail composer update -W
#> sail artisan orchid:install
#> sail artisan vendor:publish
#> sail artisan migrate
#> sail artisan orchid:admin admin user@example.com password
#> sail composer require orchid/crud:dev-master

How to restore an encrypted dokku postgres dump to your local dev environment

Dienstag, 07. März 2023, 16:23 Uhr | roberto@vasquez-angel.de |

Go to the s3 storage, locate the dump and download it. Let’s assume the file is called dump.tgz.gpg

Decrypt the dump using the passphrase/key you have safely stored (i.e. in a password manager):

#> gpg --pinentry-mode=loopback --passphrase "<passphrase>" -d -o dump.tgz dump.tgz.gpg

Create a directory as unpacking target:

#> mkdir dump

Unpack the dump:

#> tar zxvf dump.tgz -C dump

Drop the current database and recreate it, so it is empty. If you are using rails you can use following commands:

#> rails db:drop && rails db:create

Restore the dump to your local postgres database:

#> pg_restore -U <username> -d <database_name> --no-owner < dump/backup/export

How to start a new laravel project

Donnerstag, 02. März 2023, 10:31 Uhr | roberto@vasquez-angel.de |

How to start a new project: https://laravel.com/docs/10.x#getting-started-on-linux

Generate a new app via:

#> curl -s https://laravel.build/example-app | bash

Timezone ASCII art

Dienstag, 20. Dezember 2022, 14:17 Uhr | roberto@vasquez-angel.de |
01:00 <-------- -|1 --------->            |             \
02:00  <-------- |10 --------->           |             |
03:00   <--------| -9 --------->          |             |
04:00    <-------|  -8 --------->         |             |
05:00     <------|-  -7 --------->        |             | America/Greenland
06:00      <-----|--  -6 --------->       |             |
07:00       <----|---  -5 --------->      |             |
08:00        <---|----  -4 --------->     |             |
09:00         <--|-----  -3 --------->    |             |
10:00          <-|------  -2 --------->   |             /
11:00           <|-------  -1 --------->  |             \
12:00            |-------- UTC ---------> |             |
13:00            |<--------  +1 --------->|             | Europe/Africa
14:00            | <--------  +2 ---------|             |
15:00            |  <--------  +3 --------|>            /
16:00            |   <--------  +4 -------|->           \
17:00            |    <--------  +5 ------|-->          |
18:00            |     <--------  +6 -----|--->         |
20:00            |      <--------  +7 ----|---->        |
21:00            |       <--------  +8 ---|----->       |
22:00            |        <--------  +9 --|------>      | Asia/Australia
23:00            |         <-------- +10 -|------->     |
24:00            |          <-------- +11 |-------->    |
00:00            |           <-------- +12|--------->   |
01:00            |            <-------- +1| --------->  |
02:00            |             <-------- +|4 ---------> /
                 \_______________________/
                            1 day

Moving from Resque to ActiveJob

Donnerstag, 18. August 2022, 08:14 Uhr | roberto@vasquez-angel.de |
  Resque ActiveJob
Object PORO Inherits from ActiveJob::Base
Entry method def self.perform def perform
Invocation MyJob.perform MyJob.perform_now
Queueing @queue = :critical queue_as :critical

ActiveJob uses the instance method #perform as entry point for the job. So when you are migrating from resque and your job reference other methods in the job, you have to change them from def self.foo to def foo. You now have the advantage that you are working on an instance. So you can have instance methods, variables, etc.

Getting a list of all presence validated attributes for all services in your application

Dienstag, 12. Juli 2022, 14:17 Uhr | roberto@vasquez-angel.de |

Assume you have built a bunch of services or any other activemodel/activerecord descendant classes. You decide to add translations to your app. Then you realize that you will have to add the translations to you yaml files. First thing that comes into your mind: I’ll make a list of all attributes of those services. The idea is good, but not perfect. You might validate getter methods and not only attributes. So simply listing the attributes of all services will not cut it. What you want is to list all validated attributes/methods in all of your services. In our special case we narrowed it down to presence validations.

Following admittedly long line will list all of your Rao::Service::Base descendants that are in the namespace Blorgh” with all presences validated attributes as yaml, sorted, ready to cut and paste into your locale yaml files:

irb> y Rao::Service::Base.descendants.collect { |d| d.name.start_with?("Blorgh") ? d : nil }.compact.sort { |c, o| c.name <=> o.name }.each_with_object({}) { |k,m| m[k.name.underscore] = k.validators.collect { |v| v.class.name.include?("Presence") ? v.attributes : nil }.flatten.compact.sort.each_with_object({}) { |a,m| m[a] = nil } }

Do not forget to enable eager loading in your development env before doing this or your list might be incomplete.

Cleanup logfiles

Montag, 09. August 2021, 16:16 Uhr | roberto@vasquez-angel.de |
shopt -s globstar && rm **/*.log

Javascript: Solved using ES6 split on String leads to error with Babel

Dienstag, 04. Mai 2021, 12:22 Uhr | roberto@vasquez-angel.de |

When using string split and transpiling your code with Babel you may get following error:

Cannot find module 'core-js/modules/es.string.split.js' from 'dist/i18n.js'

Solve it by add ing core-js to your dev package:

yarn add --dev core-js

More about core-js can be found here: https://alexbogovich.com/blog/core-js/

Git: Diff by date

Freitag, 23. April 2021, 09:53 Uhr | roberto@vasquez-angel.de |

You can get a diff of your repo comparing now and the code at a moment in the past:

# Compares the actual code with the code from two days ago
git diff 'HEAD@{2 days ago}' HEAD

Loading nested gems with zeitwerk

Montag, 12. April 2021, 14:40 Uhr | roberto@vasquez-angel.de |

When you have a gem with an nested namespace like “rao-api-resources_controller” (-> Rao::Api::ResourcesController) you cannot use the for_gem method of zeitwerk. Instead you can do as follows:

# lib/rao/api/resources_controller.rb
loader = Zeitwerk::Loader.new.tap do |loader|
  root = Pathname.new(File.expand_path("../../..", __dir__))

  loader.push_dir(File.absolute_path(root.join("lib")))

  loader.inflector = Class.new(Zeitwerk::Inflector) do
    def camelize(basename, abspath)
      if abspath.end_with?("rao/api/resources_controller/version.rb")
        "VERSION"
      else
        super
      end
    end
  end.new

  loader.setup
  loader
end

Setting up a rails development environment on windows with wsl

Samstag, 20. März 2021, 19:25 Uhr | roberto@vasquez-angel.de |
sudo apt-get update

# Install rvm
sudo apt install curl -y
sudo apt install gnupg2 -y
gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
\curl -sSL https://get.rvm.io | bash -s stable

# Install ruby
rvm install ruby-3.0.0

# Install zsh/oh-my-zsh
Install zsh from this tutorial: https://kifarunix.com/install-and-setup-zsh-and-oh-my-zsh-on-ubuntu-20-04/

# Install vscode
Install vscode on windows from here: https://code.visualstudio.com/Download
# Install the wsl extension when vscode prompts you
# Restart to be able to run code from any ubuntu terminal

# Install postgres
sudo apt install postgresql -y
sudo apt-get install libpq-dev -y
sudo service postgresql start
sudo -u postgres createuser -s $USER

# Install redis
sudo apt install redis-server -y

# Install node
sudo apt install nodejs -y

# Install npm
sudo apt install npm -y

# Install nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash

# Install yarn
sudo npm install --global yarn

# Install heroku cli
curl https://cli-assets.heroku.com/install.sh | sh

Copying a database from one heroku app to another

Sonntag, 01. November 2020, 19:04 Uhr | roberto@vasquez-angel.de |
  1. Create a backup

    $> heroku pg:backups capture –app source-app-12345

  2. Show backup infos:

    $> heroku pg:backups:info –app source-app-12345

  3. Select the backup number bxxx.

  4. Restore the backup to the target database:

    $> heroku pg:backups:restore source-app-12345::bxxx DATABASE_URL –remote target-app

Rails security resources

Dienstag, 01. September 2020, 16:11 Uhr | roberto@vasquez-angel.de |

Resources

Rails security guide: https://guides.rubyonrails.org/security.html

Zen rails security checklist: https://github.com/brunofacca/zen-rails-security-checklist

OWASP ruby on rails cheat sheet: https://cheatsheetseries.owasp.org/cheatsheets/Ruby_on_Rails_Cheat_Sheet.html

Static code analysis/audit tools

Bundle audit: https://github.com/rubysec/bundler-audit

Brakeman: https://github.com/presidentbeef/brakeman

Checking for active storage blob file presence

Montag, 31. August 2020, 14:26 Uhr | roberto@vasquez-angel.de |
ActiveRecord::Base.logger.level = 1
storage_service = ObjectSpace.each_object(ActiveStorage::Service::S3Service).first
(ActiveStorage::Attachment.pluck(:record_type).uniq - ["Em::Compare::Checkouts::PointOfDelivery"]).each do |klass|
  model = klass.constantize
  puts "#{klass}"
  puts "=" * 80
  associations = model.reflect_on_all_associations.select { |a| a.class_name == "ActiveStorage::Attachment" }
  associations.each do |association|
    storage_name = association.name.to_s.split("_").first.to_sym
    puts "#{storage_name}"
    puts "-" * 80
    records = model.joins(association.name).distinct
    records.find_each do |record|
      puts "#{model}##{record.id}"
      puts "-" * 80
      blobs = [record.send(storage_name)].flatten.map(&:blob)
      blobs.each do |blob|
        if storage_service.exist?(blob.key)
          puts "Blob key #{blob.key} exists"
        else
          puts "Blob key #{blob.key} missing"
        end
      end
    end
  end
end
ActiveRecord::Base.logger.level = 0

Rails: Using SSL in locale development

Mittwoch, 29. Juli 2020, 12:40 Uhr | roberto@vasquez-angel.de |
  1. Generate a new certificate:
  
    # Create a folder to store the certificates
    mkdir config/certs
    # Ignore the certificates folder to avoid accidentally commiting the certs to the repo
    echo "config/certs/*" >> .gitignore
    # generate the certificate:
    # Be sure to set the domain name to "lvh.me". Other settings don't matter
    openssl req -x509 -sha256 -nodes -newkey rsa:2048 -days 365 -keyout config/certs/lvh.me.key -out config/certs/lvh.me.crt
  
  1. Configure rails to optionally force ssl in development mode:
  
    Rails.application.configure do
      config.force_ssl = true if ENV.fetch('SSL', nil) == "true"
    end
  
  1. Start the server in SSL mode:
  
    SSL=true bundle exec rails s -b 'ssl://0.0.0.0:3000?key=./config/certs/lvh.me.key&cert=./config/certs/lvh.me.crt'
  
  1. Access the page:
  
    https://lvh.me:3000/
  
If you get following error message in the puma logs when accessing the page with Chrome:
  
    SSL error, peer: 127.0.0.1, peer cert: , #<Puma::MiniSSL::SSLError: OpenSSL error: error:141F7065:SSL routines:final_key_share:no suitable key share - 337604709>
  
Make sure to use puma '>= 4'.

Cleanup RVM

Freitag, 24. Juli 2020, 11:25 Uhr | roberto@vasquez-angel.de |

The hard way (remove all gems):

$ rvm all-gemsets do gem cleanup

Remove stale source files and archives and other obsolete stuff:

$ rvm cleanup all

To avoid duplicate gems enable the gem cache:

$ rvm gemset globalcache enable

Making AWS S3 requests in ruby

Donnerstag, 11. Juni 2020, 23:15 Uhr | roberto@vasquez-angel.de |
require 'aws-sdk-s3'

s3 = Aws::S3::Client.new(
  access_key_id: ENV['ACCESS_KEY_ID'],
  secret_access_key: ENV['SECRET_ACCESS_KEY'],
  region: 'eu-central-1'
)

s3.list_objects(bucket: 'my-bucket')

Manipulating the schema migrations table with active record

Dienstag, 19. Mai 2020, 10:57 Uhr | roberto@vasquez-angel.de |
class SchemaMigration < ActiveRecord::Base; self.primary_key = :version; end
SchemaMigration.where(version: "20200514202233").first
SchemaMigration.where(version: "20200514202233").update_all(version: "20200514142149")

"Could not find "README.md" in any of your source paths" when running rake dummy:app

Dienstag, 04. Februar 2020, 10:39 Uhr | roberto@vasquez-angel.de |

When you are trying to run rake dummy:app from the rails-dummy gem and you get following message:

Could not find "README.md" in any of your source paths. Your current source paths are: 
/home/vagrant/.rvm/gems/ruby-2.4.0@cmor/gems/railties-5.2.0/lib/rails/generators/rails/app/templates

You may be using rails 5.2.0. Upgrading to 5.2.3 or later solves the problem.