Ruby on rails ActiveRecord-自动将模型数据合并为聚合

Ruby on rails ActiveRecord-自动将模型数据合并为聚合,ruby-on-rails,activerecord,Ruby On Rails,Activerecord,假设我有两张桌子。 我想让用户的联系人信息作为用户对象的属性自动合并到我的用户对象中,而不必说@User.contact\u info.first\u name;相反,我更希望能够写@user.first_name 我将属性分解到contact_info表的原因是,这些属性是多个模型的公共属性。这就是为什么我要将联系人信息设置为多态关联 有人知道一种将联系人信息的属性直接聚合/合并到我的用户模型中的好方法吗?不一定是一种好方法,但我通过重写该方法,然后调用聚合对象,做了类似的事情。所以,它看起

假设我有两张桌子。

我想让用户的联系人信息作为用户对象的属性自动合并到我的用户对象中,而不必说@User.contact\u info.first\u name;相反,我更希望能够写@user.first_name

我将属性分解到contact_info表的原因是,这些属性是多个模型的公共属性。这就是为什么我要将联系人信息设置为多态关联

有人知道一种将联系人信息的属性直接聚合/合并到我的用户模型中的好方法吗?

不一定是一种好方法,但我通过重写该方法,然后调用聚合对象,做了类似的事情。所以,它看起来像:

class User
  def method_missing(method_id)
    self.contact_info.send(method_id)
  end
end
编辑1:更好的实施我认为这会奏效:

class User
  alias_method :orig_method_missing, :method_missing

  def method_missing(method_id)
    if (self.contact_info.respond_to?(method_id))
      self.contact_info.send(method_id)
    else
      orig_method_missing(method_id)
    end
  end
end
上述方法的优点是所有其他未知方法调用都能正确通过。

这不一定是一个好方法,但我通过重写该方法,然后调用聚合对象,做了类似的事情。所以,它看起来像:

class User
  def method_missing(method_id)
    self.contact_info.send(method_id)
  end
end
编辑1:更好的实施我认为这会奏效:

class User
  alias_method :orig_method_missing, :method_missing

  def method_missing(method_id)
    if (self.contact_info.respond_to?(method_id))
      self.contact_info.send(method_id)
    else
      orig_method_missing(method_id)
    end
  end
end
上述方法的优点是所有其他未知方法调用都能正确通过。

使用委托:

class User < ActiveRecord::Base
  has_one :contact_info, :as => :contactable

  delegate :name, :name=, :email, :email=, :to => :contact_info
end
使用代理:

class User < ActiveRecord::Base
  has_one :contact_info, :as => :contactable

  delegate :name, :name=, :email, :email=, :to => :contact_info
end

我终于明白了!谢谢阿米卡兹米和托弗·方吉奥。我必须实现委托和方法两种缺失的技术,才能让它正常工作

这就是最终为我工作的疯狂!如果有人对如何进一步改进这一点提出建议,我很乐意听取你的建议

class User < ActiveRecord::Base
  attr_accessible *([:user_name, :udid, :password, :password_confirmation, :contact_info] + ContactInfo.accessible_attributes.to_a.map {|a| a.to_sym})

  has_one :contact_info, :as => :contactable

  def method_missing(method_id, *args)
    if (!self.respond_to?(method_id) && self.contact_info.respond_to?(method_id))
      self.contact_info.send(method_id, *args)
    elsif (!self.class.respond_to?(method_id) && ContactInfo.respond_to?(method_id))
      ContactInfo.send(method_id, *args)
    else
      super(method_id, *args)
    end
  end

  # delegating attributes seems redundant with the method_missing above, but this secret sauce works.
  ContactInfo.accessible_attributes.to_a.each do |a|
    delegate a.to_sym, "#{a}=".to_sym, :to => :contact_info
  end

  def initialize(*args)
    options = args.extract_options!
    contact_attrs = ContactInfo.accessible_attributes.to_a.map{|a| a.to_sym}
    @ci = ContactInfo.new(options.reject {|k,v| !contact_attrs.include?(k) })
    super(*(args << options.reject { |k,v| contact_attrs.include?(k) }.merge(:contact_info => @ci) ) )
    self.contact_info = @ci
  end

  validates_presence_of :user_name
  validates_uniqueness_of :user_name

  validates_associated  :contact_info

  def after_save
    # automatically save the contact info record for the user after the user has been saved.
    self.contact_info.save!
  end

end

我终于明白了!谢谢阿米卡兹米和托弗·方吉奥。我必须实现委托和方法两种缺失的技术,才能让它正常工作

这就是最终为我工作的疯狂!如果有人对如何进一步改进这一点提出建议,我很乐意听取你的建议

class User < ActiveRecord::Base
  attr_accessible *([:user_name, :udid, :password, :password_confirmation, :contact_info] + ContactInfo.accessible_attributes.to_a.map {|a| a.to_sym})

  has_one :contact_info, :as => :contactable

  def method_missing(method_id, *args)
    if (!self.respond_to?(method_id) && self.contact_info.respond_to?(method_id))
      self.contact_info.send(method_id, *args)
    elsif (!self.class.respond_to?(method_id) && ContactInfo.respond_to?(method_id))
      ContactInfo.send(method_id, *args)
    else
      super(method_id, *args)
    end
  end

  # delegating attributes seems redundant with the method_missing above, but this secret sauce works.
  ContactInfo.accessible_attributes.to_a.each do |a|
    delegate a.to_sym, "#{a}=".to_sym, :to => :contact_info
  end

  def initialize(*args)
    options = args.extract_options!
    contact_attrs = ContactInfo.accessible_attributes.to_a.map{|a| a.to_sym}
    @ci = ContactInfo.new(options.reject {|k,v| !contact_attrs.include?(k) })
    super(*(args << options.reject { |k,v| contact_attrs.include?(k) }.merge(:contact_info => @ci) ) )
    self.contact_info = @ci
  end

  validates_presence_of :user_name
  validates_uniqueness_of :user_name

  validates_associated  :contact_info

  def after_save
    # automatically save the contact info record for the user after the user has been saved.
    self.contact_info.save!
  end

end

感谢您编辑并使代码更容易阅读:-感谢您编辑并使代码更容易阅读:-看起来它应该可以工作,但我得到了一个错误,例如。我实施了授权:电子邮件发送至:联系人信息,但仍然不起作用。>>u=用户。创建:电子邮件=>asdf@asdf.comActiveRecord::UnknownAttributeError:unknown属性:email这只是读取委托,如果您还想写入,则需要添加setter方法委托:name,:email,:name=,:email=谢谢。这又让我兴奋起来。这有助于解决我的问题。我发布了我的解决方案。谢谢大家,这也帮了我很多忙。看起来它应该可以工作,但我得到了一个错误的例子。我实施了授权:电子邮件发送至:联系人信息,但仍然不起作用。>>u=用户。创建:电子邮件=>asdf@asdf.comActiveRecord::UnknownAttributeError:unknown属性:email这只是读取委托,如果您还想写入,则需要添加setter方法委托:name,:email,:name=,:email=谢谢。这又让我兴奋起来。这有助于解决我的问题。我发布了我的解决方案。谢谢各位,这也帮了我很多忙。谢谢你们。你的推荐使我走上了正轨。谢谢你。你的推荐使我走上了正轨。