Michael Hartl Rails 教程 4,微博 偏变量和实例变量

Michael Hartl Rails Tutorial 4, micropost Partial and instance variables

在他的 tutorial 之后,Static-Pages Controller 的主页呈现 partial_form:

<%= render 'shared/micropost_form' %> 

StaticPagesController.rb

def home
  @micropost  = current_user.microposts.build #for the form_form 
  @feed_items = current_user.feed.paginate(page: params[:page])
end

然后,在 MicropostController.rb 中声明部分 micropost_form 的操作:

class MicropostsController < ApplicationController
  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      @feed_items = []
      render 'static_pages/home'
    end
  end
end

请注意,如果 micropost_form 成功,它如何重定向到 static_pages 的索引视图,但是,如果失败,它会呈现 static_pages 主视图(这也将参数保留在表单,因此用户不必输入所有数据),但是,它需要初始化 static_pages 的主控制器实例变量(即 feed_items)。

现在,假设 StaticPages Controller 的主页有一长串复杂的实例变量,MicropostController 如何在不创建那么多实例变量的情况下呈现(以在失败时保留表单数据)static_pages/home?

注:此题与my previous one相关,但我之前想了解这个基础示例

how can MicropostController render (to keep form data upon failure) static_pages/home without creating that many instance variables?

简单的回答是不能。在 Rails 中你不能在内部重定向——这是一个有意的设计。这意味着一旦路由器匹配请求,您就无法 "patch through" 向 StaticPagesController#home 发出请求。

所以为了 MicropostsController 渲染 static_pages/home 它需要做与 StaticPagesController 相同的工作。

但是,如果设置实例变量很困难,或者您想避免重复,那么一个好的技术是使用模块来提取共享功能。

# app/controllers/concerns/feedable.rb
module Feedable
  protected

    def set_feed_items!
      @feed_items = FeedItem.includes(:comments).all
    end
end

class StaticPagesController < ActiveRecord::Base
  include Feedable

  # ...
  before_action :set_feed_items!, only: [:home]
end

class MicropostsController < ApplicationController
  include Feedable

  # ...
  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      set_feed_items!
      render 'static_pages/home'
    end
  end
end

如果您的 from 引用了实例变量,那么无论是在 home 方法还是 create 方法中,您都需要在呈现表单时初始化实例变量。

这是 Sandi Metz 提出她的开发者规则第 4 条的原因之一

Controllers can instantiate only one object. Therefore, views can only know about one instance variable and views should only send messages to that object

查看此处了解所有规则...https://robots.thoughtbot.com/sandi-metz-rules-for-developers