application record: add array_attribute method.

Add `array_attribute` method that defines helper methods for converting
array attributes to or from strings.
This commit is contained in:
evazion
2018-11-13 16:25:45 -06:00
parent a57d4a9558
commit b660aeefd7
5 changed files with 37 additions and 16 deletions

View File

@@ -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

View File

@@ -269,6 +269,37 @@ class ApplicationRecord < ActiveRecord::Base
end
end
concerning :AttributeMethods do
class_methods do
# Defines `<attribute>_string`, `<attribute>_string=`, and `<attribute>=`
# methods for converting an array attribute to or from a string.
#
# The `<attribute>=` 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

View File

@@ -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.")

View File

@@ -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 %>

View File

@@ -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" %>