【问题标题】:Multiple nested routes to the same controller. Couldn't find XYZ without an ID到同一个控制器的多个嵌套路由。找不到没有 ID 的 XYZ
【发布时间】:2013-02-16 09:52:05
【问题描述】:

我正在重构我的应用程序以在任何地方使用 1 级深度嵌套资源,这是一个仅限 JSON 的 API。这是我的routes.rb 的精简版:

resources :measurements, only: [:index, :show] do
  resource :tag_node, controller: :physical_nodes, only: [:show]
  resource :anchor_node, controller: :physical_nodes, only: [:show]
  resource :experiment, only: [:show]
end

resources :physical_nodes, only: [:index, :show] do
  resources :tag_nodes, controller: :measurements, only: [:index]
  resources :anchor_nodes, controller: :measurements, only: [:index]
end

resources :experiments, only: [:index, :show] do
  resources :measurements, only: [:index]
end

还有我的精简版models

class Measurement < ActiveRecord::Base
  self.table_name = 'measurement'
  self.primary_key = 'id'

  belongs_to :physical_node, foreign_key: :tag_node_id
  belongs_to :physical_node, foreign_key: :anchor_node_id
  belongs_to :experiment, foreign_key: :experiment_id
end

class PhysicalNode < ActiveRecord::Base
  self.table_name = 'physical_node'
  self.primary_key = 'id'

  has_many :measurements, foreign_key: :tag_node_id
  has_many :measurements, foreign_key: :anchor_node_id
end

class Experiment < ActiveRecord::Base
  self.table_name = 'experiment'
  self.primary_key = 'id'

  has_many :measurements, foreign_key: :experiment_id
end

1.:

什么有效:

  • GET /experiments/4/measurements.json 工作正常

什么不起作用:(其他一切;))

  • GET /measurements/2/experiment.json

错误信息:

Processing by ExperimentsController#show as HTML
Parameters: {"measurement_id"=>"2"}

ActiveRecord::RecordNotFound (Couldn't find Experiment without an ID)

这应该很容易解决。更重要的是:

2.:

GET "/measurements/2/tag_node"

Processing by PhysicalNodesController#show as HTML
Parameters: {"measurement_id"=>"2"}

如何让 rails 将其称为 tag_node_id 而不是 measurement_id

解决方案:

在与“dmoss18”长时间交谈后,很明显将tag_nodesanchor_nodes 作为physical_nodes 的子元素是没有意义的,因为它们只存在于测量表中。

所以现在我的routes.rb 看起来像这样:

resources :measurements, only: [:index, :show, :create]

resources :physical_nodes, only: [:index, :show]

resources :tag_nodes, only: [] do
  resources :measurements, only: [:index]
end

resources :anchor_nodes, only: [] do
  resources :measurements, only: [:index]
end

resources :experiments, only: [:index, :show] do
  resources :measurements, only: [:index]
end

我还删除了所有only childs,因为这不是数据库的设计方式。

【问题讨论】:

  • #2:您的父资源是 :measurements。 Rails 自动假定 id 参数称为 [parent]_id,或在本例中为 measure_id。我相信这也是#1 失败的原因。当路由器传入 params[:measurement_id] 时,您的控制器操作 (ExeriementsController#show) 可能正在寻找 params[:id]。你可以阅读更多guides.rubyonrails.org/routing.html#nested-resources
  • 问题 #1 有点不同。如果我调用GET /measurements/2/experiment,然后在转到ExperiementsController#show 时调用参数id(而不是measurement_id),我会得到id=2 的实验。但我想要的当然是:“给我一个measurement_id=2的实验”。好像我必须建立一个:if(params[:measurement_id]) then @experiement = Experiment.where("measurement_id = ?", params[:measurement_id])。还是有更简单的解决方案?
  • 正确。假设您没有使用experiment_id 来查找实验,而是使用measurement_id。我会发布答案
  • 抱歉。你说得对。我必须JOIN 测量才能找到正确的实验,因为experiment_id 存储在测量表中。这使事情变得更加困难,但仍然可以使用if 块来解决。但如果可能的话,我正在寻找一个更简单/优雅/干燥的解决方案;)

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-3.2 routes nested-routes


【解决方案1】:

1:当 rails 传入测量 id 时,您的 ExperimentsController#show 操作可能正在寻找 params[:id] 来查找实验。您需要执行以下操作:

@experiment = Experiment.find(params[:measurement_id])

但是,这不起作用,因为您的实验表没有 measure_id 列。我不建议将嵌套实验作为测量资源。这不是您的数据库的布局方式。如果你仍然想嵌套它,这里是你需要做的:

@experiment = Measurement.find(measurement.experiment_id).experiment

您的“has_many”和“belongs_to”不需要它们的“foreign_key”属性。 Rails 会自己解决这个问题。

2:由于此路由的父资源是 Measurement,rails 将假定 id 参数称为 :measurement_id。像这样更新你的关联:

class Measurement < ActiveRecord::Base
  self.table_name = 'measurement'
  self.primary_key = 'id'

  belongs_to :tag_node, :class_name => 'PhysicalNode', :foreign_key => :tag_node_id
  belongs_to :anchor_node, :class_name => 'PhysicalNode', :foreign_key => :anchor_node_id
  belongs_to :experiment
end

class PhysicalNode < ActiveRecord::Base
  self.table_name = 'physical_node'
  self.primary_key = 'id'

  has_many :tag_node, :class_name => 'Measurement', :foreign_key => :tag_node_id
  has_many :anchor_node, :class_name => 'Measurement', :foreign_key => :anchor_node_id
end

class Experiment < ActiveRecord::Base
  self.table_name = 'experiment'
  self.primary_key = 'id'

  has_many :measurements
end

我不会在测量资源下嵌套任何东西,因为它是子资源,而不是父资源。由于您的 /measurements/1/[anythingelse] 是 measurements 路线,因此 rails 假定 id 名为 :measurement_id。 您将事物嵌套在 id 为 1 的测量资源/对象下。 换句话说,您是说测量 x HAS tag_nodes 和 HAS anchor_nodes,这不是真的。

如果您仍想这样做,您可以在控制器中为每个资源创建单独的操作,如下所示:

resources :measurements, only: [:index, :show] do
  resource :tag_node, controller: :physical_nodes, only: [:show_tag]
  resource :anchor_node, controller: :physical_nodes, only: [:show_anchor]
  resource :experiment, only: [:show]
end

在您的物理节点控制器中创建一个 show_tag 和 show_anchor 操作。然后这些操作将查找 params[:measurement_id)

【讨论】:

  • 这是一个使用嵌套资源的示例项目。请注意,嵌套资源控制器 (cmets) 假定参数将始终称为 :article_id,因为评论是文章的资源。这种方法假设用户永远不会直接点击评论路线(例如/cmets/1),在这种情况下,参数将只是:id github.com/railscasts/139-nested-resources/blob/master/blog/app/…
  • #1 我认为可以做得更简单:@e = Measurement.where(params[:measurement_id]).experiment。它应该可以工作,因为它是使用模型关系连接的,对吧?
  • 是的,我只是想让方法非常清晰。不过你是对的
  • #2 的问题是:MeasurementPhysicalNode 有两个不同的连接,一个是tag_node_id,一个是anchor_node_id。我需要一种方法来区分它们......
  • 您的“belongs_to”和“has_many”需要更新。 belongs_to :tag_node, :class_name => 'PhysicalNode', :foreign_key => :tag_node_id belongs_to :anchor_node, :class_name => 'PhysicalNode', :foreign_key => :anchor_node_id,并将 has_many :measurements 更改为 :tag_node 和 :anchor_node。我不会在您的测量资源中嵌套“tag_node”和“anchor_node”,因为它们不是测量的子资源。它们是父资源。
猜你喜欢
  • 1970-01-01
  • 2011-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多