Add new has_json to add Account#settings to restrict room creation to only administrators

This commit is contained in:
David Heinemeier Hansson
2025-11-27 17:15:26 +01:00
parent b7c7d99dcd
commit bea2c89c2b
7 changed files with 88 additions and 1 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ class AccountsController < ApplicationController
end
def account_params
params.require(:account).permit(:name, :logo)
params.require(:account).permit(:name, :logo, settings: {})
end
def account_users
+9
View File
@@ -2,4 +2,13 @@ module AccountsHelper
def account_logo_tag(style: nil)
tag.figure image_tag(fresh_account_logo_path, alt: "Account logo", size: 300), class: "account-logo avatar #{style}"
end
def button_to_toggle_setting(label, setting)
button_to account_path(account: { settings: { setting => !Current.account.settings.send("#{setting}?") } }),
method: :put,
role: "checkbox", aria: { checked: true, labelledby: "#{setting}_account_setting" }, tabindex: 0,
class: "btn" do
tag.span(label, id: "#{setting}_account_setting")
end
end
end
+1
View File
@@ -2,4 +2,5 @@ class Account < ApplicationRecord
include Joinable
has_one_attached :logo
has_json settings: { restrict_room_creation_to_administrators: :boolean }, delegate: true
end
+6
View File
@@ -64,6 +64,12 @@
<% end %>
</div>
<% end %>
<% if Current.account.restrict_room_creation_to_administrators? %>
<%= button_to_toggle_setting "Allow everyone to create new rooms", :restrict_room_creation_to_administrators %>
<% else %>
<%= button_to_toggle_setting "Only allow admins to create new rooms", :restrict_room_creation_to_administrators %>
<% end %>
<% else %>
<%= account_logo_tag style: "txt-xx-large center" %>
<h1 class="flex-item-grow txt-x-large"><%= @account.name %></h1>
@@ -0,0 +1,5 @@
class AddAccountSettings < ActiveRecord::Migration[7.2]
def change
add_column :accounts, :settings, :json, default: {}
end
end
+52
View File
@@ -0,0 +1,52 @@
module ActiveRecord
class TypedJson
def initialize(schema, data:)
@schema, @data = schema, data
end
def assign_data_with_type_casting(new_data)
new_data.each do |key, value|
@data[key] = ActiveModel::Type.lookup(@schema[key.to_sym]).cast(value)
end
end
private
def method_missing(method_name, *args, **kwargs)
key = method_name.to_s.remove(/(\?|=)/)
if key_type = @schema[key.to_sym]
if method_name.ends_with?("?")
@data[key].present?
elsif method_name.ends_with?("=")
value = args.first
@data[key] = ActiveModel::Type.lookup(key_type).cast(value)
else
@data.fetch(key)
end
else
super
end
end
def respond_to_missing?(method_name, include_private = false)
@schema.key?(method_name.to_s.remove(/[?=]/).to_sym) || super
end
end
class Base
class << self
def has_json(delegate: false, **schemas)
schemas.each do |name, schema|
define_method(name) { ActiveRecord::TypedJson.new(schema, data: self[name]) }
define_method("#{name}=") { |data| send(name).assign_data_with_type_casting(data) }
schema.keys.each do |schema_key|
define_method(schema_key) { send(name).send(schema_key) }
define_method("#{schema_key}?") { send(name).send("#{schema_key}?") }
define_method("#{schema_key}=") { |value| send(name).send("#{schema_key}=", value) }
end if delegate
end
end
end
end
end
+14
View File
@@ -1,4 +1,18 @@
require "test_helper"
class AccountTest < ActiveSupport::TestCase
test "settings" do
accounts(:signal).restrict_room_creation_to_administrators = true
assert accounts(:signal).restrict_room_creation_to_administrators?
assert_equal({ "restrict_room_creation_to_administrators" => true }, accounts(:signal)[:settings])
accounts(:signal).update!(settings: { "restrict_room_creation_to_administrators" => "true" })
assert accounts(:signal).reload.restrict_room_creation_to_administrators?
accounts(:signal).restrict_room_creation_to_administrators = false
assert_not accounts(:signal).restrict_room_creation_to_administrators?
assert_equal({ "restrict_room_creation_to_administrators" => false }, accounts(:signal)[:settings])
accounts(:signal).update!(settings: { "restrict_room_creation_to_administrators" => "false" })
assert_not accounts(:signal).reload.restrict_room_creation_to_administrators?
end
end