在 Rails 中重构相同的模型
Refactoring identical models in Rails
我使用加入 table 解决方案来建立这样的友谊:
class Contact < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => :friend_id
def self.request(user, friend)
unless user == friend
current = find_by_user_id_and_friend_id(user, friend)
unless current
transaction do
create :user => user, :friend => friend, :status => "pending"
create :user => friend, :friend => user, :status => "requested"
end
end
end
end
...
我去给群组创建成员资格,发现了相同的场景:
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :network
def self.request(user, network)
current = find_by_user_id_and_network_id(user, network)
unless current
transaction do
create :user => user, :network => network, :status => "pending"
create :user => network, :network => user, :status => "requested"
end
end
end
...
我用阻塞把这个复杂化了,这是很多重复的代码。
由于 belongs_to :friend, :class_name => "User", :foreign_key => :friend_id
,将该键识别为具体代表用户,我认为我无法为用户 <-> 用户和用户 <-> 使用 Contact
网络。我也可以通过 network_id
使它成为 belongs_to
一个网络,但我仍然觉得我必须将方法加倍才能解决这个问题。我想我可以将 type
(:friend
或 :network
)传递给每个方法并像这样使用它:
create :user => user, type => target, :status => "pending"
create :user => target, type => user, :status => "requested"
但是,有更好的解决方案吗?
我的另一个想法是始终使用术语 :friend
,但可能使用混入或抽象 class 并且只是在两个文件之间以不同方式定义 belongs_to :friend
行.
多态关联应该有助于使用一种模型:
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
您可以将此行为抽象到名为 Requestable
的模块中。
module Requestable
extend ActiveSupport::Concern
class_methods do
def by_name=(name)
@name = name
end
def request(user, instance)
# use @name or class name as default
name = @name || self.class.name.dasherize.to_sym
# find current relation
current = self.class.where(user: user, name => instance)
# create new relations, if needed
unless current
transaction do
create :user => user, name => network, :status => "pending"
create :user => network, name => user, :status => "requested"
end
end
end
end
end
现在你可以晒干你的模型了:
class Contact < ActiveRecord::Base
include Requestable
by_name 'friend'
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => :friend_id
end
class Member < ActiveRecord::Base
include Requestable
belongs_to :user
belongs_to :network
end
我没有调试代码,但思路清晰,希望。
我使用加入 table 解决方案来建立这样的友谊:
class Contact < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => :friend_id
def self.request(user, friend)
unless user == friend
current = find_by_user_id_and_friend_id(user, friend)
unless current
transaction do
create :user => user, :friend => friend, :status => "pending"
create :user => friend, :friend => user, :status => "requested"
end
end
end
end
...
我去给群组创建成员资格,发现了相同的场景:
class Member < ActiveRecord::Base
belongs_to :user
belongs_to :network
def self.request(user, network)
current = find_by_user_id_and_network_id(user, network)
unless current
transaction do
create :user => user, :network => network, :status => "pending"
create :user => network, :network => user, :status => "requested"
end
end
end
...
我用阻塞把这个复杂化了,这是很多重复的代码。
由于 belongs_to :friend, :class_name => "User", :foreign_key => :friend_id
,将该键识别为具体代表用户,我认为我无法为用户 <-> 用户和用户 <-> 使用 Contact
网络。我也可以通过 network_id
使它成为 belongs_to
一个网络,但我仍然觉得我必须将方法加倍才能解决这个问题。我想我可以将 type
(:friend
或 :network
)传递给每个方法并像这样使用它:
create :user => user, type => target, :status => "pending"
create :user => target, type => user, :status => "requested"
但是,有更好的解决方案吗?
我的另一个想法是始终使用术语 :friend
,但可能使用混入或抽象 class 并且只是在两个文件之间以不同方式定义 belongs_to :friend
行.
多态关联应该有助于使用一种模型:
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
您可以将此行为抽象到名为 Requestable
的模块中。
module Requestable
extend ActiveSupport::Concern
class_methods do
def by_name=(name)
@name = name
end
def request(user, instance)
# use @name or class name as default
name = @name || self.class.name.dasherize.to_sym
# find current relation
current = self.class.where(user: user, name => instance)
# create new relations, if needed
unless current
transaction do
create :user => user, name => network, :status => "pending"
create :user => network, name => user, :status => "requested"
end
end
end
end
end
现在你可以晒干你的模型了:
class Contact < ActiveRecord::Base
include Requestable
by_name 'friend'
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => :friend_id
end
class Member < ActiveRecord::Base
include Requestable
belongs_to :user
belongs_to :network
end
我没有调试代码,但思路清晰,希望。