gpt4 book ai didi

ruby-on-rails - 向模型添加按位虚拟列

转载 作者:行者123 更新时间:2023-12-04 05:56:38 26 4
gpt4 key购买 nike

我正在现有数据库上构建这个 RoR 站点。数据库上的用户模型有一个名为“secret”的列,它是一个按位整数,包含用户设置为 secret 的列的信息(名字、姓氏等)。

变量是 2 的幂,例如:姓氏 = 1<<1 = 2,名字 = 1<<2 = 4,电子邮件 == 1<<3 = 8,等等。所以如果用户设置了名字& email 为 secret,列值变为 4+8 = 12。

现在,我正在尝试找到一种通用方法将这些虚拟列实现到 Rails 模型中。所以,我可以这样做(只是一个虚拟的例子,重点是,我想检索和存储状态):

if user.secret_email?
user.secret_name_last = true
user.secret_name_first = false
end

如何将这些虚拟列巧妙地实现到模型中(无需修改现有数据库)?目前我有关注。它有效,但并不整洁。由于我有 20 个 secret 列,因此代码看起来非常难看。
  SECRET_NAME_LAST    = (1 << 1) # 2
attr_accessible :secret_name_last
def secret_name_last; secret & SECRET_NAME_LAST > 0 unless secret.nil?; end
def secret_name_last=(value); secret_set_value(SECRET_NAME_LAST, value); end

SECRET_NAME_FIRST = (1 << 2) # 4
attr_accessible :secret_name_first
def secret_name_first; secret & SECRET_NAME_FIRST > 0 unless secret.nil?; end
def secret_name_first=(value); secret_set_value(SECRET_NAME_FIRST, value); end

SECRET_EMAIL = (1 << 3) # 8
attr_accessible :secret_email
def secret_email; secret & SECRET_EMAIL > 0 unless secret.nil?; end
def secret_email=(value); secret_set_value(SECRET_EMAIL, value); end

***snip (17 more)***

private
def secret_set_value(item, value)
if self.secret.nil?
self.secret = 0
end

if value == "1" || value == true || value == 1
# Add item to secret column (if it doesn't exist)
if self.secret & item == 0
self.secret += item
end
else
# Remove item from secret column (if it exists)
if self.secret & item > 0
self.secret -= item
end
end
end

我可以做类似的事情会很棒:
as_bitwise :secret_name_first, :column=>'secret', :value=>4
as_bitwise :secret_name_last, :column=>'secret', :value=>2

甚至,
as_bitwise :secret, { :secret_name_last=>4, :secret_name_first=>2 }

编辑

根据 Brandan 的出色回答,这就是我目前所得到的:
  module BitwiseColumn
extend ActiveSupport::Concern

module ClassMethods
def bitwise_column(*args)
mapping = args.extract_options!
column_name = args.shift
real_column_name = args.shift

logger.debug "Initializing bitwisecolumn, column: " + column_name.to_s

mapping.each_pair do |attribute, offset|
logger.debug "\tSetting a pair: offset: " + offset.to_s + ", " + attribute.to_s
mask = 2 ** offset

class_eval %{
attr_accessible :#{column_name}_#{attribute}
def #{column_name}_#{attribute}?
#{real_column_name} & #{mask} > 0 unless #{real_column_name}.nil?
end

def #{column_name}_#{attribute}=(value)
if self.#{real_column_name}.nil?
self.#{real_column_name} = 0
end

if value == "1" || value == true || value == 1
if self.#{real_column_name} & #{mask} == 0
self.#{real_column_name} += #{mask}
end
else
if self.#{real_column_name} & #{mask} > 0
self.#{real_column_name} -= #{mask}
end
end
end
}
end
end
end
end

这允许我使用:
  bitwise_column :secret, :realsecretcolumnatdatabase, :name_last=>1, :name_first=>2, :email=>3, :picture=>5, :dob=>6, :place=>12

之后,我可以调用 User.first.secret_name_last 吗?等等

最佳答案

您可以使用 class_eval干掉你的代码。我还建议将此行为分解为与您的User 分开的某种模块。类,以便您可以彻底地测试它,并与其他 User 分开- 特定的行为。

和你一样,我倾向于使用所需的 API 开始这些类型的任务,然后向后工作。我在我的模型中开始使用这个:

class User < ActiveRecord::Base
include BitwiseColumn

bitwise_column :secret, :first_name => 1, :last_name => 2
end

传递给 bitwise_column 的哈希值将虚拟属性名称作为指数映射到它们的掩码值。我觉得这比自己记住 2 的力量更容易管理:-)

然后我创建了mixin:
module BitwiseColumn
extend ActiveSupport::Concern

module ClassMethods
def bitwise_column(*args)
mapping = args.extract_options!
column_name = args.shift

mapping.each_pair do |attribute, offset|
mask = 2 ** offset

class_eval %{
def secret_#{attribute}?
#{column_name} & #{mask} > 0 unless #{column_name}.nil?
end

def secret_#{attribute}=(value)
if self.#{column_name}.nil?
self.#{column_name} = 0
end

if value == "1" || value == true || value == 1
if self.#{column_name} & #{mask} == 0
self.#{column_name} += #{mask}
end
else
if self.#{column_name} & #{mask} > 0
self.#{column_name} -= #{mask}
end
end
end
}
end
end
end
end

这个 mixin 为每个虚拟属性创建了两个实例方法,一个带有 ?一个带有 = ,因为这似乎是你所追求的。我将您现有的逻辑用于按位运算,这似乎工作得很好。

关于ruby-on-rails - 向模型添加按位虚拟列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9447632/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com