泛型示例问题

时间:2011-02-12 17:27:05

标签: ruby-on-rails ruby ruby-on-rails-3

我是Ruby on Rails的新手,作为C#开发人员,当我想重用代码(对于一个存储库类)时,我可以把它放到类型为<T>的基类中,以便能够做这样的事情:

public virtual IEnumerable<T> GetAll()
{
    return Context<T>.GetAll();
}

如果我需要做任何自定义逻辑,我当然可以覆盖我的“用户”存储库中的方法。

在Ruby中,我很熟悉你可以这样做:

class UsersController < ApplicationController

这将允许访问ApplicationController中的所有方法及其父类。使用scaffolding时,它会在每个子类中生成以下方法:

def index
  @users = User.all

  respond_to do |format|
    format.html # index.html.erb
    format.xml  { render :xml => @users }
  end
end

我最终得到的是10个具有相同方法的类,但唯一的区别是'User.all','Post.all'等。

我如何将此方法设为通用,以便将其放入ApplicationController类中?

感谢您为Ruby on Rails新手提供的任何帮助。

5 个答案:

答案 0 :(得分:4)

首先要了解的脚手架代码是它可以被删除,因此:

def index
  @users = User.all
end

除非您打算以其他格式(如json,html,pdf)提供视图,否则不需要respond_to块。如果您仍然觉得需要干掉这种方法,那么您可以执行类似

的操作
# app/controllers/concerns/autoload_records.rb

module AutoloadRecords
  included do
    before_action :load_records, only: :index
    before_action :load_record, only: [:create, :show, :edit, :update, :destroy]
  end

  private
  def load_records
    @records = model_class.all
  end

  def load_record
    @record = model_class.find(params[:id])
  end

  def model_class
    klass = self.class.to_s[/\A(\w+)sController\Z/,1] #=> get the name of the class from the controller Constant
    Object.const_get(klass)
  end
end

并像

一样编写控制器
class UsersController < ApplicationController
  include AutoloadRecords

  def index
    @records # => #<ActiveRecord::Relation[...]>
  end

  def show
    @record # => #<User ...>
  end

  def non_rest_action
    @record # => nil
    @records # => nil
  end
end

答案 1 :(得分:3)

而不是做eval,而你真的不想做一个。查看Jose Valim的Inherited Resources宝石。它为所有控制器提供标准的CRUD方法,并且非常复杂。它也经过全面测试,因此您无需担心确保您的通用代码在所有情况下都按预期运行。

有关如何使用它的详细信息,请参阅链接的GitHub页面。

答案 2 :(得分:3)

也许一个简单的解决方案就是依赖mixins。

您定义了一个模块,

module MyModule 
   def my_index(klass)
     @elements = klass.all

     respond_to do |format|
       format.html # index.html.erb
       format.xml  { render :xml => @elements }
     end
   end
end 

然后,你有你的控制器,

include MyModule
def index
   my_index(User)
end 

当然,您需要在视图中使用@elements。如果您想在每个视图中使用不同的变量名称

   def my_index(klass, var_name)
     self.instance_variable_set(var_name, klass.all)
     ...
   end

答案 3 :(得分:1)

有几个rails插件可以帮助减少这种重复。轨道广播第230集介绍了这个。

https://github.com/josevalim/inherited_resources

答案 4 :(得分:0)

  1. 根据我的经验,您很少会看到像@user = User.all这样的10个索引操作。如果您事先知道不同模型之间的某些操作将是相同的 - 那么提取通用逻辑可能是有意义的。但那么这些模型可能会以某种方式连接起来吗?我不会提前说Post和User会有相同的索引操作。
  2. 对于像这样的简短方法,我不会试图重复,因为你最终可能会失去可读性。