如何使用外键定义activerecord和activeresource之间的关系?

时间:2014-06-17 08:43:42

标签: ruby-on-rails activerecord foreign-keys foreign-key-relationship activeresource

我有一个使用activerecord的本地用户模型。用户有一个电子邮件字段。我还有一个名为tasks的activeresource模型,它有一个created_by字段,用于存储提交用户的电子邮件地址。我想将这两者联系起来,但我正在努力使用正确的语法,甚至是否可能。

ActiveResource的主要分支似乎甚至不支持外键。我找到了alternative branch,但仍然无法正常工作。

class User < ActiveRecord::Base
   has_many :tasks
end

class Task < ActiveResource::Base
  belongs_to :user
  schema do
    string 'created_by' #email
    # other fields
  end
end

2 个答案:

答案 0 :(得分:4)

您的代码应该可以正常工作,因为user_id上有Task属性作为外键,或者您可以在User模型上的关联中指定外键如下:

class User < ActiveRecord::Base
  has_many :tasks, foreign_key: "uid"
end

现在问题是,您无法在belongs_to上使用ActiveResource,所以除非您需要从user类的实例中检索Task,你可以删除它,关系的另一面仍然可以工作,但是,如果你需要检索user,那么你必须按如下方式实现自己的finder方法:

class Task < ActiveResource::Base
  schema do
    string 'created_by' #email
    # other fields
  end

  def user
    @user ||= User.find self.user_id # use the attribute name that represents the foreign key
  end

  def user=(user)
    @user = user
    self.update_attribute(:user_id, user.id)
  end
end

这基本上与您在ActiveRecord模型上的预期相同,但如果您有多个关联,这可能会很烦人,因此您可以扩展ActiveResource模块以添加{{1}如下:

belongs_to

这将允许您在任何module BelongsToActiveResource def self.included(base) base.extend(ClassMethods) end module ClassMethods def belongs_to( name, options = {} ) class_eval %( def #{name} @#{name} ||= name.to_s.classify.find( name.id ) end def #{name}=(obj) @#{name} ||= obj self.update_attribute((name.to_s + "_id").to_sym, @#{name}.id end ) end end end ActiveResource::Base.class_eval { include BelongsToActiveResource } 模型上使用belongs_to。

P.S。:上述解决方案的灵感来自https://stackoverflow.com/a/8844932/3770684

答案 1 :(得分:1)

你不能,但你可以通过自己实施访问者方法来伪造它。

class User < ActiveRecord::Base
  #has_many :tasks
  def tasks
    Task.find(:all, params: {created_by: email})
  end
end

class Task < ActiveResource::Base
  #belongs_to :user
  def user
    User.where(email: created_by).first
  end

  schema do
    string 'created_by' #email
    # other fields
  end
end

这将允许您编写代码,就像您的对象相关联(即User.first.tasks.length)。但是,他们并没有真正加入。这意味着调用User.first.tasks将打到数据库,然后发出额外的HTTP请求来检索任务。根据代码的结构,您可能会遇到意外的性能问题。

此外,您无法运行单个查询来获取用户所有关联的任务(因为它是两个独立的数据存储),您无法执行此操作做像User.joins(:tasks).where({tasks: field_1: true})这样的花哨的东西。