Migrate from ledermann/rails-settings to rails-settings-cached which allows global settings
with YAML-defined defaults. Add admin page for editing global settings. Add "site_description" setting that would show as a paragraph on the frontpage
This commit is contained in:
		
							parent
							
								
									babc6a1528
								
							
						
					
					
						commit
						b11fdc3ae3
					
				
							
								
								
									
										3
									
								
								Gemfile
								
								
								
								
							
							
						
						
									
										3
									
								
								Gemfile
								
								
								
								
							| 
						 | 
				
			
			@ -17,6 +17,7 @@ gem 'pg'
 | 
			
		|||
gem 'pghero'
 | 
			
		||||
gem 'dotenv-rails'
 | 
			
		||||
gem 'font-awesome-rails'
 | 
			
		||||
gem 'best_in_place', '~> 3.0.1'
 | 
			
		||||
 | 
			
		||||
gem 'paperclip', '~> 5.0'
 | 
			
		||||
gem 'paperclip-av-transcoder'
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +44,7 @@ gem 'will_paginate'
 | 
			
		|||
gem 'rack-attack'
 | 
			
		||||
gem 'rack-cors', require: 'rack/cors'
 | 
			
		||||
gem 'sidekiq'
 | 
			
		||||
gem 'ledermann-rails-settings'
 | 
			
		||||
gem 'rails-settings-cached'
 | 
			
		||||
gem 'pg_search'
 | 
			
		||||
gem 'simple-navigation'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								Gemfile.lock
								
								
								
								
							
							
						
						
									
										10
									
								
								Gemfile.lock
								
								
								
								
							| 
						 | 
				
			
			@ -60,6 +60,9 @@ GEM
 | 
			
		|||
      babel-source (>= 4.0, < 6)
 | 
			
		||||
      execjs (~> 2.0)
 | 
			
		||||
    bcrypt (3.1.11)
 | 
			
		||||
    best_in_place (3.0.3)
 | 
			
		||||
      actionpack (>= 3.2)
 | 
			
		||||
      railties (>= 3.2)
 | 
			
		||||
    better_errors (2.1.1)
 | 
			
		||||
      coderay (>= 1.0.0)
 | 
			
		||||
      erubis (>= 2.6.6)
 | 
			
		||||
| 
						 | 
				
			
			@ -172,8 +175,6 @@ GEM
 | 
			
		|||
    json (1.8.3)
 | 
			
		||||
    launchy (2.4.3)
 | 
			
		||||
      addressable (~> 2.3)
 | 
			
		||||
    ledermann-rails-settings (2.4.2)
 | 
			
		||||
      activerecord (>= 3.1)
 | 
			
		||||
    letter_opener (1.4.1)
 | 
			
		||||
      launchy (~> 2.2)
 | 
			
		||||
    link_header (0.0.8)
 | 
			
		||||
| 
						 | 
				
			
			@ -259,6 +260,8 @@ GEM
 | 
			
		|||
      nokogiri (~> 1.6.0)
 | 
			
		||||
    rails-html-sanitizer (1.0.3)
 | 
			
		||||
      loofah (~> 2.0)
 | 
			
		||||
    rails-settings-cached (0.6.5)
 | 
			
		||||
      rails (>= 4.2.0)
 | 
			
		||||
    rails_12factor (0.0.3)
 | 
			
		||||
      rails_serve_static_assets
 | 
			
		||||
      rails_stdout_logging
 | 
			
		||||
| 
						 | 
				
			
			@ -405,6 +408,7 @@ DEPENDENCIES
 | 
			
		|||
  addressable
 | 
			
		||||
  autoprefixer-rails
 | 
			
		||||
  aws-sdk (>= 2.0)
 | 
			
		||||
  best_in_place (~> 3.0.1)
 | 
			
		||||
  better_errors
 | 
			
		||||
  binding_of_caller
 | 
			
		||||
  browserify-rails
 | 
			
		||||
| 
						 | 
				
			
			@ -426,7 +430,6 @@ DEPENDENCIES
 | 
			
		|||
  i18n-tasks (~> 0.9.6)
 | 
			
		||||
  jbuilder (~> 2.0)
 | 
			
		||||
  jquery-rails
 | 
			
		||||
  ledermann-rails-settings
 | 
			
		||||
  letter_opener
 | 
			
		||||
  link_header
 | 
			
		||||
  lograge
 | 
			
		||||
| 
						 | 
				
			
			@ -445,6 +448,7 @@ DEPENDENCIES
 | 
			
		|||
  rack-cors
 | 
			
		||||
  rack-timeout-puma
 | 
			
		||||
  rails (~> 5.0.1.0)
 | 
			
		||||
  rails-settings-cached
 | 
			
		||||
  rails_12factor
 | 
			
		||||
  rails_autolink
 | 
			
		||||
  react-rails
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,8 @@
 | 
			
		|||
//= require jquery
 | 
			
		||||
//= require jquery_ujs
 | 
			
		||||
//= require extras
 | 
			
		||||
//= require best_in_place
 | 
			
		||||
 | 
			
		||||
$(function () {
 | 
			
		||||
  $(".best_in_place").best_in_place();
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,10 @@
 | 
			
		|||
      text-decoration: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  strong {
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
samp {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,10 +4,10 @@ class AboutController < ApplicationController
 | 
			
		|||
  before_action :set_body_classes
 | 
			
		||||
 | 
			
		||||
  def index
 | 
			
		||||
    @description = Setting.site_description
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def terms
 | 
			
		||||
  end
 | 
			
		||||
  def terms; end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Admin::SettingsController < ApplicationController
 | 
			
		||||
  before_action :require_admin!
 | 
			
		||||
 | 
			
		||||
  layout 'admin'
 | 
			
		||||
 | 
			
		||||
  def index
 | 
			
		||||
    @settings = Setting.all_as_records
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update
 | 
			
		||||
    @setting = Setting.where(var: params[:id]).first_or_initialize(var: params[:id])
 | 
			
		||||
 | 
			
		||||
    if @setting.value != params[:setting][:value]
 | 
			
		||||
      @setting.value = params[:setting][:value]
 | 
			
		||||
      @setting.save
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    respond_to do |format|
 | 
			
		||||
      format.html { redirect_to admin_settings_path }
 | 
			
		||||
      format.json { respond_with_bip(@setting) }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -8,14 +8,18 @@ class Settings::PreferencesController < ApplicationController
 | 
			
		|||
  def show; end
 | 
			
		||||
 | 
			
		||||
  def update
 | 
			
		||||
    current_user.settings(:notification_emails).follow         = user_params[:notification_emails][:follow]         == '1'
 | 
			
		||||
    current_user.settings(:notification_emails).follow_request = user_params[:notification_emails][:follow_request] == '1'
 | 
			
		||||
    current_user.settings(:notification_emails).reblog         = user_params[:notification_emails][:reblog]         == '1'
 | 
			
		||||
    current_user.settings(:notification_emails).favourite      = user_params[:notification_emails][:favourite]      == '1'
 | 
			
		||||
    current_user.settings(:notification_emails).mention        = user_params[:notification_emails][:mention]        == '1'
 | 
			
		||||
    current_user.settings['notification_emails'] = {
 | 
			
		||||
      follow:         user_params[:notification_emails][:follow]         == '1',
 | 
			
		||||
      follow_request: user_params[:notification_emails][:follow_request] == '1',
 | 
			
		||||
      reblog:         user_params[:notification_emails][:reblog]         == '1',
 | 
			
		||||
      favourite:      user_params[:notification_emails][:favourite]      == '1',
 | 
			
		||||
      mention:        user_params[:notification_emails][:mention]        == '1',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    current_user.settings(:interactions).must_be_follower  = user_params[:interactions][:must_be_follower]  == '1'
 | 
			
		||||
    current_user.settings(:interactions).must_be_following = user_params[:interactions][:must_be_following] == '1'
 | 
			
		||||
    current_user.settings['interactions'] = {
 | 
			
		||||
      must_be_follower:  user_params[:interactions][:must_be_follower]  == '1',
 | 
			
		||||
      must_be_following: user_params[:interactions][:must_be_following] == '1',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if current_user.update(user_params.except(:notification_emails, :interactions))
 | 
			
		||||
      redirect_to settings_preferences_path, notice: I18n.t('generic.changes_saved_msg')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,4 +14,8 @@ module SettingsHelper
 | 
			
		|||
  def human_locale(locale)
 | 
			
		||||
    HUMAN_LOCALES[locale]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def hash_to_object(hash)
 | 
			
		||||
    HashObject.new(hash)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class HashObject
 | 
			
		||||
  def initialize(hash)
 | 
			
		||||
    hash.each do |k, v|
 | 
			
		||||
      instance_variable_set("@#{k}", v)
 | 
			
		||||
      self.class.send(:define_method, k, proc { instance_variable_get("@#{k}") })
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Setting < RailsSettings::Base
 | 
			
		||||
  source Rails.root.join('config/settings.yml')
 | 
			
		||||
  namespace Rails.env
 | 
			
		||||
 | 
			
		||||
  def to_param
 | 
			
		||||
    var
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class << self
 | 
			
		||||
    def all_as_records
 | 
			
		||||
      vars    = thing_scoped
 | 
			
		||||
      records = vars.map { |r| [r.var, r] }.to_h
 | 
			
		||||
 | 
			
		||||
      default_settings.each do |key, default_value|
 | 
			
		||||
        next if records.key?(key) || default_value.is_a?(Hash)
 | 
			
		||||
        records[key] = Setting.new(var: key, value: default_value)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      records
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def default_settings
 | 
			
		||||
      return {} unless RailsSettings::Default.enabled?
 | 
			
		||||
      RailsSettings::Default.instance
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class User < ApplicationRecord
 | 
			
		||||
  include RailsSettings::Extend
 | 
			
		||||
 | 
			
		||||
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable
 | 
			
		||||
 | 
			
		||||
  belongs_to :account, inverse_of: :user
 | 
			
		||||
| 
						 | 
				
			
			@ -14,11 +16,6 @@ class User < ApplicationRecord
 | 
			
		|||
  scope :recent,   -> { order('id desc') }
 | 
			
		||||
  scope :admins,   -> { where(admin: true) }
 | 
			
		||||
 | 
			
		||||
  has_settings do |s|
 | 
			
		||||
    s.key :notification_emails, defaults: { follow: false, reblog: false, favourite: false, mention: false, follow_request: true }
 | 
			
		||||
    s.key :interactions, defaults: { must_be_follower: false, must_be_following: false }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def send_devise_notification(notification, *args)
 | 
			
		||||
    devise_mailer.send(notification, self, *args).deliver_later
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,8 +41,8 @@ class NotifyService < BaseService
 | 
			
		|||
    blocked ||= @recipient.id == @notification.from_account.id                                                                     # Skip for interactions with self
 | 
			
		||||
    blocked ||= @recipient.blocking?(@notification.from_account)                                                                   # Skip for blocked accounts
 | 
			
		||||
    blocked ||= (@notification.from_account.silenced? && !@recipient.following?(@notification.from_account))                       # Hellban
 | 
			
		||||
    blocked ||= (@recipient.user.settings(:interactions).must_be_follower  && !@notification.from_account.following?(@recipient)) # Options
 | 
			
		||||
    blocked ||= (@recipient.user.settings(:interactions).must_be_following && !@recipient.following?(@notification.from_account)) # Options
 | 
			
		||||
    blocked ||= (@recipient.user.settings.interactions['must_be_follower']  && !@notification.from_account.following?(@recipient)) # Options
 | 
			
		||||
    blocked ||= (@recipient.user.settings.interactions['must_be_following'] && !@recipient.following?(@notification.from_account)) # Options
 | 
			
		||||
    blocked ||= send("blocked_#{@notification.type}?")                                                                             # Type-dependent filters
 | 
			
		||||
    blocked
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			@ -58,6 +58,6 @@ class NotifyService < BaseService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def email_enabled?
 | 
			
		||||
    @recipient.user.settings(:notification_emails).send(@notification.type)
 | 
			
		||||
    @recipient.user.settings.notification_emails[@notification.type]
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
  %meta{ property: 'og:site_name', content: 'Mastodon' }/
 | 
			
		||||
  %meta{ property: 'og:type', content: 'website' }/
 | 
			
		||||
  %meta{ property: 'og:title', content: Rails.configuration.x.local_domain }/
 | 
			
		||||
  %meta{ property: 'og:description', content: "Mastodon is a free, open-source social network server. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Anyone can run Mastodon and participate in the social network seamlessly" }/
 | 
			
		||||
  %meta{ property: 'og:description', content: @description.blank? ? "Mastodon is a free, open-source social network server. A decentralized alternative to commercial platforms, it avoids the risks of a single company monopolizing your communication. Anyone can run Mastodon and participate in the social network seamlessly" : strip_tags(@description) }/
 | 
			
		||||
  %meta{ property: 'og:image', content: asset_url('mastodon_small.jpg') }/
 | 
			
		||||
  %meta{ property: 'og:image:width', content: '400' }/
 | 
			
		||||
  %meta{ property: 'og:image:height', content: '400' }/
 | 
			
		||||
| 
						 | 
				
			
			@ -24,6 +24,9 @@
 | 
			
		|||
 | 
			
		||||
  .screenshot= image_tag 'screenshot.png'
 | 
			
		||||
 | 
			
		||||
  - unless @description.blank?
 | 
			
		||||
    %p= @description.html_safe
 | 
			
		||||
 | 
			
		||||
  .actions
 | 
			
		||||
    .info
 | 
			
		||||
      = link_to t('about.terms'), terms_path
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
- content_for :page_title do
 | 
			
		||||
  Site Settings
 | 
			
		||||
 | 
			
		||||
%table.table
 | 
			
		||||
  %colgroup
 | 
			
		||||
    %col{ width: '35%' }/
 | 
			
		||||
  %thead
 | 
			
		||||
    %tr
 | 
			
		||||
      %th Setting
 | 
			
		||||
      %th Click to edit
 | 
			
		||||
  %tbody
 | 
			
		||||
    %tr
 | 
			
		||||
      %td
 | 
			
		||||
        %strong Site description
 | 
			
		||||
        %br/
 | 
			
		||||
        Displayed as a paragraph on the frontpage and used as a meta tag.
 | 
			
		||||
        %br/
 | 
			
		||||
        You can use HTML tags, in particular
 | 
			
		||||
        %code= '<a>'
 | 
			
		||||
        and
 | 
			
		||||
        %code= '<em>'
 | 
			
		||||
      %td= best_in_place @settings['site_description'], :value, as: :textarea, url: admin_setting_path(@settings['site_description'])
 | 
			
		||||
| 
						 | 
				
			
			@ -6,14 +6,14 @@
 | 
			
		|||
 | 
			
		||||
  = f.input :locale, collection: I18n.available_locales, wrapper: :with_label, include_blank: false, label_method: lambda { |locale| human_locale(locale) }
 | 
			
		||||
 | 
			
		||||
  = f.simple_fields_for :notification_emails, current_user.settings(:notification_emails) do |ff|
 | 
			
		||||
  = f.simple_fields_for :notification_emails, hash_to_object(current_user.settings.notification_emails) do |ff|
 | 
			
		||||
    = ff.input :follow, as: :boolean, wrapper: :with_label
 | 
			
		||||
    = ff.input :follow_request, as: :boolean, wrapper: :with_label
 | 
			
		||||
    = ff.input :reblog, as: :boolean, wrapper: :with_label
 | 
			
		||||
    = ff.input :favourite, as: :boolean, wrapper: :with_label
 | 
			
		||||
    = ff.input :mention, as: :boolean, wrapper: :with_label
 | 
			
		||||
 | 
			
		||||
  = f.simple_fields_for :interactions, current_user.settings(:interactions) do |ff|
 | 
			
		||||
  = f.simple_fields_for :interactions, hash_to_object(current_user.settings.interactions) do |ff|
 | 
			
		||||
    = ff.input :must_be_follower, as: :boolean, wrapper: :with_label
 | 
			
		||||
    = ff.input :must_be_following, as: :boolean, wrapper: :with_label
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,5 +7,6 @@ SimpleNavigation::Configuration.run do |navigation|
 | 
			
		|||
    primary.item :domain_blocks, safe_join([fa_icon('lock fw'), 'Domain Blocks']), admin_domain_blocks_url
 | 
			
		||||
    primary.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url
 | 
			
		||||
    primary.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url
 | 
			
		||||
    primary.item :settings, safe_join([fa_icon('cogs fw'), 'Site Settings']), admin_settings_url
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,6 +58,7 @@ Rails.application.routes.draw do
 | 
			
		|||
  namespace :admin do
 | 
			
		||||
    resources :pubsubhubbub, only: [:index]
 | 
			
		||||
    resources :domain_blocks, only: [:index, :create]
 | 
			
		||||
    resources :settings, only: [:index, :update]
 | 
			
		||||
 | 
			
		||||
    resources :accounts, only: [:index, :show, :update] do
 | 
			
		||||
      member do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
# config/app.yml for rails-settings-cached
 | 
			
		||||
defaults: &defaults
 | 
			
		||||
  site_description: ''
 | 
			
		||||
  site_contact_username: ''
 | 
			
		||||
  site_contact_email: ''
 | 
			
		||||
  notification_emails:
 | 
			
		||||
    follow: false
 | 
			
		||||
    reblog: false
 | 
			
		||||
    favourite: false
 | 
			
		||||
    mention: false
 | 
			
		||||
    follow_request: true
 | 
			
		||||
  interactions:
 | 
			
		||||
    must_be_follower: false
 | 
			
		||||
    must_be_following: false
 | 
			
		||||
 | 
			
		||||
development:
 | 
			
		||||
  <<: *defaults
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
  <<: *defaults
 | 
			
		||||
 | 
			
		||||
production:
 | 
			
		||||
  <<: *defaults
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
class MigrateSettings < ActiveRecord::Migration
 | 
			
		||||
  def up
 | 
			
		||||
    remove_index :settings, [:target_type, :target_id, :var]
 | 
			
		||||
    rename_column :settings, :target_id, :thing_id
 | 
			
		||||
    rename_column :settings, :target_type, :thing_type
 | 
			
		||||
    change_column :settings, :thing_id, :integer, null: true, default: nil
 | 
			
		||||
    change_column :settings, :thing_type, :string, null: true, default: nil
 | 
			
		||||
    add_index :settings, [:thing_type, :thing_id, :var], unique: true
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    remove_index :settings, [:thing_type, :thing_id, :var]
 | 
			
		||||
    rename_column :settings, :thing_id, :target_id
 | 
			
		||||
    rename_column :settings, :thing_type, :target_type
 | 
			
		||||
    change_column :settings, :target_id, :integer, null: false
 | 
			
		||||
    change_column :settings, :target_type, :string, null: false, default: ''
 | 
			
		||||
    add_index :settings, [:target_type, :target_id, :var], unique: true
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@
 | 
			
		|||
#
 | 
			
		||||
# It's strongly recommended that you check this file into your version control system.
 | 
			
		||||
 | 
			
		||||
ActiveRecord::Schema.define(version: 20170109120109) do
 | 
			
		||||
ActiveRecord::Schema.define(version: 20170112154826) do
 | 
			
		||||
 | 
			
		||||
  # These are extensions that must be enabled in order to support this database
 | 
			
		||||
  enable_extension "plpgsql"
 | 
			
		||||
| 
						 | 
				
			
			@ -240,11 +240,11 @@ ActiveRecord::Schema.define(version: 20170109120109) do
 | 
			
		|||
  create_table "settings", force: :cascade do |t|
 | 
			
		||||
    t.string   "var",        null: false
 | 
			
		||||
    t.text     "value"
 | 
			
		||||
    t.string   "target_type", null: false
 | 
			
		||||
    t.integer  "target_id",   null: false
 | 
			
		||||
    t.string   "thing_type"
 | 
			
		||||
    t.integer  "thing_id"
 | 
			
		||||
    t.datetime "created_at"
 | 
			
		||||
    t.datetime "updated_at"
 | 
			
		||||
    t.index ["target_type", "target_id", "var"], name: "index_settings_on_target_type_and_target_id_and_var", unique: true, using: :btree
 | 
			
		||||
    t.index ["thing_type", "thing_id", "var"], name: "index_settings_on_thing_type_and_thing_id_and_var", unique: true, using: :btree
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  create_table "statuses", force: :cascade do |t|
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue