Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 82 additions & 13 deletions .github/workflows/ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ on:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
test-postgresql:
runs-on: ubuntu-latest
strategy:
matrix:
ruby-version: ['3.4']

services:
postgres:
image: postgres:latest
Expand All @@ -27,30 +23,103 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v4

- name: Install libvips
run: sudo apt-get install -y libvips

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{matrix.ruby-version}}
ruby-version: '3.4'
bundler-cache: true

- name: Create DB
env:
RAILS_ENV: test
run: |
cp test/dummy/config/database.yml.ci test/dummy/config/database.yml
cp test/dummy/config/database.yml.postgresql test/dummy/config/database.yml
bin/rails db:setup

- name: Compile assets
env:
RAILS_ENV: test
run: cd test/dummy && bin/rails assets:precompile


- name: Run tests
run: bin/rails test test/*

test-mysql:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: mysql
MYSQL_DATABASE: spina_test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v4

- name: Install libvips
run: sudo apt-get install -y libvips

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4'
bundler-cache: true

- name: Create DB
env:
RAILS_ENV: test
run: |
cp test/dummy/config/database.yml.mysql test/dummy/config/database.yml
bin/rails db:setup

- name: Compile assets
env:
RAILS_ENV: test
run: cd test/dummy && bin/rails assets:precompile

- name: Run tests
run: bin/rails test test/*

test-sqlite:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install libvips
run: sudo apt-get install -y libvips

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.4'
bundler-cache: true

- name: Create DB
env:
RAILS_ENV: test
run: |
cp test/dummy/config/database.yml.sqlite test/dummy/config/database.yml
bin/rails db:setup

- name: Compile assets
env:
RAILS_ENV: test
run: cd test/dummy && bin/rails assets:precompile

- name: Run tests
run: bin/rails test test/*
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ group :test do
gem "factory_bot"
gem "rails-controller-testing"

# Database adapters
gem "pg"
gem "mysql2"
gem "sqlite3"

# CodeClimate
gem "minitest-reporters"
gem "simplecov"
Expand Down
16 changes: 15 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ PATH
jsonapi-serializer
kaminari
mobility (>= 1.3.0)
pg
rack-rewrite (>= 1.5.0)
rails (>= 7.0, < 9.0)
stimulus-rails (>= 0.7.0)
Expand Down Expand Up @@ -213,6 +212,8 @@ GEM
request_store (~> 1.0)
mocha (3.0.1)
ruby2_keywords (>= 0.0.5)
mysql2 (0.5.7)
bigdecimal
net-imap (0.6.2)
date
net-protocol
Expand Down Expand Up @@ -340,6 +341,16 @@ GEM
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
sqlite3 (2.9.0-aarch64-linux-gnu)
sqlite3 (2.9.0-aarch64-linux-musl)
sqlite3 (2.9.0-arm-linux-gnu)
sqlite3 (2.9.0-arm-linux-musl)
sqlite3 (2.9.0-arm64-darwin)
sqlite3 (2.9.0-x86-linux-gnu)
sqlite3 (2.9.0-x86-linux-musl)
sqlite3 (2.9.0-x86_64-darwin)
sqlite3 (2.9.0-x86_64-linux-gnu)
sqlite3 (2.9.0-x86_64-linux-musl)
stimulus-rails (1.3.4)
railties (>= 6.0.0)
stringio (3.2.0)
Expand Down Expand Up @@ -396,13 +407,16 @@ DEPENDENCIES
letter_opener
minitest-reporters
mocha
mysql2
pg
propshaft
pry-rails
puma
rails-controller-testing
selenium-webdriver (~> 4.11.0)
simplecov
spina!
sqlite3

BUNDLED WITH
2.5.17
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def search
end

@pages ||= Page.all
@pages = @pages.joins(:translations).where("spina_page_translations.title ILIKE :query OR materialized_path ILIKE :query", query: "%#{params[:search]}%").order(created_at: :desc).distinct.page(params[:page]).per(20)
@pages = @pages.joins(:translations).where("LOWER(spina_page_translations.title) LIKE LOWER(:query) OR LOWER(materialized_path) LIKE LOWER(:query)", query: "%#{params[:search]}%").order(created_at: :desc).distinct.page(params[:page]).per(20)
render :index
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def index

def search
@resources ||= Resource.all
@resources = @resources.where("name ILIKE :query OR label ILIKE :query", query: "%#{params[:search]}%").order(created_at: :desc).distinct.page(params[:page]).per(20)
@resources = @resources.where("LOWER(name) LIKE LOWER(:query) OR LOWER(label) LIKE LOWER(:query)", query: "%#{params[:search]}%").order(created_at: :desc).distinct.page(params[:page]).per(20)
render :index
end

Expand Down
21 changes: 12 additions & 9 deletions app/jobs/spina/replace_signed_id_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ class ReplaceSignedIdJob < ApplicationJob
def perform(old_signed_id, new_signed_id)
return if old_signed_id.blank? || new_signed_id.blank?

pages = get_pages(old_signed_id)
accounts = Spina::Account.all

[pages, accounts].each do |records|
records.update_all("json_attributes = REGEXP_REPLACE(json_attributes::text, '#{old_signed_id}', '#{new_signed_id}', 'g')::jsonb")
end
replace_in_records(Spina::Page, old_signed_id, new_signed_id)
replace_in_records(Spina::Account, old_signed_id, new_signed_id)
end

private

def get_pages(signed_id)
return Spina::Page.none unless signed_id.present?
Spina::Page.where("json_attributes::text LIKE ?", "%#{signed_id}%")
def replace_in_records(model, old_signed_id, new_signed_id)
model.find_each(batch_size: 100) do |record|
next unless record.json_attributes.present?

json_string = record.json_attributes.to_json
next unless json_string.include?(old_signed_id)

updated_json = json_string.gsub(old_signed_id, new_signed_id)
record.update_column(:json_attributes, JSON.parse(updated_json))
end
end
end
end
2 changes: 1 addition & 1 deletion app/models/concerns/spina/attachable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Attachable

scope :with_filename, ->(query) do
joins(:file_blob).where(
"active_storage_blobs.filename ILIKE ?",
"LOWER(active_storage_blobs.filename) LIKE LOWER(?)",
"%" + Image.sanitize_sql_like(query) + "%"
)
end
Expand Down
4 changes: 3 additions & 1 deletion app/models/spina/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ module Spina
class Resource < ApplicationRecord
extend Mobility

attribute :slug, :json, default: -> { {} }

has_many :pages, dependent: :restrict_with_exception

after_commit :update_resource_pages, on: [:update]

translates :slug, backend: :jsonb
translates :slug, backend: :json

def pages
case order_by
Expand Down
2 changes: 2 additions & 0 deletions app/models/spina/setting.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module Spina
class Setting < ApplicationRecord
attribute :preferences, :json, default: -> { {} }

validates :plugin, presence: true
end
end
2 changes: 1 addition & 1 deletion db/migrate/13_add_json_attributes_to_spina_accounts.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class AddJsonAttributesToSpinaAccounts < ActiveRecord::Migration[5.2]
def change
add_column :spina_accounts, :json_attributes, :jsonb
add_column :spina_accounts, :json_attributes, :json
end
end
2 changes: 1 addition & 1 deletion db/migrate/14_add_json_attributes_to_spina_pages.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class AddJsonAttributesToSpinaPages < ActiveRecord::Migration[5.2]
def change
add_column :spina_pages, :json_attributes, :jsonb
add_column :spina_pages, :json_attributes, :json
end
end
2 changes: 1 addition & 1 deletion db/migrate/15_add_slug_to_spina_resources.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class AddSlugToSpinaResources < ActiveRecord::Migration[5.2]
def change
add_column :spina_resources, :slug, :jsonb
add_column :spina_resources, :slug, :json
end
end
4 changes: 2 additions & 2 deletions db/migrate/18_change_default_spina_resources_slug.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
class ChangeDefaultSpinaResourcesSlug < ActiveRecord::Migration[7.0]
def up
change_column :spina_resources, :slug, :jsonb, default: {}
# Default handled in model layer for MySQL compatibility
end

def down
change_column :spina_resources, :slug, :jsonb, default: nil
# Default handled in model layer for MySQL compatibility
end
end
2 changes: 1 addition & 1 deletion db/migrate/7_create_spina_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class CreateSpinaSettings < ActiveRecord::Migration[5.0]
def change
create_table :spina_settings do |t|
t.string :plugin
t.jsonb :preferences, default: {}
t.json :preferences
t.timestamps
end

Expand Down
2 changes: 1 addition & 1 deletion docs/v2/advanced/1_create_custom_parts.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Custom parts

All page content is stored in a single JSONB-column in the database. Spina uses the `attr_json` gem to work with these nested json objects. All default parts are `AttrJson::Model` objects. Follow the steps below to create your own custom part.
All page content is stored in a single JSON column in the database. Spina uses the `attr_json` gem to work with these nested json objects. All default parts are `AttrJson::Model` objects. Follow the steps below to create your own custom part.

## Step 1. Create a part
Let's imagine our app contains a movie database. We'd like to add a part to select one of the movies in our collection. First we need to create the object that can be stored as page content.
Expand Down
12 changes: 11 additions & 1 deletion docs/v2/getting_started/2_installing_spina.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# Install Spina CMS

Start by creating a new Rails app using a PostgreSQL database.
Start by creating a new Rails app. Spina supports PostgreSQL, MySQL, and SQLite databases.

```
rails new yourwebsite --database=postgresql
```

Or for MySQL:
```
rails new yourwebsite --database=mysql
```

Or for SQLite (development only):
```
rails new yourwebsite --database=sqlite3
```

Create a database.

```
Expand Down
2 changes: 1 addition & 1 deletion docs/v2/getting_started/3_existing_project.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Existing project

If you already have an existing Rails project, just add `gem "spina"` to your Gemfile and run `bundle install`. (Make sure you're using PostgreSQL as your database)
If you already have an existing Rails project, just add `gem "spina"` to your Gemfile and run `bundle install`. Spina supports PostgreSQL, MySQL (5.7.8+), and SQLite (3.38+) databases.

Run the installer to get started.

Expand Down
1 change: 0 additions & 1 deletion spina.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ Gem::Specification.new do |gem|
gem.files = Dir["{app,config,db,lib,vendor}/**/*"] + ["Rakefile", "README.md"]

gem.add_dependency "rails", ">= 7.0", "< 9.0"
gem.add_dependency "pg"
gem.add_dependency "bcrypt"
gem.add_dependency "image_processing"
gem.add_dependency "ancestry"
Expand Down
26 changes: 4 additions & 22 deletions test/dummy/config/database.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
# SQLite. Versions 3.8.0 and up are supported.
# gem install sqlite3
#
# Ensure the SQLite 3 gem is defined in your Gemfile
# gem 'sqlite3'
#
#
default: &default
adapter: postgresql
encoding: unicode
pool: 5
host: localhost

development:
<<: *default
database: spina_development

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
<<: *default
database: spina_test
adapter: sqlite3
pool: 5
timeout: 5000
database: db/test.sqlite3
9 changes: 9 additions & 0 deletions test/dummy/config/database.yml.mysql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
test:
adapter: mysql2
encoding: utf8mb4
pool: 5
host: 127.0.0.1
port: 3306
username: root
password: mysql
database: spina_test
Loading