【问题标题】:Solution to insert cross-hyperlinks of Rails objects inside text attribute (as HTML)在文本属性(如 HTML)中插入 Rails 对象的交叉超链接的解决方案
【发布时间】:2012-11-27 06:02:06
【问题描述】:

我正在使用 Rails 中的一个 Web 应用程序,其行为与 CMS 非常相似:有些文章具有包含指向其他文章(或其他对象类)的链接的文本属性。我目前将属性存储为 HTML。

有没有什么好的方法可以以相对容易更改的方式对这些链接进行建模,并包含对对象 id 的引用,而不是绝对 url?

其中一个解决方案我想的是使用某种特殊标记,例如:

[link_to "Text for the link", Article:12]

其中 12 是它链接到的文章的 ID。呈现文本时将解析此标记。

这样做的缺点是我必须侵入 TinyMCE(我正在考虑使用的编辑器来编辑 HTML),以便它可以通过访问数据库并自动分配对象类型来插入指向其他对象的链接和ID(编辑文本的人不知道 ID)。

有什么简单的解决办法吗?

或者我应该坚持使用绝对网址(除了维护问题之外,这在开发中很烦人,因为它们总是指向生产,这让我感到困惑)?

此外,是否有人在其他语言(php、Wordpress、其他 CMS 等)中有类似的示例可以很好地解决这个问题?我在想,这在 CMS 中非常重要,如果一个好的系统可以处理所有这些链接,可以减少很多工时。

编辑:

我正在考虑的另一个可能的解决方案是让人们直接在代码中复制文章的链接,但它应该在提交时生成正确的关联 id 并使其在 url 结构发生变化时,链接始终是最新的。如果您尝试过,我想听听您对这种方法的意见和经验。

这种方法的挑战在于使用 Rails 解析链接并发现它指向一篇文章,并且该文章的 id 为 ##。然后我必须插入一个短代码,在解析和呈现时,该短代码将始终转换为该文章的实际链接。

我找到了一种可行的方法:

Rails.application.routes.recognize_path

但可能有一些我现在看不到的警告......

编辑编号。 2

我还要说明我选择CKEditor作为内容编辑器,但是如果有更明显的优势我会考虑其他的。

【问题讨论】:

  • 我使用您的第一个解决方案做了类似的事情。它类似于 wordpress 等系统中的简码操作方式。然后我构建了一个助手,它可以解析任何可能包含短代码的文本并在模型上调用相关方法。例如:parse_article_desc(article) 然后我们可以在模型上执行方法,而不仅仅是文本。希望对您有所帮助。

标签: ruby-on-rails ruby-on-rails-3 content-management-system ckeditor hyperlink


【解决方案1】:

我使用简码系统构建了类似的东西,它允许我调用模型上的特定方法并替换文本中的简码:

助手

def parse_shortcode(model)
  text = model.text      
  text.gsub(/(\[#!\s?\w+\])/i) do |match|
    result = model.try(match)
    result.nil? '' : link_to(result[:text], result[:url])
  end
end

型号

def contact_link
  { :text => self.name, :url => self.url }
end

查看

<%= parse_shortcode(@article) %>

我没有测试过上面的代码,它显然有点简化,但它解释了我背后的思考过程。

编辑:只是为了澄清我上面的例子使用了[#! method]的发明短代码语法

【讨论】:

  • 这很有用,当我将解析短代码的内容时,由于它们的灵活性,我最终将不得不使用它们。我不确定我是否想公开模型的每个方法,但我可以轻松地将方法列入白名单。这就是说,您的答案和@James Mason 的答案的组合将适合接受......
  • 如您所说...您始终可以执行shortcode_#{match} 之类的操作,以便完全控制可访问的方法。很高兴能帮上忙。
  • 很好......这是一个很酷的技巧:) 我会创建一个符号列表和一个只调用该列表中的方法的自定义方法。但与您的简单解决方案相比,这太疯狂了:D
【解决方案2】:

一篇文章可以有许多related_articles,同时这篇文章可以与许多其他文章相关,因此最好将其建模为多对多关系。

在 Rails 中定义这种类型的关系的一种方法是has_many :through

要使用has_many :through,您必须创建一个连接模型,或许将其命名为ArticleRelation。此模型将有两个字段,一个表示当前文章的 article_id 和一个表示被称为相关文章的 related_article_id

class Article < AR::Base
  has_many :article_relations
  has_many :related_articles, :through => :article_relations
end

class ArticleRelation < AR::Base
  belongs_to :article
  belongs_to :article_relation, :class_name => 'Article'
end

在创建自我参照关系时,请务必记住,您只是在创建关系的一方面。虽然 article_1 可能会将 article_2 列为相关,但 article_2 无法将 article_1 列为相关。您需要两个 ArticleRelation 记录来创建相互关系。

很难想出合适的名称来定义关系的另一面,因此您可以在两者前面加上“反向”一词,以给出 inverse_article_relationsinverse_related_articles。您还需要指定一些附加选项以使关系有效。对于 inverse_article_relations,您必须指定另一个模型的名称,因为它无法从关系名称中推断出来,您还必须将外键定义为 related_article_id强>。对于 inverse_related_articles 关系,您需要将来源指定为 articles,因为它不能从关系名称中推断出来。

has_many :inverse_article_relations, :class_name => "ArticleRelation", :foreign_key => "related_article_id"
has_many :inverse_related_articles, :through => :inverse_article_relations, :source => :article

测试一下,这应该适合您当前的要求。

【讨论】:

  • 我已经有一个多对多的关系,所以我知道一篇文章正在链接到其他文章。但是,我想找到一种在编辑器中创建链接的简单方法,这样对于创建链接的人来说都很容易,而且在代码中也是一种实用的方法。我目前正在使用 CKEditor(最新版本),但我还没有尝试自定义操作(例如选择另一篇文章和生成链接)。
【解决方案3】:

我在许多其他 CMS 中看到的一个解决方案是结合 TinyMCE 中的自定义文件浏览器和页面重写(类似于freakyDaz 的回答)。

TinyMCE 有 documentation and example code 用于实现自定义浏览器。当然,您必须提供后端部分。

CKEditor 也有documentation for a similar feature

让您的后端实现返回一些易于解析的网址(例如 urlfor:Article:12),然后让您的渲染代码用实际网址替换这些内容。

【讨论】:

  • 有趣...我目前正在使用 CKEditor(最新版本),但我还没有尝试自定义操作(例如选择另一篇文章和生成链接)。我希望 CKEditor 与您的链接中的示例等效。
  • 更新了自定义文件浏览器的 CKEditor 文档链接。
【解决方案4】:

我只是想到了另一种可能的用例解决方案:

  1. 管理员用户在编辑文本之前指定关系(使用Chosen.js,这可以以用户友好的方式完成)。
  2. 然后该人要么提交表单以保存模型,要么可以异步完成。
  3. 保存关系后,会为每个关系生成并显示一个短代码,并且该短代码可以轻松粘贴到文本中。
  4. 在前端显示文本时,文本将被解析为短代码,类似于@freakyDaz 所建议的方式。

通过这种方式,我不必在编辑器中破解或创建自定义操作。我认为这是一种非常务实的方法,但我想听听您的意见。当然,应该教育编写文本的管理员按顺序遵循流程,但在我的情况下,很少有人可以成为管理员(1 或 2),所以它是易于管理的。

【讨论】:

  • 如果您的有效关系可以受到如此严格的限制,我不明白为什么它不起作用。听起来这对管理员来说会做更多的工作,但对用户来说应该会容易得多(因为他们不能选择无效的关系)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-01-24
  • 1970-01-01
  • 1970-01-01
  • 2016-12-21
  • 2015-07-05
  • 1970-01-01
  • 2012-01-26
相关资源
最近更新 更多