Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails:通过多对多关系从另一个模型收集数据的有效方法_Ruby On Rails_Ruby_Acts As Taggable On - Fatal编程技术网

Ruby on rails Rails:通过多对多关系从另一个模型收集数据的有效方法

Ruby on rails Rails:通过多对多关系从另一个模型收集数据的有效方法,ruby-on-rails,ruby,acts-as-taggable-on,Ruby On Rails,Ruby,Acts As Taggable On,我有两种型号,书签和标签。这些标记是通过在gem上充当标记来实现的,但我将在这里解释要点 书签模型包含一个url字段。给定书签实例@Bookmark,@bookmart.tags返回其标记。不同的书签可以共享同一个标记(即标记的多个部分) 标记具有名称和标记计数。taggings_count字段存储标记的书签数量。在幕后,有一张标签桌,但这并不重要 现在的问题是,我想检索所有被带有特定url值的书签标记的标签,结果应该按照标记某个标签的书签数量排序(该数字与taggings_count字段不同,

我有两种型号,书签和标签。这些标记是通过在gem上充当标记来实现的,但我将在这里解释要点

书签模型包含一个url字段。给定书签实例@Bookmark,@bookmart.tags返回其标记。不同的书签可以共享同一个标记(即标记的多个部分)

标记具有名称和标记计数。taggings_count字段存储标记的书签数量。在幕后,有一张标签桌,但这并不重要

现在的问题是,我想检索所有被带有特定url值的书签标记的标签,结果应该按照标记某个标签的书签数量排序(该数字与taggings_count字段不同,该字段表示所有书签的标记计数,但此处需要特定url的书签)。如何才能使生成的sql有效

我知道为了提高效率,我可以直接用sql编写代码,但我也想知道Rails是否可以在不影响太多性能的情况下也这样做,这样我就不必在Rails应用程序中注入sql代码

以下是表定义,在taggings表中,taggable_id用作书签的外键,tag_id用作标记的外键:

CREATE TABLE `bookmarks` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  `description` text,
  `private` tinyint(1) DEFAULT NULL,
  `read` tinyint(1) DEFAULT NULL,
  `list_id` int(11) DEFAULT NULL,
  `user_id` int(11) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `taggings` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `tag_id` int(11) DEFAULT NULL,
  `taggable_id` int(11) DEFAULT NULL,
  `taggable_type` varchar(255) DEFAULT NULL,
  `tagger_id` int(11) DEFAULT NULL,
  `tagger_type` varchar(255) DEFAULT NULL,
  `context` varchar(128) DEFAULT NULL,
  `created_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `taggings_idx` (`tag_id`,`taggable_id`,`taggable_type`,`context`,`tagger_id`,`tagger_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

CREATE TABLE `tags` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `taggings_count` int(11) DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `index_tags_on_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
这是一个解决方案:

bookmark_ids  = Bookmark.where(url: "http://foobar.com").pluck(:id)
taggings      = Tagging.where(taggable_id: bookmark_ids).where(taggable_type: "Bookmark")
tag_ids       = taggings.pluck(:tag_id).uniq
tags          = Tag.where(id: tag_ids).order(taggings_count: :desc)
它理论上可以使用ActiveRecord中的
joins()
方法编写,但我不知道您使用的gem如何定义关联。
这可能有效,也可能无效:

Tag.order(taggings_count: :desc)
   .joins(taggings: :bookmark)
   .where(bookmark: { url: "http://foobar.com" })

您也可以编写原始SQL,但在rails中感觉很脏。

结果很简单,实际上可以在关联上操作。文档中有这样的示例,我只是没有注意到:

Bookmark.where(url: url).tag_counts_on(:tags).sort_by(&:taggings_count).reverse.map(&:name)
唯一的问题是,结果仍然是按照这些标记的流行程度排序的,不管它们在什么类型的上下文中流行。但这并不重要。关键是,rails语句只生成一个sql:

SELECT tags.*, taggings.tags_count AS count FROM "tags" JOIN (SELECT taggings.tag_id, COUNT(taggings.tag_id) AS tags_count FROM "taggings" INNER JOIN bookmarks ON bookmarks.id = taggings.taggable_id WHERE (taggings.taggable_type = 'Bookmark' AND taggings.context = 'tags') AND (taggings.taggable_id IN(SELECT bookmarks.id FROM "bookmarks"  WHERE "bookmarks"."url" = 'http://kindleren.com/forum.php?gid=49')) GROUP BY taggings.tag_id HAVING COUNT(taggings.tag_id) > 0) AS taggings ON taggings.tag_id = tags.id

如果您关心SQL查询的效率,您应该给我们:3个表上的索引,“标记”的列表。另外,您使用的是哪个Rails版本?哪个DB?@tompave检查我的表定义更新。我正在使用Rails 4.1.0,它将被部署到带有MySQL的服务器。您是否使用Rails的active record?或其他DB接口。您似乎只需要您关心的书签id。bookmark.where(url:your url).pull(:id)[0]如果只有一个。那么只需执行一个tabable。其中(id:)并获取标记url。@bobbdelsol是的,我使用的是active record。可能有多个书签具有相同的url。谢谢,tompave。在我的问题中,有一件事你遗漏了,即结果应该按此设计中的标记计数字段以外的其他字段排序。但你的回答促使我了解更多。我找到并想一想,也许我可以重新设计它,将url作为上下文。然后我可以使用Bookmark.tag\u counts\u on(“特定url”)获取url的标签。在新设计中,可以使用taggings_count。我明白了。很抱歉,我错过了。如果关联正确,您可以查看我将您的第一个解决方案与我发布的解决方案进行比较的方法,生成的sql结果类似,gem更紧凑,使用ruby和sql。我将您的代码编辑为包含上下文一个条件,并结合第二条和第三条语句,不确定将它们写成两条语句是否会导致执行两条语句而不是一条语句。顺便说一句,连接无法工作,我不知道是否有办法配置rails如何连接表。好的,但决不能以这种方式编辑其他人的答案。即使答案是正确的不正确,您不应该更正它。我的答案的含义已经丢失,我不会以这种方式编写代码:我对库的了解不够,无法像您这样引用名称空间,我也不会以这种方式链接方法调用。问答集模型的目的是您应该选择正确的answer、 或者自己提供一个。错误的答案可以被忽略或否决。我恢复了更改。如果您对我的答案不满意,您可以否决并选择另一个作为赢家。