Posts

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

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

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.

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

Rails security resources

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

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'.

View routes in the rails console

Dienstag, 14. Juli 2020, 19:28 Uhr | roberto@vasquez-angel.de |

# For the main application
Rails.application.routes.named_routes.send(:routes).each {|name, route| puts "%20s: %s" % [name, route] }; nil
# For a specific engine
Cmor::Blog::Backend::Engine.routes.named_routes.send(:routes).each {|name, route| puts "%20s: %s" % [name, route] }; nil

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.

Fix command: webpack not found on heroku

Mittwoch, 22. Januar 2020, 22:43 Uhr | roberto@vasquez-angel.de |

If you get following message when deploying to heroku (i.e. after upgraping rails):

command webpacker not found

You may need to run following command locally and commit the changes:

rails webpacker:install

Expect exceptions in rspec2 test

Donnerstag, 07. April 2011, 13:31 Uhr | roberto@vasquez-angel.de |

I keep forgetting how to test exceptions with rspec2. This is an example:

  describe "something" do
    describe "exceptions" do
      it "should raise an exception" do
        expect {
          # Code that throws an exception
        }.to raise_error
      end

Capistrano and bundle config

Montag, 04. April 2011, 16:40 Uhr | roberto@vasquez-angel.de |

When you use capistrano and you need a custom bundler config in your Rails app, you have the problem, that it gets lost after each update.

The solution to this problem is to move the .bundle folder in your rails app, to the shared folder in your capistrano environment. Then you tell capistrano to link the .bundle to the shared folder after each update.

  • First, move your Rails.root/.bundle to ../../shared/.bundle
  • Add a rake task to Rails.root/config/deploy.rb:
namespace(:bundle) do
  desc "Symlinks your machine specific bundle to your rails app"
  task :symlink, :roles => :app do
    run <<-CMD
      ln -nfs #{shared_path}/.bundle #{release_path}/.bundle
    CMD
  end
end
  • tell capistrano to invoke the bundle:symlink task after symlinking your freshly deployed realase. In your Rails.root/config/deploy.rb:
after "deploy:symlink", "bundle:symlink"

Devise: Testing controllers and requests that need authentication with rspec2

Montag, 04. April 2011, 01:07 Uhr | roberto@vasquez-angel.de |

Imagine you have been happily writing your controller test and then, you have to add authentication to your application using devise.

Assume you have a posts controller with following test:

require 'spec_helper'

describe PostsController do
  def mock_post(stubs={})
    @mock_post ||= mock_model(Post, stubs).as_null_object
  end

  describe "GET index" do
    it "assigns all posts as @posts" do
      Post.stub(:all) { [mock_post] }
      get :index
      assigns(:posts).should eq([mock_post])
    end
  end

  describe "GET show" do
    it "assigns the requested post as @post" do
      Post.stub(:find).with("37") { mock_post }
      get :show, :id => "37"
      assigns(:post).should be(mock_post)
    end
  end
end  

First, you’ll have to add the Devise TestHelpers. Add a new file spec/support/devise.rb:

RSpec.configure do |config|
  config.include Devise::TestHelpers, :type => :controller
end

You’ll need a factory for the admin. I use factory girl. Add the admin factory to Rails.root/spec/factories.rb:

Factory.define(:admin) do |admin|
  admin.email    "admin@example.com"
  admin.password "foobar"
end

Then you throw all your controller tests into a new describe block, that signins in your admin before each test:

describe PostsController do
  describe "as a signed in admin" do
    before(:each) do
      admin = Factory(:admin)
      sign_in admin
    end
    
    def mock_post(stubs={})
      @mock_post ||= mock_model(Post, stubs).as_null_object
    end

    describe "GET index" do
      it "assigns all posts as @posts" do
        Post.stub(:all) { [mock_post] }
        get :index
        assigns(:posts).should eq([mock_post])
      end
    end

    describe "GET show" do
      it "assigns the requested post as @post" do
        Post.stub(:find).with("37") { mock_post }
        get :show, :id => "37"
        assigns(:post).should be(mock_post)
      end
    end
  end
end

Customize the request specs. Before:

require 'spec_helper'

describe "NewsItems" do
  describe "GET /news_items" do
    it "works! (now write some real specs)" do
      # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
      get news_items_path
      response.status.should be(200)
    end
  end
end

and with devise integration:

require 'spec_helper'

describe "NewsItems" do
  context "as logged in admin" do
    before(:each) do
      admin = Factory(:admin)
      get new_admin_session_path
      fill_in :email,    :with => admin.email
      fill_in :password, :with => admin.password
      click_button
    end
    
    describe "GET /news_items" do
      it "works! (now write some real specs)" do
        # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
        get news_items_path
        response.status.should be(200)
      end
    end
  end
end

Rake task to create a new devise user

Montag, 04. April 2011, 01:07 Uhr | roberto@vasquez-angel.de |

namespace :devise do
  desc "Create admin"
  task :create_admin, :email, :password, :needs => :environment do |t, args|
    if a = Admin.create(:email => args.email, :password => args.password)
      puts "Created admin"
    else 
      puts a.errors
    end    
  end
end  

Usage:

$> rake devise:create_admin["user@example.com","password"]

Add a new role to your site with devise

Montag, 04. April 2011, 01:06 Uhr | roberto@vasquez-angel.de |

Adding a new role (i.e. “Admin”) is easy:

$> rails generate devise Admin

Don’t forget to migrate:

$> rake db:migrate

Then you can check for the admin in your controllers:

class BackendController < ApplicationController
  before_filter :authenticate_admin!
end 

Installing Devise

Montag, 04. April 2011, 01:06 Uhr | roberto@vasquez-angel.de |

  • Add the gem to your Gemfile:
gem 'devise'
  • Install your Bundle:
$> bundle install
  • Run the generator:
$> rails generate devise:install

This will generate a initialiter in your config/initializers folder. You should check the options in config/initializers/devise.rb

  • Add default URL options to your mailer configuration in the environments files:

environments/development.rb:

config.action_mailer.default_url_options = { :host => 'localhost:3000' }

environments/production.rb:

config.action_mailer.default_url_options = { :host => 'blog.robotex.de' }

svn:ignore für Rails Projekte

Montag, 04. April 2011, 01:06 Uhr | roberto@vasquez-angel.de |

.svnignore Datei im Rails.root erstellen:

.bundle
.project
*.swp
*~
webrat.log
db/*.sqlite3
log/*
tmp/*
doc/api/*
doc/app/*

und danach die Datei “scharf” schalten:

svn -R propset svn:ignore -F .svnignore .