如何使用 BlankSlate 和 Proxy 模式在记录之间创建符号链接?

发布于 2024-08-08 04:21:18 字数 1050 浏览 6 评论 0原文

我希望能够添加一个类似于符号链接的记录。换句话说,我希望能够存储一个记录/对象,它将大多数属性推迟到另一个记录/对象。

与文件系统上的情况相同,其中符号链接指向另一个文件(它自己的数据),但将其他所有内容推迟到另一个文件。

class Document < ActiveRecord::Base
end

class Page < Document
end

class Folder < Document
end

class Symlink < ActiveRecord::Base
  set_table_name  :documents

  instance_methods.each { |m| undef_method m if (ActiveRecord::Base.instance_methods(false).include? m) && (!['link', 'link_id', 'link_id='].include? m) }

  def method_missing(sym, *args, &block)
    puts "Sending #{sym}(#{args.join(',')}) to obj"
    link.__send__(sym, *args, &block)
  end

  def save
    raise 'Symlink cant be saved' unless new_record?
    super
  end

  private

  def link
    @link ||= Document.find(self.link_id)
  end  
end

当我尝试创建新记录时,我得到的堆栈级别对于“链接”来说太深了。

我认为这将是解决问题的一种巧妙方法,可以将其提取到 gem 中(acts_as_symlink :column => 'parent_id')。

另一个想法是保留原始记录的完整副本,并使用 after_save 回调来更新任何符号链接,或者如果符号链接发生更改,则更新原始记录。所以不是真正的符号链接更像是同步副本。

对我的代码或替代方案有什么想法吗?

I want to be able to add a record which acts like a symlink. In other words I want to be able to store a record/object which will defer most attributes to another record/object.

The same as on a file system where a symlink points to another file (it own data), yet defers everything else to another file.

class Document < ActiveRecord::Base
end

class Page < Document
end

class Folder < Document
end

class Symlink < ActiveRecord::Base
  set_table_name  :documents

  instance_methods.each { |m| undef_method m if (ActiveRecord::Base.instance_methods(false).include? m) && (!['link', 'link_id', 'link_id='].include? m) }

  def method_missing(sym, *args, &block)
    puts "Sending #{sym}(#{args.join(',')}) to obj"
    link.__send__(sym, *args, &block)
  end

  def save
    raise 'Symlink cant be saved' unless new_record?
    super
  end

  private

  def link
    @link ||= Document.find(self.link_id)
  end  
end

At the moment when I try and create a new record I get a stack level too deep for 'link'.

I thought this would be a neat way of solving the problem which could be extracted in to a gem (acts_as_symlink :column => 'parent_id').

Another thought was to keep a full copy of the original record and use a after_save callback to update any symlinks or if the symlink is changed, update the original. So not real symlinks more like sync'd copies.

Any thoughts on my code or an alternative?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

烟雨凡馨 2024-08-15 04:21:18

好吧,我似乎已经破解了它,关键是用遵循另一个对象的方法替换访问数据库列的方法。通过重写 id 方法,我还可以确定 save 是否会将属性保存到符号链接或原始记录。在我的例子中,Document是一个acts_as_tree + acts_as_list,所以我排除了parent_idposition 列被推迟,这样我就可以将符号链接分配到不同的文件夹(否则无用)并将其放置在该文件夹中。

class Symlink < Document
  attr_accessor :save_to  


  self.columns.map { |c| c.name }.reject { |c| %w(position parent_id sync_id).include? c }.each do | col |
    self.send :define_method, col.to_sym do   
      source.send(col)
    end
  end

  def id
    if save_to == :symlink
      return read_attribute(:id)
    else
      return source.send :id
    end
  end

  def copy?
    !sync_id.nil?
  end


  private

  def source
    if sync_id
      @source ||= Document.find(sync_id)
    else
      Document.new
    end
  end
end

到目前为止仅在控制台中进行了测试,但这是为什么它不能在整个堆栈上工作的原因。

如果成功的话,我会考虑将其抽象为通用的acts_as_symlink gem。

Okay I seem to have cracked it, the key was to replace the methods which access the database column with methods which defer to another object. By over-riding the id method I can also determine if save will save the attributes to either the symlink or the original record. Document in my case is an acts_as_tree + acts_as_list so I am excluding parent_id and position columns from being deferred so I can assign the symlink to a different folder (useless otherwise) and position it within that folder.

class Symlink < Document
  attr_accessor :save_to  


  self.columns.map { |c| c.name }.reject { |c| %w(position parent_id sync_id).include? c }.each do | col |
    self.send :define_method, col.to_sym do   
      source.send(col)
    end
  end

  def id
    if save_to == :symlink
      return read_attribute(:id)
    else
      return source.send :id
    end
  end

  def copy?
    !sync_id.nil?
  end


  private

  def source
    if sync_id
      @source ||= Document.find(sync_id)
    else
      Document.new
    end
  end
end

Only tested in console so far, but reason why this should not work over the full stack.

If its successful I will think abstracting this out in to a general purpose acts_as_symlink gem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文