我正在写一个应用程序的一部分,这是“要做的工作”,而工作对他们有记录或评论。
我永远不确定使用嵌套资源视图的正确方法是什么 - 我不认为nested_attributes_for在这里有效 - 我可能错了。
我想要做的是拥有作业渲染的主要#show动作,并在脚下渲染has_many模型的#index(显示当前注释),然后渲染has_many模型的#new,当我提交它通过AJAX发送,并将新评论添加到备注/评论面板的底部。
我不认为nested_attributes_for就在这里,因为我实际上并没有在父控制器上提交任何内容。
class JobsController < ApplicationController
end
class JobNotesController < ApplicationController
end
class Job < ActiveRecord::Base
has_many :job_notes
end
class JobNote < ActiveRecord::Base
belongs_to :job
end
在我看来,从JobsController #show中呈现JobNotesController的#new动作更有意义,这样我就可以有效地将某人发送到原始URL:/ jobs / 7 / jobs_notes / 34
在我看来,这种方式会更加干燥。
我可能过于复杂了。
看起来我的问题有点模糊 - 问题是什么被认为是最好的方法....
我已经写了许多不同的标题/详细信息类型的变体,我不确定的是这样做的最佳实践并且效率很高。
这种情况下的标题是要完成的工作。它有自己的#edit方法和视图,使屏幕更易于使用。
当您查看工作时,在其详细信息下面,我想包括有关工作的讨论 - 如果您愿意,请注意。
我总是希望显示一个用于添加新笔记的表单,但我还想显示附加到此作业的所有其他笔记。
我可以创建所有相关的逻辑/处理程序,以便仅返回最后N个音符并进一步读取,以便下一个音符在正确的时间顺序位置而不是反转所有音符。这很容易。
它涉及在父控制器/视图的上下文中执行属于另一个控制器的表单。
我正沿着这个助手的路线前进。
def new_job_note
nc = JobNotesController.new
nc.params = { :job_id = @job.id }
nc.dispatch(:new, request)
return c.response.body
end
然后在我看来我可以打电话
<%= new_job_note %>
这实际上有效 - 只要我为没有周围标签的JobNotesController设置布局。
这感觉不是正确的做法。
答案 0 :(得分:0)
使用partials可能更好。您可以对job_notes
使用partial,将其拥有的作业作为本地(或使用实例变量)传递给它。另一个部分用于创建新笔记,再次传递拥有的工作来渲染它。
您仍然可以使用AJAX更新记事列表。
答案 1 :(得分:0)
我不确定你想做什么,但从技术上讲,你的应用程序总是只呈现一个动作(而不是索引+显示等...)。如果您想渲染块而不重复自己,请在视图中使用render partial: 'xxx'
。
示例:
您创建了一个名为_job_list.html.erb
<% jobs.each do |j| %> ... <% end %>
您可以从作业#index和其他类似的操作中调用此块:
<%=render partial: 'job_list', locals: { jobs: @jobs } %>
Secundo,嵌套的资源可以在这样的路线中设置:
#in routes.rb
resources :jobs do
resources :job_notes
end
job_notes INSIDE作业的节目将指向JobNoteController,但您将有两个参数而不是一个:job_id
和job_note_id
。
然后,您可以在job_id
中使用job_note_id
和JobNoteController
两个参数:
class JobNoteController < ApplicationController
def show
@job = Job.find params[:job_id]
@job.job_notes.find params[:job_note_id]
end
end
如果您希望您的控制器更通用(例如,您希望还有一个指向/ job_notes /:id的路径,而不是确定特定作业的范围),您可以改进这段代码:
class JobNoteController < ApplicationController
def show
@scope = params[:job_id] ? Job.find(params[:job_id]).job_notes : JobNote
@scope.find params[:job_note_id]
end
end
这种情况下,您将根据上下文(您想要的DRY:P)确定查询范围 我不确定我是否已经回答了你想要的东西,随便解释你想做什么。
此致
亚辛。
答案 2 :(得分:0)
在REST中描述嵌套资源非常简单:
users/1/pets
直接告诉我们关于资源的信息。但是,在嵌套时(或之前)应该记住一些事情。
所以在你的情况下你会想要使用:
resources :jobs, shallow: true do
resources :jobs_notes
end
哪会给你
GET|POST /jobs/:job_id/jobs_notes
GET|PATCH|DELETE /jobs_notes/:id # no context required!
浅嵌套是如此甜蜜的原因是,它允许您执行redirect_to(@child)
而不是redirect_to([@parent, @child])
,并且当您拥有可以具有多个父类型的资源时,它会使其更清晰。
/new
路由是简单资源的rails约定。在其他情况下,从父项show
甚至index
操作创建资源可能更有意义。如果你没有采取新的行动,Rails警察就不会来。
nested_attributes_for
。
但是,如果要使用单个请求创建/编辑多个子记录,它也很有用。假设您有类todo列表应用程序:
class List < ActiveRecord::Base
has_many :items
accepts_nested_attributes_for :list, allow_destroy: true
end
class Item < ActiveRecord::Base
belongs_to :list
end
然后,您可以使用以下内容创建多个Item
记录
POST /lists, { list: { items_attributes: [{ desc: 'Feed cat' }] } }
或者使用以下命令同时创建更新和删除:
PATCH /lists/1, { list: {
items_attributes: [
{ desc: 'Feed cat' },
{id: '2', desc: 'new desc'},
{id: '3', _destroy: '1'}
]
}}
当然,如果你创建一个像SPA这样的AJAX繁重的应用程序,最好将它作为单独的原子操作来执行,因为嵌套的params往往会使事情变得复杂和脆弱,因为有很多事情一次发生。
这里你真正想要的是不重复使用控制器动作,而是重复使用视图的一部分,例如表单。那是partials进来的地方。
# things/_form.html.erb
<%= form_for(thing) %>
# ...
<% end %>
# parents/show.html.erb
render_partial 'things/form', thing: @parent.thing.new
要在控制器之间共享诸如回调或操作之类的代码,您可以使用mixins作为模块或垂直继承的形式。请注意,这并不意味着您可以/应该在单个请求周期中使用多个控制器操作!相反,你可以这样做,以避免重复相同的方法。
class TaggableController < ApplicationController
before_action :set_resource
def create
@tag = @resource.tag.create
# ...
end
end
class Posts::TagsController < TaggableController
private
def set_resource
@resource = Post.find(params[:tag_id])
end
end
class Images::TagsController < TaggableController
private
def set_resource
@resource = Image.find(params[:image_id])
end
end
# or use an ActiveSupport::Concern.
module Taggable
def self.included(base)
base.class_eval do
before_action :set_resource
end
end
def create
@tag = @resource.tag.create
# ...
end
end
class Posts::TagsController < ApplicationController
include Taggable
private
def set_resource
@resource = Post.find(params[:tag_id])
end
end
class Images::TagsController < ApplicationController
include Taggable
private
def set_resource
@resource = Image.find(params[:image_id])
end
end
你甚至可以将两者结合起来。