Ruby on rails 在*不同*控制器的方法之间传递参数
已经有关于如何在同一控制器的方法之间传递参数的线程 但是有没有一种方法可以在不同控制器的方法之间传递参数呢 因为有时候你会有一篇文章,当你对它调用#update操作时,你也希望同时通过TagsController的#update操作来更新与它相关的标签 该习惯用法类似于在ArticlesController#actions中实例化TagsController,然后在执行Ruby on rails 在*不同*控制器的方法之间传递参数,ruby-on-rails,controller,request,rack,Ruby On Rails,Controller,Request,Rack,已经有关于如何在同一控制器的方法之间传递参数的线程 但是有没有一种方法可以在不同控制器的方法之间传递参数呢 因为有时候你会有一篇文章,当你对它调用#update操作时,你也希望同时通过TagsController的#update操作来更新与它相关的标签 该习惯用法类似于在ArticlesController#actions中实例化TagsController,然后在执行tags\u controller\u instance.send(:update)时向其传递一个新的Rack::Respons
tags\u controller\u instance.send(:update)
时向其传递一个新的Rack::Response实例,其中只包含整个参数散列的:tags部分
您必须只发送ArticlesController收到的参数散列的特殊部分,因为TagsController将具有不同的StrongParameters
我认为这可以归结为一个问题,即如何创建一个Rack::Request,一方面复制ArticlesController的请求,另一方面如何传递给它,而不是整个参数散列,而只是其中有意义的部分
然后应该可以在ArticlesController#update中使用this.tags
请求更新的标记列表,对吗
谢谢
冯·斯波茨
该习惯用法类似于在ArticlesController#操作中实例化TagsController,然后在执行tags#controller#instance.send(:update)时向其传递一个新的Rack::Response实例,其中只包含整个参数散列的:tags部分
请不要那样做!这将很难理解和维护。可能还有其他副作用,你甚至没有想过
问题是,tagscoontroller#update
做了哪些您不想在ArticlesController
中复制的事情?如果是一些复杂的逻辑,我认为你应该把它抽象出来,比如用a来代替
大概是这样的:
类更新tags
def自运行(参数)
新建(参数)。运行
结束
def初始化(参数)
@params=params
结束
def运行
#从标记控制器复制逻辑
结束
结束
然后您可以在控制器中使用/重用此服务
类标记控制器
def更新
UpdateTags.run(参数)
结束
结束
类文章控制器
def更新
#更新文章或将其移动到专用服务中
UpdateTags.run(参数)
结束
结束
另一种方法是让
文章
接受标签
的属性
编辑
详细说明为什么实例化另一个控制器不是一个好主意
- 过滤器之前呢?(再次)执行它们可以吗
- 视图渲染呢?您显然不想渲染视图,因此这是额外的工作,可能会产生副作用
- 其他副作用,如缓存、日志记录、数据分析
- 实例化控制器不是一个公共API,因此这可能会在Rails版本之间发生变化,从而导致更新困难
- 这不是一个常见的模式,所以很难理解
tagscoontroller#update
做了哪些您不想在ArticlesController
中复制的事情?如果是一些复杂的逻辑,我认为你应该把它抽象出来,比如用a来代替
大概是这样的:
类更新tags
def自运行(参数)
新建(参数)。运行
结束
def初始化(参数)
@params=params
结束
def运行
#从标记控制器复制逻辑
结束
结束
然后您可以在控制器中使用/重用此服务
类标记控制器
def更新
UpdateTags.run(参数)
结束
结束
类文章控制器
def更新
#更新文章或将其移动到专用服务中
UpdateTags.run(参数)
结束
结束
另一种方法是让
文章
接受标签
的属性
编辑
详细说明为什么实例化另一个控制器不是一个好主意
- 过滤器之前呢?(再次)执行它们可以吗
- 视图渲染呢?您显然不想渲染视图,因此这是额外的工作,可能会产生副作用
- 其他副作用,如缓存、日志记录、数据分析
- 实例化控制器不是一个公共API,因此这可能会在Rails版本之间发生变化,从而导致更新困难
- 这不是一个常见的模式,所以很难理解
我想再次强调,这不是一个好主意。重复的代码比错误的抽象要好。对于一个微不足道的问题,这听起来像是一个疯狂的解决方案 Rails中控制器的唯一公共方法应该是控制器的动作,这些动作是响应HTTP请求的方法,并且只能通过HTTP调用来调用这些方法 任何其他方法。没有有效的情况下,您会调用另一个控制器上的
TagsController#update
来更新标记,因为该方法-更新标记以响应补丁/tags/:id
如果要在一次请求中更新文章及其标记,请使用接受\u嵌套的\u属性\u for:tags
:
class Article < ApplicationRecord
has_many :tags
accepts_nested_attibutes_for :tags
end
class标记控制器module Taggable
private
def tag_attributes
[:foo, :bar, :baz]
end
end
class TagsController < ApplicationController
include Taggable
# PATCH /tags/:id
def update
@tag = Tag.find(params[:id])
if @tag.update(tag_params)
redirect_to @tag, success: 'Tag updated'
else
render :edit
end
end
private
def tag_params
params.require(:tag).permit(*tag_attibutes)
end
end
class ArticlesController < ApplicationController
include Taggable
def update
if @article.update(article_params)
redirect_to @article, success: 'Article updated'
else
render :edit
end
end
private
def article_params
params.require(:article).permit(:title, :body, tags_attributes: tag_attibutes)
end
end
<%= form_with(model: @article) do |f| %>
...
<%= f.fields_for :tags do |tag| %>
<div class="field">
<%= tag.label :foo %>
<%= tag.text_field :foo %>
</div>
<% end %>
<% f.submit %>
<% end %>