diff --git a/app/controllers/pools_controller.rb b/app/controllers/pools_controller.rb index 610c22c7e..2f183e4dd 100644 --- a/app/controllers/pools_controller.rb +++ b/app/controllers/pools_controller.rb @@ -94,7 +94,7 @@ class PoolsController < ApplicationController private def pool_params - permitted_params = %i[name description category is_active post_ids] + permitted_params = %i[name description category is_active post_ids post_ids_string] params.require(:pool).permit(*permitted_params, post_ids: []) end end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 42dced560..e80fe1ccd 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -269,6 +269,37 @@ class ApplicationRecord < ActiveRecord::Base end end + concerning :AttributeMethods do + class_methods do + # Defines `_string`, `_string=`, and `=` + # methods for converting an array attribute to or from a string. + # + # The `=` setter parses strings into an array using the + # `parse` regex. The resulting strings can be converted to another type + # with the `cast` option. + def array_attribute(name, parse: /[^[:space:]]+/, cast: :itself) + define_method "#{name}_string" do + send(name).join(" ") + end + + define_method "#{name}_string=" do |value| + raise ArgumentError, "#{name} must be a String" unless value.respond_to?(:to_str) + send("#{name}=", value) + end + + define_method "#{name}=" do |value| + if value.respond_to?(:to_str) + super value.to_str.scan(parse).map(&cast) + elsif value.respond_to?(:to_a) + super value.to_a + else + raise ArgumentError, "#{name} must be a String or an Array" + end + end + end + end + end + def warnings @warnings ||= ActiveModel::Errors.new(self) end diff --git a/app/models/pool.rb b/app/models/pool.rb index 115088842..6df6a08cc 100644 --- a/app/models/pool.rb +++ b/app/models/pool.rb @@ -1,13 +1,15 @@ class Pool < ApplicationRecord class RevertError < Exception ; end + array_attribute :post_ids, parse: /\d+/, cast: :to_i + belongs_to_creator + validates_uniqueness_of :name, case_sensitive: false, if: :name_changed? validate :validate_name, if: :name_changed? validates_inclusion_of :category, :in => %w(series collection) validate :updater_can_change_category validate :updater_can_remove_posts validate :updater_can_edit_deleted - belongs_to_creator before_validation :normalize_post_ids before_validation :normalize_name after_save :update_category_pseudo_tags_for_posts_async @@ -153,18 +155,6 @@ class Pool < ApplicationRecord self.post_ids = post_ids.uniq if is_collection? end - # allow assigning a string to post_ids so it can be assigned from the text - # field in the pool edit form (PUT /pools/1?post_ids=1+2+3). - def post_ids=(value) - if value.respond_to?(:to_str) - super value.to_str.scan(/\d+/).map(&:to_i) - elsif value.respond_to?(:to_a) - super value.to_a - else - raise ArgumentError, "post_ids must be a String or an Array" - end - end - def revert_to!(version) if id != version.pool_id raise RevertError.new("You cannot revert to a previous version of another pool.") diff --git a/app/views/pools/edit.html.erb b/app/views/pools/edit.html.erb index 460a0ba5c..53318d5bc 100644 --- a/app/views/pools/edit.html.erb +++ b/app/views/pools/edit.html.erb @@ -8,7 +8,7 @@ <%= f.input :name, :as => :string, :input_html => { :value => @pool.pretty_name } %> <%= dtext_field "pool", "description" %> <%= dtext_preview_button "pool", "description" %> - <%= f.input :post_ids, as: :text, label: "Posts", input_html: { value: @pool.post_ids.join(" ") } %> + <%= f.input :post_ids_string, as: :text, label: "Posts" %> <%= f.input :category, :collection => ["series", "collection"], :include_blank => false %> <%= f.input :is_active %> <%= f.button :submit %> diff --git a/app/views/pools/new.html.erb b/app/views/pools/new.html.erb index d3d28221f..b1156a0f4 100644 --- a/app/views/pools/new.html.erb +++ b/app/views/pools/new.html.erb @@ -7,7 +7,7 @@ <%= simple_form_for(@pool) do |f| %> <%= f.input :name, :as => :string, :required => true %> <%= dtext_field "pool", "description" %> - <%= f.input :post_ids, as: :text, label: "Posts", input_html: { value: @pool.post_ids.join(" ") } %> + <%= f.input :post_ids_string, as: :text, label: "Posts" %> <%= f.input :category, :collection => ["series", "collection"], :include_blank => true, :selected => "", :required => true %> <%= f.input :is_active %> <%= f.button :submit, "Submit" %>