Ruby on rails 在*不同*控制器的方法之间传递参数

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

已经有关于如何在同一控制器的方法之间传递参数的线程

但是有没有一种方法可以在不同控制器的方法之间传递参数呢

因为有时候你会有一篇文章,当你对它调用#update操作时,你也希望同时通过TagsController的#update操作来更新与它相关的标签

该习惯用法类似于在ArticlesController#actions中实例化TagsController,然后在执行
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版本之间发生变化,从而导致更新困难
  • 这不是一个常见的模式,所以很难理解
我想再次强调,这不是一个好主意。重复的代码比错误的抽象要好

该习惯用法类似于在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版本之间发生变化,从而导致更新困难
  • 这不是一个常见的模式,所以很难理解

我想再次强调,这不是一个好主意。重复的代码比错误的抽象要好。

对于一个微不足道的问题,这听起来像是一个疯狂的解决方案

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 %>