【问题标题】:Rails - ActiveRecord where with multiple conditions in nested routesRails - ActiveRecord 在嵌套路由中有多个条件
【发布时间】:2019-02-04 00:24:19
【问题描述】:

我正在建立一个用户可以创建项目的网站。每个项目包含几篇论文。每篇论文都可以通过回答几个问题来进行审核。

我有四个模型(用户、项目、论文、问题)。

questions_controller 中,我创建了一个动作replies,目的是选择具有特定project_idpaper_id 的所有回复。

在对象@replies中,我想选择所有在URL中显示project_idpaper_id的论文和项目。

http://0.0.0.0:3000/projects/3/papers/2/questions/1/replies

我想选择所有带有project_id == 3paper_id == 2 的回复

为此,我编写了以下代码:

questions_controller.rb

  def replies
    @project = Project.find(params[:project_id])
    @paper = Paper.find(params[:paper_id])
    @replies = Question.where("project_id = ? AND paper_id = ?", params[:project_id], params[:paper_id])
  end

并通过@replies in:

views/questions/replies.html.erb

<% @replies.each do |reply| %>
  <%= reply %>
<% end %>

但是,它不起作用。事实上,我在@replies 中的查询并没有在我的views/questions/replies.html.erb 中传递任何内容。 我不确定我做错了什么。

routes.rb

Rails.application.routes.draw do
  resources :projects do
    resources :papers do
      resources :questions do
        collection do
          get 'replies'
        end
      end
    end
  end
devise_for :users
root to: 'pages#home'

project.rb

class Project < ApplicationRecord
  belongs_to :user
  has_many :papers, dependent: :destroy
  has_many :questions
end

paper.rb

class Paper < ApplicationRecord
  belongs_to :project
  has_many :questions
  has_one_attached :paper_pdf
end

question.rb

class Question < ApplicationRecord
  belongs_to :user
  belongs_to :paper
  belongs_to :project
end

user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  has_many :projects
  has_many :questions
end

【问题讨论】:

  • 你没有说真正的问题。除了 raise 之外,你还有什么错误吗?如果您没有错误,则问题与代码无关。您实际上是否将 questions 存储在论文 2 的数据库中? ...请详细说明。
  • 显示您的模型,显示实际错误。此外,不鼓励使用超过 2 级的嵌套资源,您肯定有办法简化您的路线。我猜你需要加入表格来做这些查询,阅读关于 activerecord 的joinsincludesreferences
  • 按照您当前设置路线的方式,您还需要在路径中有一个 question_id。但是我认为您实际上并不想要问题ID。您将路线更改为这样的东西,也许它会开箱即用:resources :questions do collection do get 'replies' end end ---不要忘记确保问题正确嵌套在项目和论文资源中,最后,我建议使用浅嵌套。
  • @BKSpureon 我认为你是对的。我不需要在question_id 之后有replies。我想我需要像 /papers/1/questions/replies 这样的它,因为我需要针对特定​​论文的所有回复(问题的)。我按照您的建议修复了路线,但我仍然卡住了。在我的 questions_controller 中,我添加了一个动作 replies@replies = Question.where("project_id = ? AND paper_id = ?", params[:project_id], params[:paper_id]),但它仍然无法找到 @replies。所以我想我的查询是错误的。
  • @Maxence @arieljuod 我添加了您在我的问题中提出的信息,并使其更加清晰。我的问题是我的 question_controller@replies的查询没有检索到任何内容。我想检索(特定项目中特定论文的所有已回答问题)。创建问题是因为我通过 rails console --&gt; Question.allverigy 它存在正确的 project_idpaper_id 参数,

标签: sql ruby-on-rails activerecord


【解决方案1】:

您的应用程序设计中存在不同的问题。

第一个是问题的关系:

class Question < ApplicationRecord
  belongs_to :user
  belongs_to :paper
  belongs_to :project
end

我了解您在这里要做什么:一个问题可以适用于不同的模型:用户、论文、项目。虽然有一个问题:这个问题只能引用这些模型中的一个(一个问题同时适用于不同的对象会很奇怪)。然后,当您创建与用户相关的新问题时,论文 (paper_id) 和项目 (project_id) 的外键将为空。

这不是一个好的设计。这样做的方法是使 Question 模型成为多态模型。

如果 Question 应该只适用于论文,正如你上面提到的,那么为什么 Question 是 Paper 以外的其他模型的子模型?

第二个问题:您尝试使用两个外键获取问题:

@replies = Question.where("project_id = ? AND paper_id = ?", params[:project_id], params[:paper_id])

正如我在前面的问题 1 中所描述的,您的 Question 模型可能有 3 个外键(指向它所属的 3 个模型),但一个问题一次不能引用多个模型。

因此,当您尝试同时使用这 2 个外键提出问题时,您的查询可能得不到答案。

第三个问题:使用浅嵌套,你的路由太深了:

http://0.0.0.0:3000/projects/3/papers/2/questions/1/replies

这里不需要三层嵌套。您似乎是初学者,因此可能感觉不直观,但请查看下面的建议

建议

如果我正确阅读了您的问题布局,则问题仅适用于论文。 那么如果你想得到与这篇论文相关的所有问题,最好在这个模型中创建一个新方法get replies,而不是问题模型。

让它成为一个成员,而不是一个集合:

路线:

...
resources :papers do
  member do
     get 'replies'
  end
end
...

那么当你的路线以papers/5/replies结束时

您可以在纸张控制器中触发以下代码:

def replies
  @paper = Paper.find(params[:id])
  @replies = @paper.questions
end

您注意到我的操作代码实际上并不需要路由中的任何前面的 id。我只选择与数字 5 相关的params[:id]。纸模型的 id。

如果您有深层嵌套路由,您会意识到路由中有一些未使用的数据。路线中真正重要的数据是最后一个参数。也许是前面的参数。

如果您需要确保论文属于当前用户项目,只需将当前用户与论文 id 进行比较,例如:

unless current_user.id == Paper.find(params[:id]).project.user.id
redirect_to root_path

然后就是这样

【讨论】:

  • 非常感谢。我没有得到以下内容:每次用户提交新的已回答问题时,我都需要在 question.rb 中创建一个包含已保存答案的实体,加上它所指的 id of the paper 以及 @987654334 @ 论文所在的位置。如果我按照你说的做,我想我在/questions/new 提交表单时没有传递正确数量的参数。
  • 为什么一定要传项目id?如果问题与论文相关联,您应该只将论文的 id 作为外键传递。您当然也可以传递项目 ID,但它会使问题成为我认为不正确的两个模型的孩子。但是,如果您在创建问题时添加了两个外键,那么您的原始查询应该可以工作。只需查看您的数据库并检查新创建的问题是否同时包含外键并重新运行您的原始查询。你应该在@queries里面得到一些东西
  • 我说你不​​需要添加两个外键,因为它没用。论文是项目的子项。您不需要在问题记录中同时添加纸质外键和项目外键。您可以通过爬上关系树轻松到达论文的父级:@paper = Paper.find(params[:id])@project = @paper.project
  • 我想传递project_id,因为稍后我必须创建两个页面。一个是每个用户对每篇论文的答案。一个项目中所有论文的答案的平均值。例如:Project 1 包含 paper Apaper B。用户回答 paper A 中的问题,值为 0-0-0。然后,他以 0.5-0.5-0.5 的值回答 paper B 中的问题。另一位用户在paper A 1-1-1 和paper B 0-0-0(在同一个项目中)回答了这个问题。论文 A 的平均值为 0.5-0.5-0.5,论文 B 的平均值为 0.25-0-25-0-25。因此,该项目的平均值为 0.375-0.375-0.375
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-18
  • 1970-01-01
  • 2018-03-24
  • 2015-11-17
  • 2015-11-22
  • 1970-01-01
相关资源
最近更新 更多