嘿伙计们,关注Rails和STI的问题:
我有以下课程:
class Account < AC::Base
has_many :users
end
class User < AC::Base
extend STI
belongs_to :account
class Standard < User
before_save :some_callback
end
class Other < User
end
end
module STI
def new(*args, &block)
type = args.dup.extract_options!.with_indifferent_access.delete(:type)
if type.blank? or (type = type.constantize) == self
super(*args, &block)
else
type.new(*args, &block)
end
end
end
现在问题是:
如果不重写User.new
(在模块STI中),User::Standard
内的回调永远不会被调用,否则如果我以这种方式创建用户,则account_id始终为nil
:
account.users.create([{ :type => 'User::Standard', :firstname => ... }, { :type => 'User::Other', :firstname => ... }])
如果我对模块使用不同的方法,如:
module STI
def new(*args, &block)
type = args.dup.extract_options!.with_indifferent_access.delete(:type)
if type.blank? or (type = type.constantize) == self
super(*args, &block)
else
super(*args, &block).becomes(type)
end
end
end
然后不共享实例变量,因为它正在创建一个新对象。 如果没有将回调移动到父类并检查类的类型,是否有解决此问题的方法?
格尔茨 马里奥
答案 0 :(得分:0)
也许有些事情我不知道,但我从未见过以这种方式定义的Rails STI类。通常它看起来像......
应用程序/模型/ user.rb:
class User < AC::Base
belongs_to :account
end
应用程序/模型/用户/ standard.rb:
module Users
class Standard < User
before_save :some_callback
end
end
应用程序/模型/用户/ other.rb:
module Users
class Other < User
end
end
看起来好像是在将类范围(类“生活”与其他类,模块,方法等相关)与类继承(由“class Standard&lt; User”表示)混淆在一起。 Rails STI关系涉及继承但不关心范围。也许你试图通过嵌套继承的类来完成一些非常具体的东西,我只是想念它。但如果没有,它可能会导致你的一些问题。
现在特别转向回调。标准中的回调没有被调用,因为“account.users”关系使用的是User类,而不是Standard类(但我想你已经知道了)。有几种方法可以解决这个问题(我将在示例中使用我的类结构):
一:
class Account
has_many :users, :class_name => Users::Standard.name
end
这将强制所有account.users使用Standard类。如果您需要其他用户的可能性,那么......
二:
class Account
has_many :users # Use this to look up any user
has_many :standard_users, :class_name => Users::Standard.name # Use this to look up/create only Standards
has_many :other_users, :class_name => Users::Other.name # Use this to look up/create only Others
end
三:
只需在代码中手动调用Users :: Standard.create()和Users :: Other.create()。
我确信还有很多其他方法可以实现这一目标,但可能最简单。
答案 1 :(得分:0)
所以我在将实例变量移动到@attributes
并将第二种方法用于模块STI
后解决了我的问题:
module STI
def new(*args, &block)
type = args.dup.extract_options!.with_indifferent_access.delete(:type)
if type.blank? or (type = type.constantize) == self
super(*args, &block)
else
super(*args, &block).becomes(type)
end
end
end
class User < AR:Base
extend STI
belongs_to :account
validates :password, :presence => true, :length => 8..40
validates :password_digest, :presence => true
def password=(password)
@attributes['password'] = password
self.password_digest = BCrypt::Password.create(password)
end
def password
@attributes['password']
end
class Standard < User
after_save :some_callback
end
end
现在我的实例变量(密码)被复制到新的User::Standard
对象,并且回调和验证正在运行。太好了!但这是一种解决方法,而不是真正的解决方案。 ;)