Created
July 5, 2017 22:26
-
-
Save abicky/e72e3a9799a46ccae3c6e24411388399 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @example | |
# class User < ApplicationRecord | |
# include HasSetting | |
# has_setting :setting, :user_setting_item | |
# end | |
# | |
# # == Schema Information | |
# # | |
# # Table name: user_settings | |
# # | |
# # id :integer unsigned, not null, primary key | |
# # user_id :integer unsigned, not null | |
# # user_setting_item_id :integer unsigned, not null | |
# # flag :boolean default(FALSE), not null | |
# # | |
# # Indexes | |
# # | |
# # ux_user_id_user_setting_item_id (user_id,user_setting_item_id) UNIQUE | |
# # | |
# class UserSettting < ApplicationRecord | |
# belongs_to :user_setting_item | |
# delegate :name, to: :user_setting_item | |
# end | |
# | |
# # == Schema Information | |
# # | |
# # Table name: user_setting_items | |
# # | |
# # id :integer unsigned, not null, primary key | |
# # name :string(255) not null | |
# # | |
# class UserSetttingItem < ApplicationRecord | |
# end | |
# | |
# UserSetttingItem.create!(name: 'foo') | |
# UserSetttingItem.create!(name: 'bar') | |
# | |
# user = User.first | |
# user.setting.enabled #=> [] | |
# user.setting.update!(foo: true, bar: true) | |
# user.setting.enabled #=> ["foo", "bar"] | |
# user.setting.enabled?(:foo) #=> true | |
# user.setting.disable(:foo) | |
# user.setting.enabled?(:foo) #=> false | |
# user.setting.save | |
# user.setting.save! | |
module HasSetting | |
extend ActiveSupport::Concern | |
included do | |
class_attribute :__assoc_to_setting_name_assoc | |
end | |
class_methods do | |
# @param assoc [Symbol] association name for the setting | |
# @param setting_name_assoc [Symbol] association name of the setting name | |
# @param has_many_opts [Hash] options for +has_many+ | |
def has_setting(assoc, setting_name_assoc, **has_many_opts) | |
self.__assoc_to_setting_name_assoc ||= {} | |
self.__assoc_to_setting_name_assoc[assoc] = setting_name_assoc | |
has_many assoc, -> { includes(setting_name_assoc).extending(Extension) }, has_many_opts | |
end | |
end | |
module Extension | |
def enabled?(name) | |
!!find_setting(name)&.flag | |
end | |
def enabled | |
each.with_object([]) do |setting, names| | |
next unless setting.flag | |
names << setting.name | |
end | |
end | |
def enable(*names) | |
with_setting_cache do | |
names.each do |name| | |
find_or_initialize(name).flag = true | |
end | |
end | |
end | |
def disable(*names) | |
names.each do |name| | |
find_setting(name)&.flag=(false) | |
end | |
end | |
def save | |
transaction do | |
all? { |setting| setting.save } | |
end | |
end | |
def save! | |
transaction do | |
each { |setting| setting.save! } | |
end | |
end | |
def update!(settings) | |
with_setting_cache do | |
settings.each do |name, flag| | |
if flag | |
enable(name) | |
else | |
disable(name) | |
end | |
end | |
end | |
save! | |
end | |
private | |
def setting_name_refrectoin | |
setting_name_assoc = proxy_association.owner.__assoc_to_setting_name_assoc[proxy_association.reflection.name] | |
proxy_association.klass.reflect_on_association(setting_name_assoc) | |
end | |
def name_to_id(name) | |
name_to_id = @__setting_cache&.[](:name_to_id) || setting_name_refrectoin.klass.pluck(:name, :id).to_h | |
@__setting_cache[:name_to_id] = name_to_id if @__setting_cache | |
id = name_to_id[name.to_s] | |
raise ArgumentError, "Unknown item: #{name}" if id.nil? | |
id | |
end | |
def with_setting_cache | |
@__with_setting_cache_depth ||= 0 | |
@__with_setting_cache_depth += 1 | |
@__setting_cache = {} | |
yield | |
ensure | |
@__with_setting_cache_depth -= 1 | |
remove_instance_variable(:@__setting_cache) if @__with_setting_cache_depth.zero? | |
end | |
def find_setting(name) | |
find { |setting| setting.name == name.to_s } | |
end | |
def find_or_initialize(name) | |
find_setting(name) || proxy_association.build(setting_name_refrectoin.foreign_key => name_to_id(name)) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment