diff --git a/docs/customizing_dashboards.md b/docs/customizing_dashboards.md index ffaaf8d998..8843efbcba 100644 --- a/docs/customizing_dashboards.md +++ b/docs/customizing_dashboards.md @@ -200,7 +200,8 @@ objects to display as. **Field::Select** -`:collection` - Specify the array or range to select from. Defaults to `[]`. +`:collection` - Specify the options shown on the select field. It accept either +an array or an object responding to `:call`. Defaults to `[]`. `:searchable` - Specify if the attribute should be considered when searching. Default is `true`. diff --git a/lib/administrate/field/select.rb b/lib/administrate/field/select.rb index 73b0ea570f..df4de56fcf 100644 --- a/lib/administrate/field/select.rb +++ b/lib/administrate/field/select.rb @@ -14,7 +14,10 @@ def selectable_options private def collection - @collection ||= options.fetch(:collection, []) + maybe_proc = options.fetch(:collection, []) + return maybe_proc.call if maybe_proc.respond_to? :call + + @collection ||= maybe_proc end end end diff --git a/spec/example_app/app/dashboards/product_dashboard.rb b/spec/example_app/app/dashboards/product_dashboard.rb index 75362fb74b..bf89c5272b 100644 --- a/spec/example_app/app/dashboards/product_dashboard.rb +++ b/spec/example_app/app/dashboards/product_dashboard.rb @@ -7,6 +7,7 @@ class ProductDashboard < Administrate::BaseDashboard :description, :image_url, :product_meta_tag, + :release_year, ] ATTRIBUTE_TYPES = { @@ -17,6 +18,9 @@ class ProductDashboard < Administrate::BaseDashboard name: Field::String, price: Field::Number.with_options(prefix: "$", decimals: 2), product_meta_tag: Field::HasOne, + release_year: Field::Select.with_options( + collection: -> { (Time.current.year - 10)..Time.current.year }, + ), } COLLECTION_ATTRIBUTES = ATTRIBUTES diff --git a/spec/example_app/app/models/product.rb b/spec/example_app/app/models/product.rb index 7151684ffc..8b6fceb38a 100644 --- a/spec/example_app/app/models/product.rb +++ b/spec/example_app/app/models/product.rb @@ -6,6 +6,11 @@ class Product < ApplicationRecord validates :image_url, presence: true validates :name, presence: true validates :price, presence: true + validates :release_year, + numericality: { + less_than_or_equal_to: ->(_product) { Time.current.year }, + }, + allow_blank: true validates :slug, uniqueness: true validate :valid_slug diff --git a/spec/example_app/db/migrate/20200326202615_add_release_year_to_products.rb b/spec/example_app/db/migrate/20200326202615_add_release_year_to_products.rb new file mode 100644 index 0000000000..2bdb2c39c7 --- /dev/null +++ b/spec/example_app/db/migrate/20200326202615_add_release_year_to_products.rb @@ -0,0 +1,5 @@ +class AddReleaseYearToProducts < ActiveRecord::Migration[6.0] + def change + add_column :products, :release_year, :integer, limit: 2 + end +end diff --git a/spec/example_app/db/schema.rb b/spec/example_app/db/schema.rb index bff7c0454f..0608b17e42 100644 --- a/spec/example_app/db/schema.rb +++ b/spec/example_app/db/schema.rb @@ -2,15 +2,15 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `rails +# db:schema:load`. When creating a new database, `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.define(version: 20180525115059) do +ActiveRecord::Schema.define(version: 2020_03_26_202615) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -100,6 +100,7 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "slug", null: false + t.integer "release_year", limit: 2 t.index ["slug"], name: "index_products_on_slug", unique: true end diff --git a/spec/factories.rb b/spec/factories.rb index 9551ca063f..fd87fb2aba 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -44,6 +44,7 @@ "https://cdn.recombu.com/mobile/images/news/M11370/1264769196_w670.jpg" end product_meta_tag + release_year { [2018, 2019, 2020].sample } end factory :product_meta_tag do diff --git a/spec/features/products_form_spec.rb b/spec/features/products_form_spec.rb index c38723d144..f424cdfc5e 100644 --- a/spec/features/products_form_spec.rb +++ b/spec/features/products_form_spec.rb @@ -1,6 +1,8 @@ require "rails_helper" describe "product form has_one relationship" do + include ActiveSupport::Testing::TimeHelpers + it "saves product and meta tag data correctly" do visit new_admin_product_path @@ -21,6 +23,18 @@ ) end + it "have dynamic release_year" do + visit new_admin_product_path + current_year = Time.current.year + expect(page).to have_select("Release year", with_options: [current_year]) + + travel_to(1.year.ago) do + visit new_admin_product_path + expect(page). + not_to have_select("Release year", with_options: [current_year]) + end + end + it "edits product and meta tag data correctly" do product = create(:product) diff --git a/spec/models/product_spec.rb b/spec/models/product_spec.rb index dd0af41b77..9d3aba359a 100644 --- a/spec/models/product_spec.rb +++ b/spec/models/product_spec.rb @@ -7,6 +7,11 @@ it { should validate_presence_of(:name) } it { should validate_presence_of(:price) } + it do + should validate_numericality_of(:release_year). + is_less_than_or_equal_to(Time.now.year) + end + it "should not allow names that produce empty slugs" do product = build(:product, name: "???")