【问题标题】:Rails - How do Controllers pass instance variables to Views...can it be stopped?Rails - 控制器如何将实例变量传递给视图...可以停止吗?
【发布时间】:2013-09-13 05:09:40
【问题描述】:

我理解并欣赏通过将 @ 放在 Controller 中的变量名前面,它可以在加载的任何视图中使用。这非常有用,但我想了解它的魔力。它是如何发生的,可以阻止吗?

我正在尝试使用继承来干燥我的 CRUDdy 资源控制器,将大部分逻辑放在ApplicationController 中。超类应该引用抽象变量@resource(用于单个资源)、@resources(用于资源集合)和@parent_resource(用于嵌套@resource 时的父资源),但理想情况下是视图将获得更具体的名称,例如:@customer@customers@sales_territory。这可以在不将所有对象的副本(一次在抽象名称中,一次在具体名称中)发送到视图的情况下完成吗?

在我写这篇文章时,想到的可能性是:

  1. 受保护的实例变量...Ruby 有这样的东西吗? 如果是这样,控制器会魔法将它们交给视图吗?
  2. 在渲染/重定向之前将通用命名变量设置为 nil
  3. 使用子类中定义的受保护的空方法来代替 抽象命名实例变量

如何实现这一点的正确选择是什么?

【问题讨论】:

  • 你想通过隐藏/阻止这些变量在视图中使用来实现什么?实例变量持有的对象不会在视图中“复制” - 通过调用已经设置的控制器的实例变量,视图可以简单地访问它们。
  • 我实际上应该放一些代码来让事情更清楚,但我的目标是得到关于 Rails 中视图和控制器之间关系的内部运作的答案,而不是解决我的具体问题.在我的具体情况下,超类正在处理“@resource”,但“CustomersController”需要“@customer”才能进入视图。如果两者都存在,那么我的假设是它们都被发送,这将浪费资源。

标签: ruby-on-rails ruby


【解决方案1】:

我假设这里发生的情况是,您的应用中有一堆控制器实际上只是做同样的事情,因此您希望利用继承来干掉它。

话虽如此,我并不完全确定 ApplicationController 是否是转储所有这些功能的正确位置,因为将来如果您有新的控制器,它们也将继承所有这些功能而不必需要它。

我会这样做:

  • 假设您有这样的控制器:
    • lions_controller.rb
    • tigers_controller.rb
    • hippos_controller.rb

并且它们几乎具有相似的功能...我将创建一个“基本”控制器,然后在子控制器上设置继承。然后我还会做一个动作来设置子控制器的“逻辑”默认值,就像这样。

AnimalsController.rb

class AnimalsController < ApplicationController
  class_attribute :resource_class, :parent_resource_class

  protected
    def self.set_resource_attributes(options={})
       self.resource_class = options[:resource_class]
       self.parent_resource_class = options[:parent_resource_class]
    end
end

LionsController.rb

class LionsController < AnimalsController
  #call methods in AnimalsController here, start with setting the resource name
  set_resource_attributes :resource_class => Lion, :parent_resource_class => Animal
end

等等等等...可能有用的另一件事是使用“instance_variable_set”方法,以便您可以在视图中设置实际有意义的实例变量名称...您可以使用您刚刚设置的类变量来执行此操作...例如,让我们重新打开 AnimalsController.rb 类:

class AnimalsController < ApplicationController
  def show
    instance_variable_set("@#{self.resource_class.name.underscore}".to_sym, self.resource_class.find(params[:id]))
    #... all the regular show stuff
  end
end

这样,当您转到 lions#show 路径时,您将在视图中访问名为 @lion 的变量,该变量将被设置并包含通过 ActiveRecord 找到的 Lion 类的实例。

当然,我在这里输入的这个伪代码可以被清理并干燥一点,但希望你能得到我想要的地方。希望这会有所帮助。

【讨论】:

  • 当然,因为您也有“parent_resource_class”,您也可以使用 instance_variable_set 以相同的方式将它的实例设置为实例变量。有关 instance_variable_set 的更多信息,请在此处查看:apidock.com/ruby/v1_9_3_392/Object/instance_variable_set
  • 非常感谢。这个答案强调了我只是在帮助解决我的具体问题时并没有以 Ruby 的方式思考事情,并为我指明了正确的研究方向。至于 ApplicationController - 我在发布我的问题后立即开始将代码移出那里。现在我所有的控制器都是直接的 CRUDdy,但我知道这会改变。我想所有这一切都应该转移到混合中,这是我需要自学的其他东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多