复制控制器类实例变量



我想写一个简单的动词模板生成器来解析使用Generator模块的视图中存储的动词模板。我从rails控制器调用Generator来生成它的单例实例,并通过self指针将WallController传递给它。

require 'generator'
class WallController < ApplicationController
def index
header = File.read 'app/views/application-header.html'.freeze
@instances = {header: header}
# Load view generators
Generator.generate_instances self
end 
end

Generator.generate_instances实际上尝试做的第一件事是复制WallController实例变量(因此是self指针)来执行正确的动词模板解析。然后生成返回动词结果文本的方法。

require 'erb'
module Generator
def self.generate_instances environment
# Mimic class environment
if environment.superclass == ApplicationController
environment.instance_variables.each do |v| 
puts "Copy instance variable '#{v}' from #{environment.name} to #{self.name}"
value = environment.instance_variable_get(v)
self.send :instance_variable_set, v, value
end 
end 
# Parse the ERB templates
templates = @instances
return 0 if !templates.is_a?(Hash) or templates.empty? 
templates.keys.each.with_index do |key, index|
define_singleton_method key do
ERB.new(templates.values[index]).result
end
end 
end 
end

Generator接口的用法如下:

<%=== Generator.header %>

我是新的轨道,但我发现,轨道控制器的包含的文件仅限于一个单一的静态结构。我没有设法覆盖class Objectclass Class单例方法,这可能是有帮助的。

但是,在运行上面的例子之后,WallController的实例变量返回的是WallController类的地址,而不是WallController.index定义的值。

undefined method `empty?' for #<WallController:0x000000000a1f90>

是否有一个正确的方法来分发一个rails控制器实例变量之间的其他控制器?如果不是,为什么常规实例复制不工作?

如果我必须用ruby写的话,那就很容易了:

module Y
def self.generate_environment environment
environment.instance_variables.each do |v| 
puts "Copy #{v} from #{environment.name} to #{self.name}"
value = environment.instance_variable_get v
self.instance_variable_set(v, value)
end if environment.class == Class

puts "Retrived string: #{@hello}"
end 
end
class X
def self.index
@hello = 'Hello, World!'
Y.generate_environment self
end 
end
X.index

这个问题可以通过viewcomponent来解决,它允许为视图控制器提供标准的ruby代码。还解决了以合理的速度将视图代码划分为更小的可重用组件的问题。

要使用viewcomponent gem,首先把它包含到你的Gemfile中。

gem 'view_component', require: 'view_component/engine'

bundle install更新你的gem后,你还需要重启你的服务器,如果它正在运行,以应用新的gem。

生成组件的用法与其他rails生成器类似。第一个参数是组件名称,第二个参数是组件参数。

rails generate component Header site_id

现在我主要讨论app/component目录下生成的文件、视图和控制器代码。这将是一个简单的控制器,用于创建视图的标题片段。

app/component/header_component.rb的内部可以封装WallController中与头视图相关的所有代码。

class HeaderComponent < ViewComponent::Base
def initialize(site_id:)
puts "Rendering header component for site: #{site_id}"
# Load site elements
@site = Site.find site_id
@menu_items = []
Site.all.each.with_index do |site, index|
@menu_items.push site.title => site.link
end 
end
end

同样,将所有标题视图动词代码放到app/component/header.html.erb.

完成的组件可以使用rails render从视图生成:

<%= render HeaderComponent.new(site_id: 1) %>

最新更新