我有一个名为Address的多态模型。我想要实现的是将许多地址绑定到其他模型(例如用户),但仍然使用它们,如果只有只有一个,并尝试按类型区分它们。
我的项目只使用一个地址,因此我有很多代码,例如User.first.address
或User.first.address=...
,我无能为力。
以下是一些例子:
|id|addressable_type|addressable_id| type | street |
1|User |1 | first | Foo
2|User |1 | second | Bar
3|User |1 | NULL | Other
我想做的是:
User.find(1).address(:second)
哪个应该返回<Address street:"Bar">
,
User.find(1).address
哪个应该返回<Address street:"Other">
,
但是User.find(1).addresses
应该返回对象的集合。
我使用一段代码将地址行为添加到我的模型中:
module Ext::Models::Addressable
def self.included(mod)
super
mod.class_eval do
def self.acts_as_addressable
include InstanceMethods
# Use has_many :delete_all for better performance
has_many :addresses, :as => :addressable, :dependent => :delete_all
has_one :address, :as => :addressable
end
end
end
module InstanceMethods
# I tried with this, but this doesn't even allow me to start rails becauses raises "there is no address method"
def address_with_type(type = nil)
if type
self.addresses.find(:first, :conditions => ["type = ?", type.to_s])
else
address_without_type
end
end
alias_method_chain :address, :type
end
end
我正在使用Rails 2.3.14和Ruby 1.9.2。
如果可以的话,我也想知道为给定模型创建新地址的最佳方法是什么(比方说用户)。
提前致谢。
我缩小了所有可能性,目前在项目中只有两种类型的地址。我能够简化我的方法。目前我的self.included
看起来像是:
has_many :addresses, :as => :addressable, :dependent => :delete_all
has_one :address, :as => :addressable, :conditions => {:type => nil}
has_one :foo_address, :class_name => 'Address', :as => :addressable, :conditions => {:type => "foo"}
现在我可以构建这样的新对象:
user.build_address(:street => "abc")
和user.build_foo_address(:street => "def")
,我需要的是什么。
答案 0 :(得分:0)
我会以这种方式覆盖默认和预期的行为。你有没有理由让user.address
成为?
我不确定你要解决的问题,但也许你可以这样做:
class User < ActiveRecord::Base
has_many :addresses, :as => :addressable, :dependent => :delete_all
def address(only_type = "primary")
addresses.find_first("type" => only_type)
end
def address=(addr)
addresses.delete address
addresses << addr.update_attribute("type", "primary")
end
def build_address(attr)
addresses.delete address
addresses.build attr.merge("type" => "primary")
end
def create_address(attr)
addresses.delete address
addresses.create attr.merge("type" => "primary")
end
end
我还没有测试过这段代码,我不再熟悉rails 2了,所以只能用它作为灵感。你可以将它包装在一些元数据中以模块化它。顺便说一句,如果你使用“类型”,你会得到STI,不确定这是不是你想要的。