Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.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 正在加载关联的第一条记录_Ruby On Rails - Fatal编程技术网

Ruby on rails 正在加载关联的第一条记录

Ruby on rails 正在加载关联的第一条记录,ruby-on-rails,Ruby On Rails,在一个由Rails应用程序制作的非常简单的论坛中,我从数据库中获取了30个主题,索引操作如下 def index @topics = Topic.all.page(params[:page]).per_page(30) end <%= link_to simple_format(topic.name), posts_path( :topic_id => topic), :data => { :toggle => 'tooltip', :placement =>

在一个由Rails应用程序制作的非常简单的论坛中,我从数据库中获取了30个主题,索引操作如下

def index

@topics = Topic.all.page(params[:page]).per_page(30)

end 
<%= link_to simple_format(topic.name), posts_path(
:topic_id => topic), :data => { :toggle => 'tooltip', :placement => 'top', :'original-title' => "#{ topic.posts.first.body }"}, :class => 'tool' %>
@topics = Topic.all.page(params[:page]).per_page(30).includes(:posts)
但是,当我在views/topics/index.html.erb中列出它们时,我还希望能够访问每个主题中要显示在工具提示中的第一篇文章,这样当用户滚动浏览时,他们就可以阅读第一篇文章,而无需单击链接。因此,在索引中每个帖子的链接中,我将以下内容添加到数据属性

topic.posts.first.body
每个链接看起来都像这样

def index

@topics = Topic.all.page(params[:page]).per_page(30)

end 
<%= link_to simple_format(topic.name), posts_path(
:topic_id => topic), :data => { :toggle => 'tooltip', :placement => 'top', :'original-title' => "#{ topic.posts.first.body }"}, :class => 'tool' %>
@topics = Topic.all.page(params[:page]).per_page(30).includes(:posts)
我已经注意到Rails对其中一些进行了自动缓存,但我认为可能有一种方法可以以不同的方式编写索引操作,以避免出现这种n+1问题,但我可以找到方法。我发现我可以

include(:posts) 
如下图所示,快速加载帖子

def index

@topics = Topic.all.page(params[:page]).per_page(30)

end 
<%= link_to simple_format(topic.name), posts_path(
:topic_id => topic), :data => { :toggle => 'tooltip', :placement => 'top', :'original-title' => "#{ topic.posts.first.body }"}, :class => 'tool' %>
@topics = Topic.all.page(params[:page]).per_page(30).includes(:posts)
但是,如果我知道我只想要每个主题的第一篇文章,有没有办法指定?如果一个主题有30篇帖子,我不想急于加载所有帖子

我试着去做

.includes(:posts).first

但它打破了密码据我所知你不能。自定义关联通常用于允许包含限制以外的条件

如果使用指定的:limit选项加载关联,将忽略该关联,并返回所有关联对象


这似乎对我有效,因此请尝试一下,看看是否对您有效:

Topic.includes(:posts).where("posts.id = (select id from posts where posts.topic_id = topics.id limit 1)").references(:posts)
这将创建一个从属子查询,其中子查询中的posts topic_id与父查询中的topics id匹配。使用子查询中的limit 1子句,结果是每个主题行将只包含1个匹配的Post行,这要归功于includes:Post


请注意,当将SQL字符串传递给.where时,该字符串引用了一个急切加载的关系,应该追加references方法以通知ActiveRecord我们正在引用一个关联,以便它知道在后续查询中执行适当的联接。显然,从技术上讲,它可以在没有该方法的情况下工作,但您会收到一个弃用警告,因此您最好将其加入,以免在将来的Rails更新中遇到问题。

尝试通过Rails本机解决此问题时,会出现一些问题,详细信息请参见

我们使用SQL作用域解决了这个问题,对于您的情况,类似于:

class Topic < ApplicationRecord
  has_one :first_post, class_name: "Post", primary_key: :first_post_id, foreign_key: :id

  scope :with_first_post, lambda {
    select(
      "topics.*,
      (
        SELECT id as first_post_id
        FROM posts
        WHERE topic_id = topics.id
        ORDER BY id asc
        LIMIT 1
      )"
    )
  }
end

Topic.with_first_post.includes(:first_post)

但是查询量并没有减少,而是进入了一个大的查询中:顺便说一句,我记得在SQL中,select in where不是一个好的样式。@BillyChan试一试,它肯定会减少查询数。从30降到1,应该是。你是对的,它确实涉及到一个更大的问题,那就是除非我误解了OP想要什么;要消除通过执行topic.posts.first执行的附加查询,请执行以下操作。另外,我不太清楚为什么select在where子句中不是一种好的样式,因为我不确定如何执行子查询,或者没有它的任何查询。也许我误解了你的意思,你能详细解释一下吗?蒂格,我忘了我在哪里读到过那篇文章,目前找不到可靠的来源。无论如何,在这种情况下,如果需要修复较长的查询,我不希望使用includes:@BillyChan好吧,很公平,如果你找到那篇文章,请告诉我。如果你所说的查询是指ruby/rails代码,我不相信它有那么长,而且它很容易阅读,但是每个人都有自己的代码。如果您指的是生成的SQL,是的,它相当长,但这并不重要。查询的大小没有区别,重要的是适当的索引和适当的查询结构,尽管查询很长,但确实如此。我甚至认为,在大多数情况下,只要长查询仍然可读,就应该首选它来提高性能。