复制控制器类实例变量 [英] Copy a controller class instance variables

查看:59
本文介绍了复制控制器类实例变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to write a simple erb template generator to parse stored erb templates from the views using Generator module. I call the Generator from the rails controller to generate it's singleton instances and pass it the WallController by self pointer.

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模板执行正确的解析.然后生成返回erb结果文本的方法.

The first thing Generator.generate_instances actually attempts to do is to copy the WallController instance variables (hence the self pointer) to perform correct parsing of the erb templates. Then it generates methods returning erb resulted text.

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 单例方法.

I am new to rails but I have found out that rails controller's included files are limited to a single static structure. I didn't manage either to overwrite class Object or class Class singleton methods which could be helpful.

但是,在运行上述示例后, WallController 的实例变量将返回 WallController 类地址,而不是由 WallController.index 定义的值.

However, after running the above example the instance variables of WallController return the WallController class address in stead of values defined by WallController.index.

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

是否存在在其他控制器之间分配Rails控制器实例变量的正确方法?如果没有,为什么常规实例副本不起作用?

Is there a correct way to distribute a rails controller instance variables among other controllers? If not, why are regular instance copy not working?

如果我不得不用红宝石来编写,那将很容易:

If I had to write it in ruby, that would be easy:

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代码.还解决了以合理的速度将视图代码划分为较小的可重用组件的问题.

This problem may be solved with viewcomponent, which allows for standard ruby code for the view controller. Also solves the problem of dividing the view code to smaller reusable components in reasonable speed.

要使用viewcomponent宝石,请先将其包含在您的Gemfile中.

To use the viewcomponent gem first include it to your Gemfile.

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

在使用 bundle install 更新了gem之后,如果服务器正在运行,则还需要重新启动服务器以应用新的gem.

After updating your gems with bundle install, you will also need to restart your server if it's running, to apply the new gem.

然后生成组件的用法与其他rails生成器相似.第一个参数是组件名称,第二个参数是组件参数.

Then generating the component is similar in usage to other rails generators. The first argument is a component name and the second is a component argument.

rails generate component Header site_id

现在,我专注于在 app/component 目录,视图和控制器代码中生成的文件.这将只是创建视图标题片段的控制器.

Now I focus on files generated in app/component directory, view and controller code. This will simply be the controller to create the header snippet of the view.

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

Inside of app/component/header_component.rb can be encapsulated all the code from WallController related to the header view.

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

类似地,将所有标题视图erb代码放入 app/component/header.html.erb .

Similarly, put all the header view erb code to the app/component/header.html.erb.

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

The finished component can be generated from the view using rails render:

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

这篇关于复制控制器类实例变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆