复制一个控制器class个实例变量
Copy a controller class instance variables
我想编写一个简单的 erb 模板生成器来使用 Generator
模块从视图中解析存储的 erb 模板。我从 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
实例变量(因此是自指针)以执行 erb 模板的正确解析。然后它生成方法 returning erb 结果文本。
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 %>
我是 rails 的新手,但我发现 rails 控制器的包含文件仅限于单个静态结构。我没有设法覆盖 class Object
或 class Class
可能有用的单例方法。
但是,在运行之后上面的例子WallController
return的实例变量WallController
class地址代替了[=定义的值27=].
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 代码。还解决了以合理的速度将视图代码划分为更小的可重用组件的问题。
要使用视图组件 gem 首先将其包含到您的 Gemfile 中。
gem 'view_component', require: 'view_component/engine'
用 bundle install
更新您的 gem 后,如果它是 运行,您还需要重新启动服务器以应用新的 gem。
然后生成组件的用法与其他 rails 生成器类似。第一个参数是组件名称,第二个是组件参数。
rails generate component Header site_id
现在我专注于 app/component
目录中生成的文件、视图和控制器代码。这将只是创建视图的 header 片段的控制器。
app/component/header_component.rb
内部可以封装WallController
中与header视图相关的所有代码。
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
同理,将所有header查看erb代码放到app/component/header.html.erb
.
可以使用 rails 渲染从视图生成完成的组件:
<%= render HeaderComponent.new(site_id: 1) %>
我想编写一个简单的 erb 模板生成器来使用 Generator
模块从视图中解析存储的 erb 模板。我从 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
实例变量(因此是自指针)以执行 erb 模板的正确解析。然后它生成方法 returning erb 结果文本。
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 %>
我是 rails 的新手,但我发现 rails 控制器的包含文件仅限于单个静态结构。我没有设法覆盖 class Object
或 class Class
可能有用的单例方法。
但是,在运行之后上面的例子WallController
return的实例变量WallController
class地址代替了[=定义的值27=].
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 代码。还解决了以合理的速度将视图代码划分为更小的可重用组件的问题。
要使用视图组件 gem 首先将其包含到您的 Gemfile 中。
gem 'view_component', require: 'view_component/engine'
用 bundle install
更新您的 gem 后,如果它是 运行,您还需要重新启动服务器以应用新的 gem。
然后生成组件的用法与其他 rails 生成器类似。第一个参数是组件名称,第二个是组件参数。
rails generate component Header site_id
现在我专注于 app/component
目录中生成的文件、视图和控制器代码。这将只是创建视图的 header 片段的控制器。
app/component/header_component.rb
内部可以封装WallController
中与header视图相关的所有代码。
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
同理,将所有header查看erb代码放到app/component/header.html.erb
.
可以使用 rails 渲染从视图生成完成的组件:
<%= render HeaderComponent.new(site_id: 1) %>