diff --git a/.env b/.env new file mode 100644 index 0000000..3247105 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +UID=1000 +GID=1000 diff --git a/Gemfile b/Gemfile index 4f4fa13..ef8f360 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,22 @@ source 'https://rubygems.org' -gemspec +if ENV['DEVEL'] == '1' + rails_ver = ENV.fetch('RAILS_VERSION') + gem 'rails', rails_ver + + gem 'activeadmin', ENV.fetch('ACTIVEADMIN_VERSION') + gem 'activeadmin_dynamic_fields', path: './' + + if rails_ver.start_with?('7.0') + gem 'concurrent-ruby', '1.3.4' + gem 'sqlite3', '~> 1.4' + else + gem 'sqlite3' + end +else + gemspec +end gem 'bigdecimal' gem 'mutex_m' diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a6fc275 --- /dev/null +++ b/Makefile @@ -0,0 +1,38 @@ +help: + @echo "Main targets: up / down / console / shell" + +# Docker commands +down: + docker compose down + +up: + docker compose up + +attach: + docker compose attach app + +up_attach: + docker compose up -d && docker compose attach app + +cleanup: + docker container rm -f activeadmin_dynamic_fields_app && docker image rm -f activeadmin_dynamic_fields-app + +# Rails specific commands +console: + docker compose exec -e "PAGER=more" app bin/rails console + +routes: + docker compose exec app bin/rails routes + +specs: + docker compose exec app bin/rspec --fail-fast + +# Other commands +bundle: + docker compose exec app bundle + +shell: + docker compose exec -e "PAGER=more" app bash + +lint: + docker compose exec app bin/rubocop diff --git a/README.md b/README.md index d9b844c..a9b9bd0 100644 --- a/README.md +++ b/README.md @@ -234,17 +234,61 @@ end The link url is loaded via AJAX before opening the dialog. +## Development + +Project created by [Mattia Roccoberton](http://blocknot.es), thanks also to the good guys that opened issues and pull requests from time to time. + +There 3 ways to interact with this project: + +1) Using Docker: + +```sh +# Run rails server on the dummy app (=> http://localhost:3000 to access to ActiveAdmin): +make up +# Enter in a Rails console (with the dummy app started): +make console +# Enter in a shell (with the dummy app started): +make shell +# Run the linter on the project (with the dummy app started): +make lint +# Run the test suite (with the dummy app started): +make specs +# Remove container and image: +make cleanup +# To try different versions of Ruby/Rails/ActiveAdmin edit docker-compose.yml +# For more commands please check the Makefile +``` + +2) Using Appraisal: + +```sh +export RAILS_ENV=development +# Install dependencies: +bin/appraisal +# Run server (or any command): +bin/appraisal rails s +# Or with a specific configuration: +bin/appraisal rails80-activeadmin rails s +``` + +3) With a local setup: + +```sh +# Dev setup (set the required envs): +source extra/dev_setup.sh +# Install dependencies: +bundle update +# Run server (or any command): +bin/rails s +# To try different versions of Rails/ActiveAdmin edit extra/dev_setup.sh +``` + ## Do you like it? Star it! If you use this component just star it. A developer is more motivated to improve a project when there is some interest. My other [Active Admin components](https://github.com/blocknotes?utf8=✓&tab=repositories&q=activeadmin&type=source). Or consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me). -## Contributors - -- [Mattia Roccoberton](http://blocknot.es): author -- The good guys that opened issues and pull requests from time to time - ## License The gem is available as open-source under the terms of the [MIT](LICENSE.txt). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..8896ffd --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +services: + app: + container_name: 'activeadmin_dynamic_fields_app' + build: + context: . + dockerfile: ./extra/Dockerfile + # dockerfile: ./extra/Dockerfile_alpine + args: + # Debian-based Ruby image: + RUBY_IMAGE: ruby:3.4-slim + UID: ${UID} + environment: + ACTIVEADMIN_VERSION: ~> 3.3 + RAILS_VERSION: ~> 8.0 + user: "${UID}:${GID}" + ports: + - '3000:3000' + working_dir: '/app' + volumes: + - '.:/app' + stdin_open: true + tty: true + entrypoint: + - /bin/sh + - ./extra/entrypoint.sh diff --git a/extra/Dockerfile b/extra/Dockerfile new file mode 100644 index 0000000..ca9287b --- /dev/null +++ b/extra/Dockerfile @@ -0,0 +1,21 @@ +ARG RUBY_IMAGE=ruby:3 +FROM ${RUBY_IMAGE} + +ARG UID + +ENV DEVEL=1 +ENV LANG=C.UTF-8 +ENV RAILS_ENV=development + +RUN apt-get update -qq +RUN DEBIAN_FRONTEND=noninteractive apt-get install -yqq --no-install-recommends build-essential chromium libyaml-dev nano + +RUN gem install bundler +RUN echo 'gem: --no-document' > /etc/gemrc + +RUN useradd -u ${UID} --shell /bin/bash app +RUN mkdir -p /home/app && chown -R app:app /home/app +RUN chown -R app /usr/local/bundle + +USER ${UID} +COPY . /app diff --git a/extra/Dockerfile_alpine b/extra/Dockerfile_alpine new file mode 100644 index 0000000..e960879 --- /dev/null +++ b/extra/Dockerfile_alpine @@ -0,0 +1,18 @@ +FROM ruby:3.3-alpine + +ARG UID + +ENV DEVEL=1 +ENV LANG=C.UTF-8 +ENV RAILS_ENV=development + +RUN apk update && apk add --no-cache build-base chromium tzdata yaml-dev + +RUN gem install bundler +RUN echo 'gem: --no-document' > /etc/gemrc + +RUN adduser -u ${UID} -D app +RUN mkdir -p /home/app && chown -R app:app /home/app +RUN chown -R app /usr/local/bundle + +COPY . /app diff --git a/extra/README.md b/extra/README.md deleted file mode 100644 index 87df75f..0000000 --- a/extra/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Development - -## Releases - -```sh -# Update lib/activeadmin/dynamic_fields/version.rb with the new version -# Update the gemfiles: -bin/appraisal -``` - -## Testing - -```sh -# Running specs using a specific configuration: -bin/appraisal rails61-activeadmin29 rspec -# Using latest activeadmin version: -bin/appraisal rails60-activeadmin rspec -# See gemfiles for more configurations -``` diff --git a/extra/dev_setup.sh b/extra/dev_setup.sh new file mode 100755 index 0000000..360b8ac --- /dev/null +++ b/extra/dev_setup.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +export DEVEL=1 + +export RAILS_VERSION=8.0.2 +export ACTIVEADMIN_VERSION=3.3.0 + +export RAILS_ENV=development diff --git a/extra/entrypoint.sh b/extra/entrypoint.sh new file mode 100644 index 0000000..0c9b41c --- /dev/null +++ b/extra/entrypoint.sh @@ -0,0 +1,8 @@ +echo "> Install dependencies" +rm -f Gemfile.lock && bundle install + +echo "> Run pending migrations" +cd spec/dummy && bundle exec rails db:migrate + +echo "> Start Rails server" +cd /app && rm -f spec/dummy/tmp/pids/server.pid && bundle exec rails s -b 0.0.0.0 diff --git a/spec/dummy/app/admin/tags.rb b/spec/dummy/app/admin/tags.rb index d4749f1..09beb57 100644 --- a/spec/dummy/app/admin/tags.rb +++ b/spec/dummy/app/admin/tags.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true ActiveAdmin.register Tag do + permit_params :name end diff --git a/spec/dummy/app/models/post.rb b/spec/dummy/app/models/post.rb index faa8994..cd4a75f 100644 --- a/spec/dummy/app/models/post.rb +++ b/spec/dummy/app/models/post.rb @@ -14,7 +14,11 @@ class Post < ApplicationRecord has_many :post_tags, inverse_of: :post, dependent: :destroy has_many :tags, through: :post_tags - serialize :description, coder: JSON + if Gem::Version.new(Rails.version) >= Gem::Version.new('7.1') + serialize :description, coder: JSON + else + serialize :description, JSON + end after_initialize -> { self.description = {} if description.nil? } @@ -50,13 +54,11 @@ def upper_title title.upcase end - class << self - def ransackable_associations(_auth_object = nil) - ["author", "author_profile", "post_tags", "tags"] - end + def self.ransackable_associations(_auth_object = nil) + ["author", "author_profile", "post_tags", "tags"] + end - def ransackable_attributes(_auth_object = nil) - ["author_id", "category", "created_at", "description", "dt", "id", "position", "published", "title", "updated_at"] - end + def self.ransackable_attributes(_auth_object = nil) + ["author_id", "category", "created_at", "description", "dt", "id", "position", "published", "title", "updated_at"] end end diff --git a/spec/dummy/app/models/tag.rb b/spec/dummy/app/models/tag.rb index 50a59bc..8660da8 100644 --- a/spec/dummy/app/models/tag.rb +++ b/spec/dummy/app/models/tag.rb @@ -3,4 +3,12 @@ class Tag < ApplicationRecord has_many :post_tags, inverse_of: :tag, dependent: :destroy has_many :posts, through: :post_tags + + def self.ransackable_associations(auth_object = nil) + ["post_tags", "posts"] + end + + def self.ransackable_attributes(auth_object = nil) + ["created_at", "id", "name", "updated_at"] + end end diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml index cfc4064..72b6a30 100644 --- a/spec/dummy/config/database.yml +++ b/spec/dummy/config/database.yml @@ -9,4 +9,5 @@ test: development: <<: *default - database: db/dev.sqlite3 + database: db/development.sqlite3 + schema_dump: schema_development.rb diff --git a/spec/dummy/db/schema_development.rb b/spec/dummy/db/schema_development.rb new file mode 100644 index 0000000..b55247a --- /dev/null +++ b/spec/dummy/db/schema_development.rb @@ -0,0 +1,99 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[8.0].define(version: 2018_06_07_053739) do + create_table "active_admin_comments", force: :cascade do |t| + t.string "namespace" + t.text "body" + t.string "resource_type" + t.integer "resource_id" + t.string "author_type" + t.integer "author_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id" + t.index ["namespace"], name: "index_active_admin_comments_on_namespace" + t.index ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id" + end + + create_table "active_storage_attachments", force: :cascade do |t| + t.string "name", null: false + t.string "record_type", null: false + t.integer "record_id", null: false + t.integer "blob_id", null: false + t.datetime "created_at", precision: nil, null: false + t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" + t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + end + + create_table "active_storage_blobs", force: :cascade do |t| + t.string "key", null: false + t.string "filename", null: false + t.string "content_type" + t.text "metadata" + t.bigint "byte_size", null: false + t.string "checksum", null: false + t.datetime "created_at", precision: nil, null: false + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true + end + + create_table "authors", force: :cascade do |t| + t.string "name" + t.integer "age" + t.string "email" + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false + end + + create_table "post_tags", force: :cascade do |t| + t.integer "post_id" + t.integer "tag_id" + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false + t.index ["post_id"], name: "index_post_tags_on_post_id" + t.index ["tag_id"], name: "index_post_tags_on_tag_id" + end + + create_table "posts", force: :cascade do |t| + t.string "title" + t.string "state" + t.text "description" + t.integer "author_id" + t.string "category" + t.datetime "dt", precision: nil + t.float "position" + t.boolean "published" + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false + t.index ["author_id"], name: "index_posts_on_author_id" + end + + create_table "profiles", force: :cascade do |t| + t.text "description" + t.integer "author_id" + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false + t.index ["author_id"], name: "index_profiles_on_author_id" + end + + create_table "tags", force: :cascade do |t| + t.string "name" + t.datetime "created_at", precision: nil, null: false + t.datetime "updated_at", precision: nil, null: false + end + + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" + add_foreign_key "post_tags", "posts" + add_foreign_key "post_tags", "tags" + add_foreign_key "posts", "authors" + add_foreign_key "profiles", "authors" +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 3ebd733..6e5f09d 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -26,7 +26,12 @@ end RSpec.configure do |config| - config.fixture_path = Rails.root.join('spec/fixtures') + if Gem::Version.new(Rails.version) >= Gem::Version.new('7.1') + config.fixture_paths = [Rails.root.join('spec/fixtures')] + else + config.fixture_path = Rails.root.join('spec/fixtures') + end + config.infer_spec_type_from_file_location! config.filter_rails_from_backtrace! diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 15060c4..121f474 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -9,10 +9,10 @@ Capybara::Cuprite::Driver.new( app, - window_size: [1600, 1280], + window_size: [1600, 1024], browser_options: browser_options, - process_timeout: 20, - timeout: 20, + process_timeout: 30, + timeout: 30, inspector: true, headless: !ENV['CUPRITE_HEADLESS'].in?(%w[n 0 no false]) )